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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e07006c1f567c3309a537233c482114dd0536b783c6e82b1cafcf7d5c53fa12
4
- data.tar.gz: f36fc1cb24ac5b59ea7090c6ffc5c425d437ef95e36f528fb012bb721472d185
3
+ metadata.gz: ab01b0340f42771cfda2e496e4dee387c3e098ee2757ee374f5fb9a95fda48b0
4
+ data.tar.gz: b74800276c349db0d4dcc74f46f36d5b6fb6a46cb4d727c5dbfb9e46d35d0aa4
5
5
  SHA512:
6
- metadata.gz: 6e53cfb5b625bbb4835cb5ba5fa5e404dfaac6e23eb607d5f981ff6c60ed67f2939d0dd4a288476ce1bd486804264c6516b2a79439c6ba302a080c2a0270dd2c
7
- data.tar.gz: 2ca83c16c743176e272793b3d411887b7b3ea9a7f4d01ba71cad0fcd2e1417423d526116d7f09ef4f24b4fc85c54b0c9399cb6a6445fb4c074d1ac09892fa1af
6
+ metadata.gz: 7621910d4fec3622e2bad85742c0877fbe6bafdf9dcb28f804e40d5ae255b362de66cdf6d978a1d49fa27874527705d2cec80146e2624f71ac4783a4bd8b5554
7
+ data.tar.gz: c65c5db1c8361cb50ada68e63cc246325590a0e8ca00a2f6a3e90e047f73cbc4a0072293ab52a60317a9b0710e96d7439ac3efd1860d3d134edd848ae144670f
@@ -214,6 +214,14 @@ fieldset {
214
214
  color: #dc322f;
215
215
  }
216
216
 
217
+ .error {
218
+ color: #dc322f;
219
+ }
220
+
221
+ .batch-upload-report {
222
+ margin: 20px;
223
+ }
224
+
217
225
  /* asmSelect */
218
226
 
219
227
  .asmListItem {
@@ -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
- var max_size = parseInt(field.data('max-size'));
150
- if (field[0].files[0]) {
151
- var fsize = field[0].files[0].size;
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
- if (PopulateMe.jsValidationsPassed(self)) {
310
-
311
- var submit_button = $('input[type=submit]',self);
312
- submit_button.hide();
313
- $.ajax({
314
- url: self.attr('action'),
315
- type: (self.is('.admin-put') ? 'put' : 'post'),
316
- data: new FormData(this),
317
- processData: false,
318
- contentType: false,
319
- success: function(res) {
320
- if (res.success==true) {
321
- var reloader = PopulateMe.finder.find('> li:nth-last-child(3) .selected');
322
- if (reloader.size()>0) {
323
- var reloadee = PopulateMe.finder.find('> li:nth-last-child(2)');
324
- var current_search = PopulateMe.copy_column_search(reloadee);
325
- reloader.trigger('click.columnav',[function(cb_object) {
326
- var target = $('[data-id='+res.data._id+']', cb_object.column);
327
- if (target.size()>0) {
328
- PopulateMe.restore_column_search(cb_object.column, current_search);
329
- PopulateMe.scroll_to(target, cb_object.column);
330
- }
331
- }]);
332
- } else {
333
- PopulateMe.finder.trigger('pop.columnav');
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
- error: function(xhr) {
338
- res = xhr.responseJSON;
339
- if (res.success==false) {
340
- $('.invalid',self).removeClass('invalid');
341
- $('.errors',self).remove();
342
- PopulateMe.mark_errors(self,res.data);
343
- PopulateMe.scroll_to(self.find('.invalid:first'));
344
- submit_button.show();
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">
@@ -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==cerberus_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
 
@@ -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
@@ -1,4 +1,4 @@
1
1
  module PopulateMe
2
- VERSION = '0.14.0'
2
+ VERSION = '0.17.0'
3
3
  end
4
4
 
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', '~> 1.13'
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 'when cerberus is active' do
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 'when cerberus is inactive' do
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.14.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: 2021-05-03 00:00:00.000000000 Z
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: '1.13'
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: '1.13'
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