volt 0.8.27.beta6 → 0.8.27.beta7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -3
- data/VERSION +1 -1
- data/app/volt/models/user.rb +1 -1
- data/app/volt/tasks/query_tasks.rb +2 -2
- data/app/volt/tasks/store_tasks.rb +14 -4
- data/app/volt/tasks/user_tasks.rb +1 -1
- data/lib/volt/controllers/http_controller.rb +60 -0
- data/lib/volt/controllers/model_controller.rb +5 -1
- data/lib/volt/extra_core/string.rb +6 -0
- data/lib/volt/models/array_model.rb +6 -2
- data/lib/volt/models/associations.rb +1 -1
- data/lib/volt/models/buffer.rb +14 -3
- data/lib/volt/models/model.rb +28 -60
- data/lib/volt/models/permissions.rb +4 -4
- data/lib/volt/reactive/computation.rb +15 -15
- data/lib/volt/reactive/reactive_array.rb +1 -0
- data/lib/volt/router/routes.rb +67 -27
- data/lib/volt/server.rb +37 -6
- data/lib/volt/server/component_templates.rb +2 -2
- data/lib/volt/server/rack/http_request.rb +50 -0
- data/lib/volt/server/rack/http_resource.rb +41 -0
- data/lib/volt/server/rack/http_response_header.rb +33 -0
- data/lib/volt/server/rack/http_response_renderer.rb +41 -0
- data/lib/volt/spec/setup.rb +4 -2
- data/lib/volt/tasks/dispatcher.rb +7 -7
- data/lib/volt/tasks/task_handler.rb +1 -1
- data/lib/volt/volt/users.rb +12 -6
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +18 -10
- data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +2 -2
- data/spec/apps/kitchen_sink/app/main/controllers/server/simple_http_controller.rb +15 -0
- data/spec/apps/kitchen_sink/app/main/controllers/upload_controller.rb +22 -0
- data/spec/apps/kitchen_sink/app/main/views/main/yield.html +2 -2
- data/spec/apps/kitchen_sink/app/main/views/upload/index.html +15 -0
- data/spec/controllers/http_controller_spec.rb +130 -0
- data/spec/extra_core/string_transformation_test_cases.rb +8 -0
- data/spec/extra_core/string_transformations_spec.rb +12 -0
- data/spec/integration/http_endpoints_spec.rb +29 -0
- data/spec/integration/user_spec.rb +42 -42
- data/spec/models/associations_spec.rb +4 -4
- data/spec/models/buffer_spec.rb +15 -0
- data/spec/models/model_spec.rb +70 -25
- data/spec/models/model_state_spec.rb +1 -1
- data/spec/models/permissions_spec.rb +64 -2
- data/spec/models/persistors/params_spec.rb +8 -8
- data/spec/models/persistors/store_spec.rb +1 -1
- data/spec/models/user_validation_spec.rb +1 -1
- data/spec/router/routes_spec.rb +111 -43
- data/spec/server/rack/http_request_spec.rb +50 -0
- data/spec/server/rack/http_resource_spec.rb +59 -0
- data/spec/server/rack/http_response_header_spec.rb +34 -0
- data/spec/server/rack/http_response_renderer_spec.rb +33 -0
- data/spec/tasks/dispatcher_spec.rb +2 -2
- data/templates/component/config/routes.rb +2 -2
- data/templates/project/Gemfile.tt +3 -5
- data/templates/project/app/main/config/routes.rb +4 -4
- data/volt.gemspec +2 -2
- metadata +33 -8
@@ -33,48 +33,48 @@ if ENV['BROWSER']
|
|
33
33
|
|
34
34
|
expect(page).to have_content('Test Account 9550')
|
35
35
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
36
|
+
|
37
|
+
it 'should login and logout' do
|
38
|
+
visit '/'
|
39
|
+
|
40
|
+
# Add the user
|
41
|
+
store._users! << { email: 'test@test.com', password: 'awes0mesEcRet', name: 'Test Account 9550' }
|
42
|
+
|
43
|
+
click_link 'Login'
|
44
|
+
|
45
|
+
fields = all(:css, 'form .form-control')
|
46
|
+
fields[0].set('test@test.com')
|
47
|
+
fields[1].set('awes0mesEcRet')
|
48
|
+
click_button 'Login'
|
49
|
+
|
50
|
+
expect(page).to have_content('Test Account 9550')
|
51
|
+
|
52
|
+
# Click the logout link
|
53
|
+
click_link 'Test Account 9550'
|
54
|
+
click_link 'Logout'
|
55
|
+
|
56
|
+
expect(page).to_not have_content('Test Account 9550')
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should fail to create an account without a valid email and password' do
|
60
|
+
visit '/'
|
61
|
+
|
62
|
+
click_link 'Login'
|
63
|
+
click_link 'Signup here'
|
64
|
+
|
65
|
+
expect(page).to_not have_content('must be at least 8 characters')
|
66
|
+
|
67
|
+
fields = all(:css, 'form .form-control')
|
68
|
+
|
69
|
+
fields[0].set('test')
|
70
|
+
fields[1].set('awe')
|
71
|
+
fields[2].set('Tes')
|
72
|
+
|
73
|
+
# some capybara drivers don't trigger blur correctly
|
74
|
+
page.execute_script("$('.form-control').blur()")
|
75
|
+
|
76
|
+
expect(page).to have_content('must be at least 8 characters')
|
77
|
+
end
|
78
78
|
end
|
79
79
|
|
80
80
|
end
|
@@ -14,20 +14,20 @@ describe Volt::Associations do
|
|
14
14
|
# DataStore.new.drop_database
|
15
15
|
# $page.instance_variable_set('@store', nil)
|
16
16
|
|
17
|
-
store._people << {name: 'Jimmy'}
|
17
|
+
store._people! << {name: 'Jimmy'}
|
18
18
|
@person = store._people[0]
|
19
|
-
@person._addresses << {city: 'Bozeman'}
|
19
|
+
@person._addresses! << {city: 'Bozeman'}
|
20
20
|
@person._addresses << {city: 'Portland'}
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'should associate via belongs_to' do
|
24
|
-
address = store._addresses
|
24
|
+
address = store._addresses!.fetch_first.sync
|
25
25
|
|
26
26
|
expect(address.person.sync._id).to eq(@person._id)
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'should associate via has_many' do
|
30
|
-
person = store._people
|
30
|
+
person = store._people!.fetch_first.sync
|
31
31
|
|
32
32
|
addresses = person.addresses.fetch.sync
|
33
33
|
expect(addresses.size).to eq(2)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Volt::Buffer do
|
4
|
+
it 'should let you pass a block that evaluates to the then of the promise' do
|
5
|
+
buffer = the_page._items!.buffer
|
6
|
+
|
7
|
+
count = 0
|
8
|
+
result = buffer.save! do
|
9
|
+
count += 1
|
10
|
+
end
|
11
|
+
|
12
|
+
expect(count).to eq(1)
|
13
|
+
expect(result.class).to eq(Promise)
|
14
|
+
end
|
15
|
+
end
|
data/spec/models/model_spec.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'volt/models'
|
3
2
|
|
4
3
|
class TestItem < Volt::Model
|
5
4
|
end
|
@@ -53,9 +52,9 @@ describe Volt::Model do
|
|
53
52
|
expect(!a._false1).to eq(true)
|
54
53
|
end
|
55
54
|
|
56
|
-
it "should return
|
55
|
+
it "should return an empty model for an underscore value that doesn't exist" do
|
57
56
|
a = Volt::Model.new
|
58
|
-
expect(a._something
|
57
|
+
expect(a._something!.attributes).to eq({})
|
59
58
|
end
|
60
59
|
|
61
60
|
it 'should trigger changed once when a new value is assigned.' do
|
@@ -141,7 +140,7 @@ describe Volt::Model do
|
|
141
140
|
it 'should trigger changed for any indicies after a deleted index' do
|
142
141
|
model = Volt::Model.new
|
143
142
|
|
144
|
-
model._items << { _name: 'One' }
|
143
|
+
model._items! << { _name: 'One' }
|
145
144
|
model._items << { _name: 'Two' }
|
146
145
|
model._items << { _name: 'Three' }
|
147
146
|
|
@@ -157,7 +156,7 @@ describe Volt::Model do
|
|
157
156
|
it 'should change the size and length when an item gets added' do
|
158
157
|
model = Volt::Model.new
|
159
158
|
|
160
|
-
model._items << { _name: 'One' }
|
159
|
+
model._items! << { _name: 'One' }
|
161
160
|
size = model._items.size
|
162
161
|
length = model._items.length
|
163
162
|
|
@@ -178,30 +177,73 @@ describe Volt::Model do
|
|
178
177
|
it 'should add doubly nested arrays' do
|
179
178
|
model = Volt::Model.new
|
180
179
|
|
181
|
-
model._items << { name: 'Cool', lists: [] }
|
182
|
-
model._items[0]._lists << { name: 'worked' }
|
180
|
+
model._items! << { name: 'Cool', lists: [] }
|
181
|
+
model._items[0]._lists! << { name: 'worked' }
|
183
182
|
expect(model._items[0]._lists[0]._name).to eq('worked')
|
184
183
|
end
|
185
184
|
|
186
185
|
it 'should make pushed subarrays into ArrayModels' do
|
187
186
|
model = Volt::Model.new
|
188
187
|
|
189
|
-
model._items << { _name: 'Test', _lists: [] }
|
188
|
+
model._items! << { _name: 'Test', _lists: [] }
|
190
189
|
expect(model._items[0]._lists.class).to eq(Volt::ArrayModel)
|
191
190
|
end
|
192
191
|
|
193
192
|
it 'should make assigned subarrays into ArrayModels' do
|
194
193
|
model = Volt::Model.new
|
195
194
|
|
196
|
-
model._item
|
195
|
+
model._item!._name = 'Test'
|
197
196
|
model._item._lists = []
|
198
197
|
expect(model._item._lists.class).to eq(Volt::ArrayModel)
|
199
198
|
end
|
200
199
|
|
200
|
+
it 'should call changed when an expanded reference changes' do
|
201
|
+
a = Volt::Model.new
|
202
|
+
|
203
|
+
count = 0
|
204
|
+
-> { a._blue ; count += 1 }.watch!
|
205
|
+
|
206
|
+
expect(count).to eq(1)
|
207
|
+
|
208
|
+
a._blue!
|
209
|
+
Volt::Computation.flush!
|
210
|
+
|
211
|
+
expect(count).to eq(2)
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'should call size changed when adding to an ArrayModel' do
|
215
|
+
a = Volt::Model.new
|
216
|
+
|
217
|
+
count = 0
|
218
|
+
-> { count = a._todos.size }.watch!
|
219
|
+
|
220
|
+
expect(count).to eq(0)
|
221
|
+
|
222
|
+
a._todos << {label: 'Be active'}
|
223
|
+
Volt::Computation.flush!
|
224
|
+
|
225
|
+
expect(count).to eq(1)
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'should track changes through an expansion' do
|
229
|
+
a = Volt::Model.new
|
230
|
+
|
231
|
+
last_count = 0
|
232
|
+
-> { last_count = a._todos.count(&:_checked) }.watch!
|
233
|
+
|
234
|
+
expect(last_count).to eq(0)
|
235
|
+
|
236
|
+
a._todos! << {checked: true}
|
237
|
+
Volt::Computation.flush!
|
238
|
+
|
239
|
+
expect(last_count).to eq(1)
|
240
|
+
end
|
241
|
+
|
201
242
|
it 'should call changed when a the reference to a submodel is assigned to another value' do
|
202
243
|
a = Volt::Model.new
|
203
244
|
|
204
245
|
count = 0
|
246
|
+
a._blue!
|
205
247
|
-> { a._blue && a._blue.respond_to?(:_green) && a._blue._green; count += 1 }.watch!
|
206
248
|
expect(count).to eq(1)
|
207
249
|
|
@@ -215,7 +257,7 @@ describe Volt::Model do
|
|
215
257
|
expect(count).to eq(3)
|
216
258
|
|
217
259
|
a._blue = { green: 50 }
|
218
|
-
expect(a._blue
|
260
|
+
expect(a._blue!._green).to eq(50)
|
219
261
|
Volt::Computation.flush!
|
220
262
|
expect(count).to eq(4)
|
221
263
|
end
|
@@ -239,14 +281,14 @@ describe Volt::Model do
|
|
239
281
|
it 'should let you append nested hashes' do
|
240
282
|
a = Volt::Model.new
|
241
283
|
|
242
|
-
a._items << { name: { text: 'Name' } }
|
284
|
+
a._items! << { name: { text: 'Name' } }
|
243
285
|
|
244
|
-
expect(a._items[0]._name
|
286
|
+
expect(a._items[0]._name!._text).to eq('Name')
|
245
287
|
end
|
246
288
|
|
247
289
|
it 'should not call added too many times' do
|
248
290
|
a = Volt::Model.new
|
249
|
-
a._lists << 1
|
291
|
+
a._lists! << 1
|
250
292
|
|
251
293
|
count = 0
|
252
294
|
a._lists.on('added') { count += 1 }
|
@@ -258,6 +300,9 @@ describe Volt::Model do
|
|
258
300
|
|
259
301
|
it 'should propigate to different branches' do
|
260
302
|
a = Volt::Model.new
|
303
|
+
|
304
|
+
# Expand first
|
305
|
+
a._new_item!
|
261
306
|
count = 0
|
262
307
|
-> do
|
263
308
|
count += 1
|
@@ -273,11 +318,11 @@ describe Volt::Model do
|
|
273
318
|
describe 'paths' do
|
274
319
|
it 'should store the path' do
|
275
320
|
a = Volt::Model.new
|
276
|
-
expect(a._test
|
321
|
+
expect(a._test!.path).to eq([:test])
|
277
322
|
a._test = { _name: 'Yes' }
|
278
323
|
expect(a._test.path).to eq([:test])
|
279
324
|
|
280
|
-
a._items << { _name: 'Yes' }
|
325
|
+
a._items! << { _name: 'Yes' }
|
281
326
|
expect(a._items.path).to eq([:items])
|
282
327
|
expect(a._items[0].path).to eq([:items, :[]])
|
283
328
|
end
|
@@ -294,7 +339,7 @@ describe Volt::Model do
|
|
294
339
|
it 'should handle nested paths' do
|
295
340
|
a = Volt::Model.new
|
296
341
|
|
297
|
-
a._items << { name: 'Cool', lists: [{ name: 'One' }, { name: 'Two' }] }
|
342
|
+
a._items! << { name: 'Cool', lists: [{ name: 'One' }, { name: 'Two' }] }
|
298
343
|
|
299
344
|
expect(a._items[0]._lists.path).to eq([:items, :[], :lists])
|
300
345
|
expect(a._items[0]._lists[1].path).to eq([:items, :[], :lists, :[]])
|
@@ -303,7 +348,7 @@ describe Volt::Model do
|
|
303
348
|
it 'should trigger added when added' do
|
304
349
|
a = Volt::Model.new
|
305
350
|
count = 0
|
306
|
-
b = a._items
|
351
|
+
b = a._items!
|
307
352
|
|
308
353
|
b.on('added') { count += 1 }
|
309
354
|
expect(count).to eq(0)
|
@@ -360,7 +405,7 @@ describe Volt::Model do
|
|
360
405
|
|
361
406
|
it 'should convert to a hash, and unwrap all of the way down' do
|
362
407
|
a = Volt::Model.new
|
363
|
-
a._items << { name: 'Test1', other: { time: 'Now' } }
|
408
|
+
a._items! << { name: 'Test1', other: { time: 'Now' } }
|
364
409
|
a._items << { name: 'Test2', other: { time: 'Later' } }
|
365
410
|
|
366
411
|
item1 = a._items[0].to_h
|
@@ -382,25 +427,25 @@ describe Volt::Model do
|
|
382
427
|
end
|
383
428
|
|
384
429
|
it 'should set the model path' do
|
385
|
-
@model._object
|
430
|
+
@model._object!._name = 'Test'
|
386
431
|
expect(@model._object.path).to eq([:object])
|
387
432
|
end
|
388
433
|
|
389
434
|
it 'should set the model path for a sub array' do
|
390
|
-
@model._items << { name: 'Bob' }
|
435
|
+
@model._items! << { name: 'Bob' }
|
391
436
|
expect(@model._items.path).to eq([:items])
|
392
437
|
expect(@model._items[0].path).to eq([:items, :[]])
|
393
438
|
end
|
394
439
|
|
395
440
|
it 'should set the model path for sub sub arrays' do
|
396
|
-
@model._lists << { name: 'List 1', items: [] }
|
397
|
-
expect(@model._lists[0]._items
|
441
|
+
@model._lists! << { name: 'List 1', items: [] }
|
442
|
+
expect(@model._lists[0]._items!.path).to eq([:lists, :[], :items])
|
398
443
|
end
|
399
444
|
|
400
445
|
it 'should update the path when added from a model instance to a collection' do
|
401
446
|
test_item = TestItem.new
|
402
447
|
|
403
|
-
@model._items << test_item
|
448
|
+
@model._items! << test_item
|
404
449
|
expect(@model._items[0].path).to eq([:items, :[]])
|
405
450
|
end
|
406
451
|
end
|
@@ -440,7 +485,7 @@ describe Volt::Model do
|
|
440
485
|
@model = Volt::Model.new
|
441
486
|
|
442
487
|
# Should return a buffer of the right type
|
443
|
-
expect(@model._items
|
488
|
+
expect(@model._items!.buffer.class).to eq(Item)
|
444
489
|
|
445
490
|
# Should insert as the right type
|
446
491
|
@model._items << { _name: 'Item 1' }
|
@@ -482,7 +527,7 @@ describe Volt::Model do
|
|
482
527
|
|
483
528
|
if RUBY_PLATFORM != 'opal'
|
484
529
|
it 'should update other queries on the server when a new model is created' do
|
485
|
-
query1 = store._todos
|
530
|
+
query1 = store._todos!
|
486
531
|
query2 = store._todos.limit(1)
|
487
532
|
|
488
533
|
count = 0
|
@@ -5,7 +5,7 @@ if RUBY_PLATFORM != 'opal'
|
|
5
5
|
|
6
6
|
describe Volt::Model do
|
7
7
|
it 'should stay loaded while a computaiton is watching some data' do
|
8
|
-
expect(store._items
|
8
|
+
expect(store._items!.loaded_state).to eq(:not_loaded)
|
9
9
|
|
10
10
|
comp = -> { store._items.size }.watch!
|
11
11
|
|
@@ -28,6 +28,25 @@ class ::TestDenyReadName < Volt::Model
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
class ::TestUpdateReadCheck < Volt::Model
|
32
|
+
attr_accessor :create_check, :update_check, :read_check
|
33
|
+
|
34
|
+
permissions(:create) do
|
35
|
+
self.create_check = true
|
36
|
+
allow
|
37
|
+
end
|
38
|
+
|
39
|
+
permissions(:update) do
|
40
|
+
self.update_check = true
|
41
|
+
allow
|
42
|
+
end
|
43
|
+
|
44
|
+
permissions(:read) do
|
45
|
+
self.read_check = true
|
46
|
+
allow
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
31
50
|
describe "model permissions" do
|
32
51
|
it 'should follow CRUD states when checking permissions' do
|
33
52
|
todo = TestUserTodoWithCrudStates.new.buffer
|
@@ -61,7 +80,7 @@ describe "model permissions" do
|
|
61
80
|
if RUBY_PLATFORM != 'opal'
|
62
81
|
describe "read permissions" do
|
63
82
|
it 'should deny read on a field' do
|
64
|
-
model = store._test_deny_read_names
|
83
|
+
model = store._test_deny_read_names!.buffer
|
65
84
|
model._name = 'Jimmy'
|
66
85
|
model._other = 'should be visible'
|
67
86
|
|
@@ -78,7 +97,7 @@ describe "model permissions" do
|
|
78
97
|
end
|
79
98
|
|
80
99
|
it 'should prevent delete if denied' do
|
81
|
-
model = store._test_deny_deletes
|
100
|
+
model = store._test_deny_deletes!.buffer
|
82
101
|
|
83
102
|
model.save!.then do
|
84
103
|
# Saved
|
@@ -92,5 +111,48 @@ describe "model permissions" do
|
|
92
111
|
expect(count).to eq(1)
|
93
112
|
end
|
94
113
|
end
|
114
|
+
|
115
|
+
it 'should not check the read permissions when updating (so that all fields are present for the permissions check)' do
|
116
|
+
model = store._test_update_read_checks!.append({name: 'Ryan'}).sync
|
117
|
+
|
118
|
+
expect(model.create_check).to eq(true)
|
119
|
+
expect(model.read_check).to eq(nil)
|
120
|
+
|
121
|
+
# Update
|
122
|
+
model._name = 'Jimmy'
|
123
|
+
|
124
|
+
expect(model.read_check).to eq(nil)
|
125
|
+
expect(model.update_check).to eq(true)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should not check read permissions on buffer save on server' do
|
129
|
+
model = store._test_update_read_checks!.buffer
|
130
|
+
|
131
|
+
model._name = 'Ryan'
|
132
|
+
|
133
|
+
# Create
|
134
|
+
model.save!
|
135
|
+
|
136
|
+
# Create happens on the save_to, not the buffer
|
137
|
+
expect(model.save_to.create_check).to eq(true)
|
138
|
+
expect(model.save_to.read_check).to eq(nil)
|
139
|
+
|
140
|
+
# Update
|
141
|
+
model._name = 'Jimmy'
|
142
|
+
model.save!
|
143
|
+
|
144
|
+
expect(model.save_to.read_check).to eq(nil)
|
145
|
+
expect(model.save_to.update_check).to eq(true)
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'should not check read on delete, so all fields are available to the permissions block' do
|
149
|
+
model = store._test_update_read_checks!.append({name: 'Ryan'}).sync
|
150
|
+
|
151
|
+
expect(model.read_check).to eq(nil)
|
152
|
+
|
153
|
+
model.destroy
|
154
|
+
|
155
|
+
expect(model.read_check).to eq(nil)
|
156
|
+
end
|
95
157
|
end
|
96
158
|
end
|