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