volt 0.8.18 → 0.8.19
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/CHANGELOG.md +14 -0
- data/Readme.md +2 -1
- data/VERSION +1 -1
- data/app/volt/controllers/notices_controller.rb +12 -2
- data/app/volt/models/user.rb +34 -1
- data/app/volt/tasks/store_tasks.rb +26 -23
- data/app/volt/tasks/user_tasks.rb +26 -2
- data/app/volt/views/notices/index.html +8 -6
- data/lib/volt.rb +47 -1
- data/lib/volt/cli/asset_compile.rb +24 -42
- data/lib/volt/config.rb +24 -14
- data/lib/volt/controllers/model_controller.rb +6 -1
- data/lib/volt/data_stores/mongo_driver.rb +7 -3
- data/lib/volt/models.rb +3 -0
- data/lib/volt/models/array_model.rb +21 -3
- data/lib/volt/models/model.rb +109 -48
- data/lib/volt/models/model_hash_behaviour.rb +25 -8
- data/lib/volt/models/persistors/array_store.rb +5 -2
- data/lib/volt/models/persistors/cookies.rb +91 -0
- data/lib/volt/models/persistors/model_store.rb +52 -14
- data/lib/volt/models/persistors/query/query_listener.rb +4 -1
- data/lib/volt/models/persistors/query/query_listener_pool.rb +1 -1
- data/lib/volt/models/persistors/store_state.rb +5 -5
- data/lib/volt/models/validations.rb +87 -18
- data/lib/volt/models/validators/length_validator.rb +1 -1
- data/lib/volt/models/validators/presence_validator.rb +1 -1
- data/lib/volt/models/validators/unique_validator.rb +28 -0
- data/lib/volt/page/bindings/template_binding.rb +2 -2
- data/lib/volt/page/page.rb +4 -0
- data/lib/volt/page/tasks.rb +2 -2
- data/lib/volt/reactive/computation.rb +2 -0
- data/lib/volt/reactive/hash_dependency.rb +1 -3
- data/lib/volt/reactive/reactive_array.rb +7 -0
- data/lib/volt/reactive/reactive_hash.rb +17 -0
- data/lib/volt/server.rb +1 -1
- data/lib/volt/server/component_templates.rb +3 -6
- data/lib/volt/server/html_parser/view_scope.rb +1 -1
- data/lib/volt/server/rack/component_code.rb +3 -2
- data/lib/volt/server/rack/component_paths.rb +15 -0
- data/lib/volt/server/rack/index_files.rb +1 -1
- data/lib/volt/tasks/dispatcher.rb +26 -12
- data/lib/volt/tasks/task_handler.rb +17 -15
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +3 -0
- data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +26 -0
- data/spec/apps/kitchen_sink/app/main/controllers/users_test_controller.rb +27 -0
- data/spec/apps/kitchen_sink/app/main/views/main/cookie_test.html +25 -0
- data/spec/apps/kitchen_sink/app/main/views/main/flash.html +13 -0
- data/spec/apps/kitchen_sink/app/main/views/main/main.html +3 -0
- data/spec/apps/kitchen_sink/app/main/views/users_test/index.html +22 -0
- data/spec/apps/kitchen_sink/config/app.rb +3 -0
- data/spec/integration/bindings_spec.rb +1 -1
- data/spec/integration/cookies_spec.rb +48 -0
- data/spec/integration/flash_spec.rb +32 -0
- data/spec/models/model_spec.rb +3 -4
- data/spec/models/validations_spec.rb +13 -13
- data/spec/tasks/dispatcher_spec.rb +1 -1
- data/templates/project/config/app.rb.tt +6 -1
- data/templates/project/{public → config/base_page}/index.html +0 -0
- data/volt.gemspec +4 -0
- metadata +47 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d48b14a1bdcbb5bd981ddba1c5eb3605a9ab64c
|
4
|
+
data.tar.gz: 7c74bc1525175653a03f9dc2053eab4cbecc5c29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a234d3f5b18ad192ffb575e7cbfbbf39586048a6e6b6ac835ccc06c2c13b1aaab720a0e5fbd3b8e84326b2553e153ba9fa9df42b7098ef210bd775f8b41198c
|
7
|
+
data.tar.gz: 6f70ce074f81d8c2d3da698090c9cfdd2b871b43ee9483198aaf2e61df477589002f82a8d469f1b8380803ccd7c5d8833f7286a3f375fda537d09cca7fba60d9
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.8.19 - 2014-11-05
|
4
|
+
### Breaking Changes
|
5
|
+
- the default index page is now moved from ```public/index.html``` to ```config/base/index.html``` Please update your app's accordingly. Since the public page is essentially static at the moment, public will only be used for asset pre-compilation (and index.html will be rendered in place)
|
6
|
+
- validations do not use underscore for the field name
|
7
|
+
|
8
|
+
### Added
|
9
|
+
- you can precompile an app with ```bundle exec volt precompile``` - still a work in process
|
10
|
+
- update flash to handle successes, notices, warnings, errors.
|
11
|
+
- Add .keys to models (you can use .keys.each do |key| until we get .each_pair binding support)
|
12
|
+
- added ```cookies``` collection. See docs for more info
|
13
|
+
- ```validate :field_name, unique: true``` now supported (scope coming soon)
|
14
|
+
- added custom validations by passing a block to ```validate``` and returning a hash of errors like ```{field_name => ['...', '...']}```
|
15
|
+
|
3
16
|
## 0.8.18 - 2014-10-26
|
4
17
|
### Added
|
5
18
|
- Added a default app.css.scss file
|
@@ -7,6 +20,7 @@
|
|
7
20
|
### Changed
|
8
21
|
- back button fixed
|
9
22
|
- improve security on task dispatcher
|
23
|
+
- lots of minor bug fixes
|
10
24
|
|
11
25
|
## 0.8.17 - 2014-10-20
|
12
26
|
### Added
|
data/Readme.md
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
[](https://travis-ci.org/voltrb/volt)
|
4
4
|
[](http://inch-ci.org/github/voltrb/volt)
|
5
5
|
[](https://gitter.im/voltrb/volt)
|
6
|
+
[](https://waffle.io/voltrb/volt)
|
6
7
|
|
7
8
|
** For the current status of volt, read: http://voltframework.com/blog
|
8
9
|
|
@@ -33,4 +34,4 @@ Read the [full docs on Volt here](http://voltframework.com/docs)
|
|
33
34
|
|
34
35
|
You want to contribute? Great! Thanks for being awesome! At the moment, we have a big internal todo list, hop on https://gitter.im/voltrb/volt so we don't duplicate work. Pull requests are always welcome, but asking about helping on gitter should save some duplication.
|
35
36
|
|
36
|
-
[](https://pledgie.com/campaigns/26731)
|
37
|
+
[](https://pledgie.com/campaigns/26731)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.8.
|
1
|
+
0.8.19
|
@@ -6,8 +6,18 @@ module Volt
|
|
6
6
|
'yep'
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
10
|
-
|
9
|
+
def map_key_class(key)
|
10
|
+
case key
|
11
|
+
when 'errors'
|
12
|
+
'danger'
|
13
|
+
when 'warnings'
|
14
|
+
'warning'
|
15
|
+
when 'successes'
|
16
|
+
'success'
|
17
|
+
else
|
18
|
+
# notices
|
19
|
+
'info'
|
20
|
+
end
|
11
21
|
end
|
12
22
|
end
|
13
23
|
end
|
data/app/volt/models/user.rb
CHANGED
@@ -1,5 +1,38 @@
|
|
1
|
+
if RUBY_PLATFORM != 'opal'
|
2
|
+
require 'bcrypt'
|
3
|
+
end
|
4
|
+
|
1
5
|
class User < Volt::Model
|
6
|
+
validate :username, unique: true, length: 8
|
7
|
+
if RUBY_PLATFORM == 'opal'
|
8
|
+
# Don't validate on the server
|
9
|
+
validate :password, length: 8
|
10
|
+
end
|
11
|
+
|
2
12
|
def password=(val)
|
3
|
-
|
13
|
+
if Volt.server?
|
14
|
+
# on the server, we bcrypt the password and store the result
|
15
|
+
self._hashed_password = BCrypt::Password.create(val)
|
16
|
+
else
|
17
|
+
self._password = val
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Login the user, return a promise for success
|
22
|
+
def self.login(username, password)
|
23
|
+
puts "Login now"
|
24
|
+
UserTasks.login(username, password).then do |result|
|
25
|
+
puts "Got: #{result.inspect}"
|
26
|
+
|
27
|
+
# Assign the user_id cookie for the user
|
28
|
+
$page.cookies._user_id = result
|
29
|
+
|
30
|
+
# Pass nil back
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.logout
|
36
|
+
$page.cookies.delete(:user_id)
|
4
37
|
end
|
5
38
|
end
|
@@ -12,6 +12,7 @@ class StoreTasks < Volt::TaskHandler
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def load_model(collection, path, data)
|
15
|
+
puts "Load Model: #{path.inspect}"
|
15
16
|
model_name = collection.singularize.camelize
|
16
17
|
|
17
18
|
# TODO: Security check to make sure we have a valid model
|
@@ -22,37 +23,39 @@ class StoreTasks < Volt::TaskHandler
|
|
22
23
|
model_class = Volt::Model
|
23
24
|
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
# Load the model, use the Store persistor and set the path
|
27
|
+
model = model_class.new({}, persistor: Volt::Persistors::StoreFactory.new(nil), path: path)
|
28
|
+
model.persistor.change_state_to(:loaded)
|
29
|
+
|
30
|
+
# Create a buffer
|
31
|
+
buffer = model.buffer
|
30
32
|
|
31
|
-
|
33
|
+
# Assign the data
|
34
|
+
buffer.attributes = data
|
35
|
+
|
36
|
+
return buffer
|
32
37
|
end
|
33
38
|
|
34
39
|
def save(collection, path, data)
|
35
40
|
data = data.symbolize_keys
|
36
|
-
model =
|
37
|
-
|
38
|
-
|
41
|
+
model = nil
|
42
|
+
Volt::Model.nosave do
|
43
|
+
model = load_model(collection, path, data)
|
44
|
+
end
|
39
45
|
|
40
|
-
|
46
|
+
# On the backend, the promise is resolved before its returned, so we can
|
47
|
+
# return from within it.
|
48
|
+
#
|
49
|
+
# Pass the channel as a thread-local so that we don't update the client
|
50
|
+
# who sent the update.
|
51
|
+
Thread.current['in_channel'] = @channel
|
52
|
+
promise = model.save!.then do |result|
|
53
|
+
return nil
|
54
|
+
end
|
41
55
|
|
42
|
-
|
43
|
-
# return from within it.
|
44
|
-
#
|
45
|
-
# Pass the channel as a thread-local so that we don't update the client
|
46
|
-
# who sent the update.
|
47
|
-
Thread.current['in_channel'] = @channel
|
48
|
-
model.persistor.changed do |errors|
|
49
|
-
Thread.current['in_channel'] = nil
|
56
|
+
Thread.current['in_channel'] = nil
|
50
57
|
|
51
|
-
|
52
|
-
end
|
53
|
-
else
|
54
|
-
return errors
|
55
|
-
end
|
58
|
+
return promise
|
56
59
|
end
|
57
60
|
|
58
61
|
def delete(collection, id)
|
@@ -1,6 +1,30 @@
|
|
1
1
|
class UserTasks < Volt::TaskHandler
|
2
2
|
# Login a user, takes a username and password
|
3
|
-
|
4
|
-
|
3
|
+
|
4
|
+
def login(username, password)
|
5
|
+
puts "META: " + Thread.current['meta'].inspect
|
6
|
+
|
7
|
+
if Volt.user
|
8
|
+
puts "USER: " + Volt.user._name
|
9
|
+
end
|
10
|
+
|
11
|
+
return store._users.find(username: username).then do |users|
|
12
|
+
user = users.first
|
13
|
+
|
14
|
+
match_pass = BCrypt::Password.new(user._hashed_password)
|
15
|
+
if match_pass == password
|
16
|
+
raise "app_secret is not configured" unless Volt.config.app_secret
|
17
|
+
|
18
|
+
# TODO: returning here should be possible, but causes some issues
|
19
|
+
|
20
|
+
# Salt the user id with the app_secret so the end user can't tamper with the cookie
|
21
|
+
signature = BCrypt::Password.create("#{Volt.config.app_secret}::#{user._id}")
|
22
|
+
|
23
|
+
# Return user_id:hash on user id
|
24
|
+
next "#{user._id}:#{signature}"
|
25
|
+
else
|
26
|
+
raise "Password did not match"
|
27
|
+
end
|
28
|
+
end
|
5
29
|
end
|
6
30
|
end
|
@@ -11,10 +11,12 @@
|
|
11
11
|
{{ if page._reconnected }}
|
12
12
|
<div class="notices alert alert-success">Reconnected!</div>
|
13
13
|
{{ end }}
|
14
|
-
{{
|
15
|
-
|
16
|
-
{{
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
{{ flash.keys.each do |key| }}
|
15
|
+
{{ if flash.send(:"_#{key}").present? }}
|
16
|
+
<div class="notices alert alert-{{ map_key_class(key) }}" e-click="flash.clear">
|
17
|
+
{{ flash.send(:"_#{key}").each do |notice| }}
|
18
|
+
<p>{{ notice }}</p>
|
19
|
+
{{ end }}
|
20
|
+
</div>
|
21
|
+
{{ end }}
|
20
22
|
{{ end }}
|
data/lib/volt.rb
CHANGED
@@ -16,7 +16,6 @@ module Volt
|
|
16
16
|
end
|
17
17
|
|
18
18
|
class << self
|
19
|
-
include Volt::Config unless RUBY_PLATFORM == 'opal'
|
20
19
|
def root
|
21
20
|
@root ||= File.expand_path(Dir.pwd)
|
22
21
|
end
|
@@ -48,5 +47,52 @@ module Volt
|
|
48
47
|
def in_browser?
|
49
48
|
@in_browser
|
50
49
|
end
|
50
|
+
|
51
|
+
# Get the user_id from the cookie
|
52
|
+
def user_id
|
53
|
+
if Volt.client?
|
54
|
+
user_id_signature = $page.cookies._user_id
|
55
|
+
else
|
56
|
+
# Check meta for the user id and validate it
|
57
|
+
meta_data = Thread.current['meta']
|
58
|
+
if meta_data
|
59
|
+
user_id_signature = meta_data['user_id']
|
60
|
+
else
|
61
|
+
user_id_signature = nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
if user_id_signature.nil?
|
66
|
+
return nil
|
67
|
+
else
|
68
|
+
index = user_id_signature.index(':')
|
69
|
+
user_id = user_id_signature[0...index]
|
70
|
+
|
71
|
+
if RUBY_PLATFORM != 'opal'
|
72
|
+
hash = user_id_signature[(index+1)..-1]
|
73
|
+
|
74
|
+
# Make sure the user hash matches
|
75
|
+
if BCrypt::Password.new(hash) != "#{Volt.config.app_secret}::#{user._id}"
|
76
|
+
# user id has been tampered with, reject
|
77
|
+
raise "user id or hash has been tampered with"
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
return user_id
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Return the current user.
|
87
|
+
def user
|
88
|
+
user_id = self.user_id
|
89
|
+
if user_id
|
90
|
+
return $page.store._users.find_one(_id: user_id)
|
91
|
+
else
|
92
|
+
return nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
51
96
|
end
|
52
97
|
end
|
98
|
+
|
@@ -6,37 +6,19 @@ module Volt
|
|
6
6
|
compile
|
7
7
|
end
|
8
8
|
|
9
|
-
desc 'watch', 'compiles the project to /compiled when a file changes'
|
10
|
-
|
11
|
-
def watch
|
12
|
-
require 'listen'
|
13
|
-
|
14
|
-
listener = Listen.to('app') do |modified, added, removed|
|
15
|
-
compile
|
16
|
-
end
|
17
|
-
|
18
|
-
listener.start # non-blocking
|
19
|
-
|
20
|
-
Signal.trap('SIGINT') do
|
21
|
-
listener.stop
|
22
|
-
end
|
23
|
-
|
24
|
-
compile
|
25
|
-
|
26
|
-
begin
|
27
|
-
sleep
|
28
|
-
rescue ThreadError => e
|
29
|
-
# ignore, breaks out on sigint
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
9
|
private
|
34
10
|
|
35
11
|
def compile
|
36
12
|
print 'compiling project...'
|
37
13
|
require 'fileutils'
|
14
|
+
ENV['SERVER'] = 'true'
|
15
|
+
|
38
16
|
require 'opal'
|
39
17
|
require 'volt'
|
18
|
+
require 'volt/boot'
|
19
|
+
|
20
|
+
Volt.boot(Dir.pwd)
|
21
|
+
|
40
22
|
require 'volt/server/rack/component_paths'
|
41
23
|
require 'volt/server/rack/component_code'
|
42
24
|
require 'volt/server/rack/opal_files'
|
@@ -68,28 +50,26 @@ module Volt
|
|
68
50
|
logical_path = logical_path.to_s
|
69
51
|
# Only include files that aren't compiled elsewhere, like fonts
|
70
52
|
unless logical_path[/[.](y|css|js|html|erb)$/]
|
71
|
-
|
53
|
+
write_sprocket_file(logical_path)
|
72
54
|
end
|
73
55
|
end
|
74
56
|
end
|
75
57
|
|
76
58
|
def write_js_and_css
|
77
59
|
(@index_files.javascript_files + @index_files.css_files).each do |logical_path|
|
78
|
-
logical_path
|
79
|
-
|
60
|
+
if logical_path =~ /^\/assets\//
|
61
|
+
logical_path = logical_path.gsub(/^\/assets\//, '')
|
62
|
+
write_sprocket_file(logical_path)
|
63
|
+
end
|
80
64
|
end
|
81
65
|
end
|
82
66
|
|
83
|
-
def
|
84
|
-
path = "#{@root_path}/
|
85
|
-
|
86
|
-
FileUtils.mkdir_p(File.dirname(path))
|
67
|
+
def write_sprocket_file(logical_path)
|
68
|
+
path = "#{@root_path}/public/assets/#{logical_path}"
|
87
69
|
|
88
70
|
begin
|
89
71
|
content = @opal_files.environment[logical_path].to_s
|
90
|
-
|
91
|
-
file.write(content)
|
92
|
-
end
|
72
|
+
write_file(path, content)
|
93
73
|
rescue Sprockets::FileNotFound, SyntaxError => e
|
94
74
|
# ignore
|
95
75
|
end
|
@@ -98,19 +78,21 @@ module Volt
|
|
98
78
|
def write_component_js
|
99
79
|
javascript_code = @component_handler.compile_for_component('main')
|
100
80
|
|
101
|
-
|
102
|
-
|
103
|
-
File.open(File.join(components_folder, '/main.js'), 'w') do |file|
|
104
|
-
file.write(javascript_code)
|
105
|
-
end
|
81
|
+
path = File.join(Volt.root, '/public/components/main.js')
|
82
|
+
write_file(path, javascript_code)
|
106
83
|
end
|
107
84
|
|
108
85
|
def write_index
|
109
|
-
path = "#{@root_path}/
|
86
|
+
path = "#{@root_path}/public/index.html"
|
87
|
+
|
88
|
+
write_file(path, @index_files.html)
|
89
|
+
end
|
90
|
+
|
91
|
+
def write_file(path, data)
|
110
92
|
FileUtils.mkdir_p(File.dirname(path))
|
111
93
|
|
112
|
-
File.open(path, '
|
113
|
-
file.write(
|
94
|
+
File.open(path, 'wb') do |file|
|
95
|
+
file.write(data)
|
114
96
|
end
|
115
97
|
end
|
116
98
|
end
|
data/lib/volt/config.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
1
|
# Config lets a user set global config options for Volt.
|
2
|
+
require 'configurations'
|
2
3
|
module Volt
|
3
|
-
|
4
|
-
def setup
|
5
|
-
yield config
|
6
|
-
end
|
7
|
-
|
8
|
-
def config
|
9
|
-
@config || self.reset_config!
|
10
|
-
end
|
4
|
+
include Configurations
|
11
5
|
|
12
|
-
|
13
|
-
def
|
6
|
+
class << self
|
7
|
+
def defaults
|
14
8
|
app_name = File.basename(Dir.pwd)
|
15
|
-
|
16
|
-
@config = OpenStruct.new(
|
9
|
+
{
|
17
10
|
app_name: app_name,
|
18
11
|
db_name: ENV['DB_NAME'] || (app_name + '_' + Volt.env.to_s),
|
19
12
|
db_host: ENV['DB_HOST'] || 'localhost',
|
20
13
|
db_port: (ENV['DB_PORT'] || 27_017).to_i,
|
21
|
-
db_driver: ENV['DB_DRIVER'] || 'mongo'
|
22
|
-
|
14
|
+
db_driver: ENV['DB_DRIVER'] || 'mongo',
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
# Resets the configuration to the default (empty hash)
|
19
|
+
def reset_config!
|
20
|
+
self.configure do |c|
|
21
|
+
c.from_h(defaults)
|
22
|
+
end
|
23
23
|
end
|
24
24
|
|
25
25
|
# Load in all .rb files in the config folder
|
@@ -28,5 +28,15 @@ module Volt
|
|
28
28
|
require(config_file)
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
alias_method :setup, :configure
|
33
|
+
alias_method :config, :configuration
|
34
|
+
end
|
35
|
+
|
36
|
+
configuration_defaults do |c|
|
37
|
+
c.from_h(Volt.defaults)
|
31
38
|
end
|
39
|
+
|
40
|
+
|
41
|
+
|
32
42
|
end
|