populate-me 0.14.0 → 0.17.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.
- checksums.yaml +4 -4
- data/lib/populate_me/admin/__assets__/css/main.css +8 -0
- data/lib/populate_me/admin/__assets__/img/favicon.png +0 -0
- data/lib/populate_me/admin/__assets__/js/main.js +158 -48
- data/lib/populate_me/admin/views/page.erb +11 -3
- data/lib/populate_me/admin.rb +8 -2
- data/lib/populate_me/document.rb +1 -1
- data/lib/populate_me/document_mixins/admin_adapter.rb +4 -0
- data/lib/populate_me/document_mixins/outcasting.rb +9 -0
- data/lib/populate_me/document_mixins/schema.rb +9 -2
- data/lib/populate_me/version.rb +1 -1
- data/populate-me.gemspec +1 -1
- data/test/test_admin.rb +43 -2
- data/test/test_document_admin_adapter.rb +24 -1
- data/test/test_document_outcasting.rb +72 -0
- data/test/test_document_schema.rb +20 -0
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab01b0340f42771cfda2e496e4dee387c3e098ee2757ee374f5fb9a95fda48b0
|
4
|
+
data.tar.gz: b74800276c349db0d4dcc74f46f36d5b6fb6a46cb4d727c5dbfb9e46d35d0aa4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7621910d4fec3622e2bad85742c0877fbe6bafdf9dcb28f804e40d5ae255b362de66cdf6d978a1d49fa27874527705d2cec80146e2624f71ac4783a4bd8b5554
|
7
|
+
data.tar.gz: c65c5db1c8361cb50ada68e63cc246325590a0e8ca00a2f6a3e90e047f73cbc4a0072293ab52a60317a9b0710e96d7439ac3efd1860d3d134edd848ae144670f
|
Binary file
|
@@ -117,13 +117,17 @@ PopulateMe.scroll_to = function(el, column) {
|
|
117
117
|
// Mark errors for report after form validation.
|
118
118
|
// It adds the .invalid class to invalid fields,
|
119
119
|
// and adds the report after the label of the field.
|
120
|
-
PopulateMe.mark_errors = function(context,report) {
|
120
|
+
PopulateMe.mark_errors = function(context, report, isSubcontext) {
|
121
|
+
if (!isSubcontext) {
|
122
|
+
$('.invalid', context).removeClass('invalid');
|
123
|
+
$('.errors', context).remove();
|
124
|
+
}
|
121
125
|
$.each(report,function(k,v) {
|
122
126
|
var field = context.find('> [data-field-name='+k+']:first');
|
123
127
|
if (field.is('fieldset')) {
|
124
128
|
$.each(v, function(index,subreport) {
|
125
129
|
var subcontext = field.find('> .nested-documents > li:nth('+index+')');
|
126
|
-
PopulateMe.mark_errors(subcontext, subreport);
|
130
|
+
PopulateMe.mark_errors(subcontext, subreport, true);
|
127
131
|
});
|
128
132
|
} else {
|
129
133
|
field.addClass('invalid');
|
@@ -133,6 +137,54 @@ PopulateMe.mark_errors = function(context,report) {
|
|
133
137
|
});
|
134
138
|
};
|
135
139
|
|
140
|
+
// Navigate columns back
|
141
|
+
PopulateMe.navigate_back = function(target_id) {
|
142
|
+
// !!! Careful, it only works if we call this from the last column
|
143
|
+
var reloader = PopulateMe.finder.find('> li:nth-last-child(3) .selected');
|
144
|
+
if (reloader.size() > 0) {
|
145
|
+
var reloadee = PopulateMe.finder.find('> li:nth-last-child(2)');
|
146
|
+
var current_search = PopulateMe.copy_column_search(reloadee);
|
147
|
+
reloader.trigger('click.columnav',[function(cb_object) {
|
148
|
+
PopulateMe.restore_column_search(cb_object.column, current_search);
|
149
|
+
if (target_id) {
|
150
|
+
var target = $('[data-id=' + target_id + ']', cb_object.column);
|
151
|
+
if (target.size() > 0) {
|
152
|
+
PopulateMe.scroll_to(target, cb_object.column);
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}]);
|
156
|
+
} else {
|
157
|
+
PopulateMe.finder.trigger('pop.columnav');
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
PopulateMe.fieldMaxSize = function(field) {
|
162
|
+
var maxSizeData = field.data('max-size');
|
163
|
+
if (!maxSizeData) {
|
164
|
+
return null;
|
165
|
+
}
|
166
|
+
return field.data('max-size');
|
167
|
+
};
|
168
|
+
|
169
|
+
PopulateMe.fieldHasFileTooBig = function(field, maybeFile) {
|
170
|
+
var file = maybeFile || field[0].files[0];
|
171
|
+
if (!file) {
|
172
|
+
return false;
|
173
|
+
}
|
174
|
+
var maxSize = PopulateMe.fieldMaxSize(field);
|
175
|
+
if (!maxSize) {
|
176
|
+
return false;
|
177
|
+
}
|
178
|
+
return file.size > maxSize;
|
179
|
+
};
|
180
|
+
|
181
|
+
PopulateMe.fileTooBigErrorMessage = function(fname, max_size) {
|
182
|
+
if (typeof max_size != 'number') {
|
183
|
+
max_size = PopulateMe.fieldMaxSize(max_size);
|
184
|
+
}
|
185
|
+
return 'File too big: ' + fname + ' should be less than ' + PopulateMe.display_file_size(max_size) + '.';
|
186
|
+
};
|
187
|
+
|
136
188
|
// JS Validations
|
137
189
|
// This adds validations that could happen before sending
|
138
190
|
// anything to the server and that cannot be done with
|
@@ -146,18 +198,13 @@ PopulateMe.jsValidationsPassed = function(context) {
|
|
146
198
|
var max_size_fields = $('input[type=file][data-max-size]', context);
|
147
199
|
max_size_fields.each(function() {
|
148
200
|
var field = $(this);
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
var fname = field[0].files[0].name;
|
153
|
-
if (fsize>max_size) {
|
154
|
-
alert('File too big: '+fname+' should be less than '+PopulateMe.display_file_size(max_size)+'.');
|
155
|
-
throw "Validation error";
|
156
|
-
}
|
201
|
+
if (PopulateMe.fieldHasFileTooBig(field)) {
|
202
|
+
alert(PopulateMe.fileTooBigErrorMessage(file.name, field));
|
203
|
+
throw "Validation error";
|
157
204
|
}
|
158
205
|
});
|
159
206
|
} catch(e) {
|
160
|
-
if (e==='Validation error') {
|
207
|
+
if (e==='Validation error') {
|
161
208
|
return false;
|
162
209
|
} else {
|
163
210
|
throw(e);
|
@@ -167,7 +214,7 @@ PopulateMe.jsValidationsPassed = function(context) {
|
|
167
214
|
return true;
|
168
215
|
};
|
169
216
|
|
170
|
-
// Init column
|
217
|
+
// Init column
|
171
218
|
// Bind events and init things that need to happen when
|
172
219
|
// a new column is added to the finder.
|
173
220
|
// The callback `custom_init_column` is also called at the end
|
@@ -303,48 +350,111 @@ $(function() {
|
|
303
350
|
});
|
304
351
|
|
305
352
|
// Ajax form
|
353
|
+
|
354
|
+
var ajaxSubmitSuccess = function(res) {
|
355
|
+
if (res.success == true) {
|
356
|
+
PopulateMe.navigate_back(res.data._id);
|
357
|
+
}
|
358
|
+
};
|
359
|
+
|
360
|
+
var ajaxSubmitError = function(xhr, ctx) {
|
361
|
+
res = xhr.responseJSON;
|
362
|
+
if (res.success == false) {
|
363
|
+
PopulateMe.mark_errors(ctx, res.data);
|
364
|
+
PopulateMe.scroll_to(ctx.find('.invalid:first'));
|
365
|
+
$('input[type=submit]', ctx).show();
|
366
|
+
ctx.fadeTo("fast", 1);
|
367
|
+
}
|
368
|
+
};
|
369
|
+
|
306
370
|
$('body').on('submit','form.admin-post, form.admin-put', function(e) {
|
307
371
|
e.preventDefault();
|
308
372
|
var self = $(this);
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
}
|
333
|
-
|
334
|
-
}
|
373
|
+
self.fadeTo("fast", 0.3);
|
374
|
+
var submit_button = $('input[type=submit]', self);
|
375
|
+
var formData = new FormData(this);
|
376
|
+
var batchField = self.data('batch-field');
|
377
|
+
var batchFieldEl = $("input[name='" + batchField + "']");
|
378
|
+
var isBatchUpload = self.is('.admin-post') &&
|
379
|
+
batchField &&
|
380
|
+
formData.getAll(batchField).length > 1;
|
381
|
+
|
382
|
+
if (isBatchUpload) {
|
383
|
+
|
384
|
+
if (confirm("You've selected multiple images. This will create an entry for each image. It may take a while to upload everything. Do you wish to proceed ?")) {
|
385
|
+
submit_button.hide();
|
386
|
+
var files = formData.getAll(batchField);
|
387
|
+
var report = $("<div class='batch-upload-report'></div>").insertAfter(self);
|
388
|
+
var latestSuccessfulId;
|
389
|
+
var errorSize = 0;
|
390
|
+
var successSize = 0;
|
391
|
+
var addCloseButtonIfDone = function() {
|
392
|
+
if (errorSize + successSize >= files.length) {
|
393
|
+
var closeButton = $("<button type='button'>Close</button>").click(function(e) {
|
394
|
+
e.preventDefault();
|
395
|
+
PopulateMe.navigate_back();
|
396
|
+
});
|
397
|
+
report.append(closeButton);
|
335
398
|
}
|
336
|
-
}
|
337
|
-
|
338
|
-
|
339
|
-
if (
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
399
|
+
};
|
400
|
+
for (var i = 0; i < files.length; i++) {
|
401
|
+
var file = files[i];
|
402
|
+
if (PopulateMe.fieldHasFileTooBig(batchFieldEl, file)) {
|
403
|
+
errorSize += 1;
|
404
|
+
var msg = PopulateMe.fileTooBigErrorMessage(file.name, batchFieldEl);
|
405
|
+
report.append("<div class='error'>" + msg + "</div>");
|
406
|
+
addCloseButtonIfDone();
|
407
|
+
} else {
|
408
|
+
formData.set(batchField, file, file.name);
|
409
|
+
$.ajax({
|
410
|
+
url: self.attr('action'),
|
411
|
+
type: (self.is('.admin-put') ? 'put' : 'post'), // Always post ?
|
412
|
+
data: formData,
|
413
|
+
successData: {filename: file.name, index: i+1},
|
414
|
+
processData: false,
|
415
|
+
contentType: false,
|
416
|
+
success: function(res, textStatus, xhr) {
|
417
|
+
successSize += 1;
|
418
|
+
if (res.success == true) {
|
419
|
+
latestSuccessfulId = res.data._id;
|
420
|
+
report.append("<div>Uploaded: " + this.successData.filename + "</div>");
|
421
|
+
}
|
422
|
+
if (successSize >= files.length) {
|
423
|
+
PopulateMe.navigate_back(res.data._id);
|
424
|
+
} else {
|
425
|
+
addCloseButtonIfDone();
|
426
|
+
}
|
427
|
+
},
|
428
|
+
error: function(xhr, textStatus, errorThrown) {
|
429
|
+
errorSize += 1;
|
430
|
+
report.append("<div class='error'>Error: " + this.successData.filename + "</div>");
|
431
|
+
res = xhr.responseJSON;
|
432
|
+
if (res.success == false) {
|
433
|
+
PopulateMe.mark_errors(self, res.data);
|
434
|
+
}
|
435
|
+
addCloseButtonIfDone();
|
436
|
+
}
|
437
|
+
});
|
345
438
|
}
|
346
439
|
}
|
347
|
-
}
|
440
|
+
}
|
441
|
+
|
442
|
+
} else {
|
443
|
+
|
444
|
+
if (PopulateMe.jsValidationsPassed(self)) {
|
445
|
+
submit_button.hide();
|
446
|
+
$.ajax({
|
447
|
+
url: self.attr('action'),
|
448
|
+
type: (self.is('.admin-put') ? 'put' : 'post'),
|
449
|
+
data: formData,
|
450
|
+
processData: false,
|
451
|
+
contentType: false,
|
452
|
+
success: ajaxSubmitSuccess,
|
453
|
+
error: function(xhr, textStatus, errorThrown) {
|
454
|
+
ajaxSubmitError(xhr, self);
|
455
|
+
}
|
456
|
+
});
|
457
|
+
}
|
348
458
|
|
349
459
|
}
|
350
460
|
});
|
@@ -4,6 +4,7 @@
|
|
4
4
|
<head>
|
5
5
|
<meta charset="utf-8" />
|
6
6
|
<title><%= settings.meta_title %></title>
|
7
|
+
<link href="<%= request.script_name %>/__assets__/img/favicon.png" rel="icon" type="image/png">
|
7
8
|
<link rel="stylesheet" href="<%= request.script_name %>/__assets__/css/jquery-ui.min.css" type="text/css" media='screen' />
|
8
9
|
<link rel="stylesheet" href="<%= request.script_name %>/__assets__/css/asmselect.css" type="text/css" media='screen' />
|
9
10
|
<link rel="stylesheet" href="<%= request.script_name %>/__assets__/css/main.css" type="text/css" media='screen' />
|
@@ -79,7 +80,7 @@
|
|
79
80
|
{{#polymorphic_type}}
|
80
81
|
<p>({{polymorphic_type}})</p>
|
81
82
|
{{/polymorphic_type}}
|
82
|
-
<form action="<%= request.script_name %>/api/{{admin_url}}" method="POST" accept-charset="utf-8" class='admin-{{#is_new}}post{{/is_new}}{{^is_new}}put{{/is_new}}'>
|
83
|
+
<form action="<%= request.script_name %>/api/{{admin_url}}" method="POST" accept-charset="utf-8" class='admin-{{#is_new}}post{{/is_new}}{{^is_new}}put{{/is_new}}' {{#batch_field}}{{#is_new}}data-batch-field="{{batch_field}}"{{/is_new}}{{/batch_field}}>
|
83
84
|
{{#custom_partial_or_default}}template_form_fields{{/custom_partial_or_default}}
|
84
85
|
{{^is_new}}
|
85
86
|
<input type="hidden" name="_method" value="PUT" />
|
@@ -117,7 +118,14 @@
|
|
117
118
|
</script>
|
118
119
|
|
119
120
|
<script id="template-string-field" type="x-tmpl-mustache">
|
120
|
-
<input name='{{input_name}}' value='{{input_value}}' {{#required}}required{{/required}}{{{build_input_attributes}}} />
|
121
|
+
<input name='{{input_name}}' value='{{input_value}}' {{#required}}required{{/required}}{{{build_input_attributes}}} {{#autocomplete.length}}list='datalist-{{id}}'{{/autocomplete.length}} />
|
122
|
+
{{#autocomplete.length}}
|
123
|
+
<datalist id='datalist-{{id}}'>
|
124
|
+
{{#autocomplete}}
|
125
|
+
<option value='{{.}}' />
|
126
|
+
{{/autocomplete}}
|
127
|
+
</datalist>
|
128
|
+
{{/autocomplete.length}}
|
121
129
|
</script>
|
122
130
|
|
123
131
|
<script id="template-text-field" type="x-tmpl-mustache">
|
@@ -149,7 +157,7 @@
|
|
149
157
|
<button class='attachment-deleter'>x</button>
|
150
158
|
<br />
|
151
159
|
{{/url}}
|
152
|
-
<input type='file' name='{{input_name}}' {{#max_size}}data-max-size='{{max_size}}'{{/max_size}} {{{build_input_atrributes}}} />
|
160
|
+
<input type='file' name='{{input_name}}' {{#multiple}}multiple{{/multiple}} {{#max_size}}data-max-size='{{max_size}}'{{/max_size}} {{{build_input_atrributes}}} />
|
153
161
|
</script>
|
154
162
|
|
155
163
|
<script id="template-list-field" type="x-tmpl-mustache">
|
data/lib/populate_me/admin.rb
CHANGED
@@ -123,11 +123,17 @@ class PopulateMe::Admin < Sinatra::Base
|
|
123
123
|
# Method = overridable = testable
|
124
124
|
ENV['CERBERUS_PASS']
|
125
125
|
end
|
126
|
+
|
126
127
|
def cerberus_available?
|
127
128
|
# Method = overridable = testable
|
128
129
|
Rack.const_defined?(:Cerberus)
|
129
130
|
end
|
130
131
|
|
132
|
+
def cerberus_auth user, pass, req
|
133
|
+
pass == cerberus_pass
|
134
|
+
end
|
135
|
+
|
136
|
+
|
131
137
|
private
|
132
138
|
|
133
139
|
def setup_default_middleware builder
|
@@ -151,8 +157,8 @@ class PopulateMe::Admin < Sinatra::Base
|
|
151
157
|
return unless settings.cerberus_active
|
152
158
|
cerberus_settings = settings.cerberus==true ? {} : settings.cerberus
|
153
159
|
cerberus_settings[:session_key] = 'populate_me_user'
|
154
|
-
builder.use Rack::Cerberus, cerberus_settings do |user,pass,req|
|
155
|
-
pass
|
160
|
+
builder.use Rack::Cerberus, cerberus_settings do |user, pass, req|
|
161
|
+
cerberus_auth user, pass, req
|
156
162
|
end
|
157
163
|
end
|
158
164
|
|
data/lib/populate_me/document.rb
CHANGED
@@ -27,7 +27,7 @@ module PopulateMe
|
|
27
27
|
# It can be used on its own but it keeps everything
|
28
28
|
# in memory. Which means it is only for tests and conceptual
|
29
29
|
# understanding.
|
30
|
-
|
30
|
+
|
31
31
|
include DocumentMixins::Typecasting
|
32
32
|
include DocumentMixins::Outcasting
|
33
33
|
include DocumentMixins::Schema
|
@@ -48,12 +48,16 @@ module PopulateMe
|
|
48
48
|
end
|
49
49
|
page_title = self.new? ? "New #{self.class.to_s_short}" : self.to_s
|
50
50
|
# page_title << " (#{self.polymorphic_type})" if self.class.polymorphic?
|
51
|
+
batch_field_item = items.find do |item|
|
52
|
+
item[:field_name] == self.class.batch_field
|
53
|
+
end
|
51
54
|
{
|
52
55
|
template: "template#{'_nested' if o[:nested]}_form",
|
53
56
|
page_title: page_title,
|
54
57
|
admin_url: self.to_admin_url,
|
55
58
|
is_new: self.new?,
|
56
59
|
polymorphic_type: self.class.polymorphic? ? self.polymorphic_type : nil,
|
60
|
+
batch_field: (not self.new? or batch_field_item.nil?) ? nil : batch_field_item[:input_name],
|
57
61
|
fields: items
|
58
62
|
}
|
59
63
|
end
|
@@ -21,6 +21,14 @@ module PopulateMe
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
def outcast_string field, item, o={}
|
25
|
+
if item.key? :autocomplete
|
26
|
+
item = item.dup
|
27
|
+
item[:autocomplete] = WebUtils.deep_copy(WebUtils.get_value(item[:autocomplete],self))
|
28
|
+
end
|
29
|
+
item
|
30
|
+
end
|
31
|
+
|
24
32
|
def outcast_list field, item, o={}
|
25
33
|
item = item.dup
|
26
34
|
item[:items] = self.__send__(field).map do |nested|
|
@@ -66,6 +74,7 @@ module PopulateMe
|
|
66
74
|
def outcast_attachment field, item, o={}
|
67
75
|
item = item.dup
|
68
76
|
item[:url] = self.attachment(field).url
|
77
|
+
item[:multiple] = (self.new? and self.class.batch_field == field)
|
69
78
|
item
|
70
79
|
end
|
71
80
|
|
@@ -118,14 +118,21 @@ module PopulateMe
|
|
118
118
|
def label sym # sets the label_field
|
119
119
|
@label_field = sym.to_sym
|
120
120
|
end
|
121
|
-
|
121
|
+
|
122
122
|
def label_field
|
123
123
|
return @label_field if self.fields.empty?
|
124
|
-
@label_field || self.fields.find do |k,v|
|
124
|
+
@label_field || self.fields.find do |k,v|
|
125
125
|
not [:id,:polymorphic_type].include?(v[:type])
|
126
126
|
end[0]
|
127
127
|
end
|
128
128
|
|
129
|
+
def batch_on_field sym # sets the batch_field
|
130
|
+
@batch_field = sym.to_sym
|
131
|
+
end
|
132
|
+
def batch_field
|
133
|
+
@batch_field
|
134
|
+
end
|
135
|
+
|
129
136
|
def sort_by f, direction=:asc
|
130
137
|
raise(ArgumentError) unless [:asc,:desc].include? direction
|
131
138
|
raise(ArgumentError) unless self.new.respond_to? f
|
data/lib/populate_me/version.rb
CHANGED
data/populate-me.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_dependency 'sinatra', '~> 2'
|
22
22
|
s.add_dependency 'json', '~> 2.1'
|
23
23
|
|
24
|
-
s.add_development_dependency 'bundler', '
|
24
|
+
s.add_development_dependency 'bundler', '>= 2.2.10'
|
25
25
|
s.add_development_dependency 'minitest', '~> 5.8'
|
26
26
|
s.add_development_dependency 'rack-test', '~> 0.6'
|
27
27
|
s.add_development_dependency 'rack-cerberus', '~> 1.0'
|
data/test/test_admin.rb
CHANGED
@@ -22,6 +22,12 @@ class AdminWithCerberusPass < Admin
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
class AdminWithCustomCerberusAuth < AdminWithCerberusPass
|
26
|
+
def self.cerberus_auth user, pass, req
|
27
|
+
[user, pass] == ['mario', '1234']
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
25
31
|
class AdminCerberusNotAvailable < AdminWithCerberusPass
|
26
32
|
def self.cerberus_available?
|
27
33
|
false
|
@@ -106,19 +112,54 @@ describe PopulateMe::Admin do
|
|
106
112
|
assert_equal 'text/css', last_response.content_type
|
107
113
|
end
|
108
114
|
|
109
|
-
describe '
|
115
|
+
describe 'When cerberus is active' do
|
110
116
|
let(:app) { AdminWithCerberusPass.new }
|
111
117
|
it 'Uses Cerberus for authentication' do
|
112
118
|
get '/'
|
113
119
|
assert_equal 401, last_response.status
|
114
120
|
end
|
121
|
+
it 'Authenticates with right login details' do
|
122
|
+
get '/', {
|
123
|
+
cerberus_login: 'admin',
|
124
|
+
cerberus_pass: '123',
|
125
|
+
_method: 'get'
|
126
|
+
}
|
127
|
+
assert_equal 200, last_response.status
|
128
|
+
end
|
129
|
+
it 'Fails authentication when login details are wrong' do
|
130
|
+
get '/', {
|
131
|
+
cerberus_login: 'admin',
|
132
|
+
cerberus_pass: 'xxx',
|
133
|
+
_method: 'get'
|
134
|
+
}
|
135
|
+
assert_equal 401, last_response.status
|
136
|
+
end
|
115
137
|
end
|
116
|
-
describe '
|
138
|
+
describe 'When cerberus is inactive' do
|
117
139
|
it 'Does not use Cerberus' do
|
118
140
|
get '/'
|
119
141
|
assert_predicate last_response, :ok?
|
120
142
|
end
|
121
143
|
end
|
144
|
+
describe 'When cerberus_auth is overridden' do
|
145
|
+
let(:app) { AdminWithCustomCerberusAuth.new }
|
146
|
+
it 'Authenticates with right login details' do
|
147
|
+
get '/', {
|
148
|
+
cerberus_login: 'mario',
|
149
|
+
cerberus_pass: '1234',
|
150
|
+
_method: 'get'
|
151
|
+
}
|
152
|
+
assert_equal 200, last_response.status
|
153
|
+
end
|
154
|
+
it 'Fails authentication when login details are wrong' do
|
155
|
+
get '/', {
|
156
|
+
cerberus_login: 'admin',
|
157
|
+
cerberus_pass: '123',
|
158
|
+
_method: 'get'
|
159
|
+
}
|
160
|
+
assert_equal 401, last_response.status
|
161
|
+
end
|
162
|
+
end
|
122
163
|
|
123
164
|
end
|
124
165
|
|
@@ -178,7 +178,7 @@ describe PopulateMe::Document, 'AdminAdapter' do
|
|
178
178
|
describe '#to_admin_form' do
|
179
179
|
class PolyForm < PopulateMe::Document
|
180
180
|
field :name
|
181
|
-
field :image, only_for: 'Image'
|
181
|
+
field :image, only_for: 'Image', type: :attachment, class_name: PopulateMe::Attachment
|
182
182
|
field :title, only_for: 'Article'
|
183
183
|
field :content, only_for: 'Article'
|
184
184
|
field :position
|
@@ -215,6 +215,29 @@ describe PopulateMe::Document, 'AdminAdapter' do
|
|
215
215
|
form = obj.to_admin_form
|
216
216
|
assert_nil form[:polymorphic_type]
|
217
217
|
end
|
218
|
+
|
219
|
+
class WithBatchField < PopulateMe::Document
|
220
|
+
field :name
|
221
|
+
field :thumbnail, type: :attachment, class_name: PopulateMe::Attachment
|
222
|
+
batch_on_field :thumbnail
|
223
|
+
end
|
224
|
+
it 'Sets :batch_field if there is one' do
|
225
|
+
obj = PolyForm.new
|
226
|
+
form = obj.to_admin_form
|
227
|
+
assert_nil form[:batch_field]
|
228
|
+
obj = NotPolyForm.new
|
229
|
+
form = obj.to_admin_form
|
230
|
+
assert_nil form[:batch_field]
|
231
|
+
obj = WithBatchField.new
|
232
|
+
form = obj.to_admin_form
|
233
|
+
assert_equal 'data[thumbnail]', form[:batch_field]
|
234
|
+
end
|
235
|
+
it 'Does not add a batch field when updating' do
|
236
|
+
obj = WithBatchField.new
|
237
|
+
obj._is_new = false
|
238
|
+
form = obj.to_admin_form
|
239
|
+
assert_nil form[:batch_field]
|
240
|
+
end
|
218
241
|
end
|
219
242
|
|
220
243
|
end
|
@@ -6,6 +6,7 @@ class Outcasted < PopulateMe::Document
|
|
6
6
|
set :default_attachment_class, PopulateMe::Attachment
|
7
7
|
|
8
8
|
field :name
|
9
|
+
field :category, autocomplete: ['Fish', 'Cat', 'Bunny']
|
9
10
|
field :size, type: :select, select_options: [
|
10
11
|
{description: 'small', value: 's'},
|
11
12
|
{description: 'medium', value: 'm'},
|
@@ -19,10 +20,17 @@ class Outcasted < PopulateMe::Document
|
|
19
20
|
field :tags, type: :select, select_options: ['art','sport','science'], multiple: true
|
20
21
|
field :related_properties, type: :select, select_options: ['prop1','prop2','prop3'], multiple: true
|
21
22
|
field :pdf, type: :attachment
|
23
|
+
field :image, type: :attachment
|
22
24
|
field :authors, type: :list
|
23
25
|
field :weirdo, type: :strange
|
24
26
|
field :price, type: :price
|
25
27
|
|
28
|
+
batch_on_field :image
|
29
|
+
|
30
|
+
def get_category_autocomplete_list
|
31
|
+
['Horse', 'Bear']
|
32
|
+
end
|
33
|
+
|
26
34
|
def get_size_options
|
27
35
|
[
|
28
36
|
[:small, :s],
|
@@ -37,6 +45,11 @@ class Outcasted::Author < PopulateMe::Document
|
|
37
45
|
field :name
|
38
46
|
end
|
39
47
|
|
48
|
+
class OutcastedNoBatchField < PopulateMe::Document
|
49
|
+
set :default_attachment_class, PopulateMe::Attachment
|
50
|
+
field :image, type: :attachment
|
51
|
+
end
|
52
|
+
|
40
53
|
describe PopulateMe::Document, 'Outcasting' do
|
41
54
|
|
42
55
|
parallelize_me!
|
@@ -65,6 +78,36 @@ describe PopulateMe::Document, 'Outcasting' do
|
|
65
78
|
|
66
79
|
end
|
67
80
|
|
81
|
+
describe '#outcast_string' do
|
82
|
+
|
83
|
+
it 'Generates the autocomplete options when needed' do
|
84
|
+
original = Outcasted.fields[:category]
|
85
|
+
output = Outcasted.new.outcast(:category, original, {input_name_prefix: 'data'})
|
86
|
+
assert_equal ['Fish', 'Cat', 'Bunny'], output[:autocomplete]
|
87
|
+
refute original.equal?(output)
|
88
|
+
|
89
|
+
original = Outcasted.fields[:name]
|
90
|
+
output = Outcasted.new.outcast(:name, original, {input_name_prefix: 'data'})
|
91
|
+
refute output.key?(:autocomplete)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'Generates the autocomplete options from a proc' do
|
95
|
+
original = Outcasted.fields[:category].dup
|
96
|
+
original[:autocomplete] = proc{ ['Dog', 'Snake'] }
|
97
|
+
output = Outcasted.new.outcast(:category, original, {input_name_prefix: 'data'})
|
98
|
+
assert_equal ['Dog', 'Snake'], output[:autocomplete]
|
99
|
+
assert original[:autocomplete].is_a?(Proc)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'Generates the autocomplete options from a method name' do
|
103
|
+
original = Outcasted.fields[:category].dup
|
104
|
+
original[:autocomplete] = :get_category_autocomplete_list
|
105
|
+
output = Outcasted.new.outcast(:category, original, {input_name_prefix: 'data'})
|
106
|
+
assert_equal ['Horse', 'Bear'], output[:autocomplete]
|
107
|
+
assert original[:autocomplete].is_a?(Symbol)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
68
111
|
describe '#outcast_list' do
|
69
112
|
|
70
113
|
it 'Has no value and an empty list of items when list is empty' do
|
@@ -241,6 +284,35 @@ describe PopulateMe::Document, 'Outcasting' do
|
|
241
284
|
assert_equal outcasted.attachment(:pdf).url, output[:url]
|
242
285
|
end
|
243
286
|
|
287
|
+
it 'Sets multiple if field is the batch field and document is new' do
|
288
|
+
original = Outcasted.fields[:image]
|
289
|
+
outcasted = Outcasted.new
|
290
|
+
output = outcasted.outcast(:image, original, {input_name_prefix: 'data'})
|
291
|
+
assert output[:multiple]
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'Does not set multiple if there is no batch field' do
|
295
|
+
original = OutcastedNoBatchField.fields[:image]
|
296
|
+
outcasted = OutcastedNoBatchField.new
|
297
|
+
output = outcasted.outcast(:image, original, {input_name_prefix: 'data'})
|
298
|
+
refute output[:multiple]
|
299
|
+
end
|
300
|
+
|
301
|
+
it 'Does not set multiple if document is not new' do
|
302
|
+
original = Outcasted.fields[:image]
|
303
|
+
outcasted = Outcasted.new
|
304
|
+
outcasted._is_new = false
|
305
|
+
output = outcasted.outcast(:image, original, {input_name_prefix: 'data'})
|
306
|
+
refute output[:multiple]
|
307
|
+
end
|
308
|
+
|
309
|
+
it 'Does not set multiple if field not the batch field' do
|
310
|
+
original = Outcasted.fields[:pdf]
|
311
|
+
outcasted = Outcasted.new
|
312
|
+
output = outcasted.outcast(:pdf, original, {input_name_prefix: 'data'})
|
313
|
+
refute output[:multiple]
|
314
|
+
end
|
315
|
+
|
244
316
|
end
|
245
317
|
|
246
318
|
end
|
@@ -6,6 +6,26 @@ describe PopulateMe::Document, 'Schema' do
|
|
6
6
|
|
7
7
|
parallelize_me!
|
8
8
|
|
9
|
+
describe "Batch field" do
|
10
|
+
|
11
|
+
class BatchFieldSet < PopulateMe::Document
|
12
|
+
field :name
|
13
|
+
field :image
|
14
|
+
batch_on_field :image
|
15
|
+
end
|
16
|
+
|
17
|
+
class NotBatchFieldSet < PopulateMe::Document
|
18
|
+
field :name
|
19
|
+
field :image
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'Sets batch field correctly' do
|
23
|
+
assert_equal :image, BatchFieldSet.batch_field
|
24
|
+
assert_nil NotBatchFieldSet.batch_field
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
9
29
|
describe "Relationships" do
|
10
30
|
|
11
31
|
class Relative < PopulateMe::Document
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: populate-me
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.17.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mickael Riga
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: web-utils
|
@@ -56,16 +56,16 @@ dependencies:
|
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 2.2.10
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 2.2.10
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: minitest
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -198,6 +198,7 @@ files:
|
|
198
198
|
- lib/populate_me/admin/__assets__/css/asmselect.css
|
199
199
|
- lib/populate_me/admin/__assets__/css/jquery-ui.min.css
|
200
200
|
- lib/populate_me/admin/__assets__/css/main.css
|
201
|
+
- lib/populate_me/admin/__assets__/img/favicon.png
|
201
202
|
- lib/populate_me/admin/__assets__/img/file.png
|
202
203
|
- lib/populate_me/admin/__assets__/img/help/children.png
|
203
204
|
- lib/populate_me/admin/__assets__/img/help/create.png
|