volt 0.9.0.pre3 → 0.9.0.pre4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -7
  3. data/VERSION +1 -1
  4. data/app/volt/tasks/user_tasks.rb +7 -2
  5. data/lib/volt.rb +1 -0
  6. data/lib/volt/cli/generate.rb +28 -10
  7. data/lib/volt/controllers/http_controller.rb +1 -1
  8. data/lib/volt/extra_core/logger.rb +14 -11
  9. data/lib/volt/models/persistors/query/query_listener.rb +7 -1
  10. data/lib/volt/page/bindings/component_binding.rb +2 -2
  11. data/lib/volt/page/bindings/{template_binding.rb → view_binding.rb} +3 -3
  12. data/lib/volt/page/bindings/{template_binding → view_binding}/grouped_controllers.rb +0 -0
  13. data/lib/volt/page/bindings/{template_binding → view_binding}/view_lookup_for_path.rb +0 -0
  14. data/lib/volt/page/page.rb +1 -1
  15. data/lib/volt/server/html_parser/view_scope.rb +4 -1
  16. data/lib/volt/server/rack/component_paths.rb +1 -1
  17. data/lib/volt/spec/setup.rb +10 -2
  18. data/lib/volt/tasks/dispatcher.rb +10 -3
  19. data/lib/volt/utils/logging/task_argument_filterer.rb +42 -0
  20. data/lib/volt/utils/logging/task_logger.rb +14 -0
  21. data/lib/volt/utils/volt_user_error.rb +4 -0
  22. data/lib/volt/volt/users.rb +2 -2
  23. data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
  24. data/spec/apps/kitchen_sink/app/main/controllers/server/simple_http_controller.rb +1 -1
  25. data/spec/apps/kitchen_sink/app/main/views/main/first_last.html +13 -0
  26. data/spec/apps/kitchen_sink/app/main/views/main/main.html +2 -2
  27. data/spec/controllers/http_controller_spec.rb +2 -2
  28. data/spec/integration/bindings_spec.rb +154 -156
  29. data/spec/integration/cookies_spec.rb +28 -30
  30. data/spec/integration/first_last_spec.rb +14 -0
  31. data/spec/integration/http_endpoints_spec.rb +22 -24
  32. data/spec/integration/templates_spec.rb +7 -9
  33. data/spec/integration/user_spec.rb +49 -52
  34. data/spec/integration/yield_spec.rb +12 -14
  35. data/spec/page/bindings/template_binding/view_lookup_for_path_spec.rb +2 -2
  36. data/spec/server/html_parser/view_parser_spec.rb +2 -2
  37. data/spec/server/rack/http_resource_spec.rb +2 -2
  38. data/spec/utils/task_argument_filtererer_spec.rb +17 -0
  39. data/templates/component/config/routes.rb +0 -5
  40. data/templates/component/controllers/server/.empty_directory +0 -0
  41. data/templates/component/lib/.empty_directory +0 -0
  42. data/templates/component_specs/controllers/server/.empty_directory +0 -0
  43. data/templates/component_specs/integration/.empty_directory +0 -0
  44. data/templates/component_specs/models/.empty_directory +0 -0
  45. data/templates/component_specs/tasks/.empty_directory +0 -0
  46. data/templates/controller/http_controller.rb.tt +1 -1
  47. data/templates/controller/http_controller_spec.rb.tt +5 -0
  48. data/templates/controller/model_controller.rb.tt +1 -1
  49. data/templates/controller/model_controller_spec.rb.tt +5 -0
  50. data/templates/model/model.rb.tt +1 -1
  51. data/templates/model/model_spec.rb.tt +5 -0
  52. data/templates/newgem/app/newgem/controllers/server/.empty_directory +0 -0
  53. data/templates/newgem/app/newgem/lib/.empty_directory +0 -0
  54. data/templates/newgem/lib/newgem.rb.tt +1 -1
  55. data/templates/project/app/main/views/main/main.html.tt +2 -2
  56. data/templates/project/config/app.rb.tt +5 -0
  57. data/templates/project/spec/app/main/controllers/server/sample_http_controller_spec.rb +5 -0
  58. data/templates/project/spec/app/main/tasks/sample_task_spec.rb +5 -0
  59. data/templates/task/task.rb.tt +0 -1
  60. data/templates/task/task_spec.rb.tt +5 -0
  61. data/templates/view/index.html.tt +5 -0
  62. metadata +29 -6
  63. data/templates/view/view.rb.tt +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a657a85e80572c96acf329e6bcae5e6068ab330
4
- data.tar.gz: 03b2010b74fe63a65b47a3032f0c96021dbaaea2
3
+ metadata.gz: e4d4f11c399ddcd63de7bc157707e0b1e5a91561
4
+ data.tar.gz: 773ade706e860021c11bf7d22c78e868fa51d139
5
5
  SHA512:
6
- metadata.gz: ce9938c5ea6de3864eb535bc7edbc8af55e2063aef79d70b0dc478dc4c2836465b7e11f4451818ec5c07d4f833664d2ed8abb1a7821480567a0b9895b4d18cd7
7
- data.tar.gz: f3a520c558f153268123966047d470847ce892bef26cadef22b9dd996be291c77297cced514a52557a5aad01469bf60add2640fead42e3465adbb1b01ab50c7e
6
+ metadata.gz: 0542352171aa44247b3471c8e3ea3838e6d2127f896c56312b127936d523840c6d6e76c7ad16126e46844322004ef119bc1949696e83563b9754db8bc014cbf0
7
+ data.tar.gz: fcb365747674befac85bf8a8b08bf64addb800fb193500e822a8f4cb7cad4ea20ee51f67688d4aedcb47bc89b189867b9c18d39e65ac79c1f2a680ffb457845a
data/CHANGELOG.md CHANGED
@@ -2,18 +2,15 @@
2
2
 
3
3
  ## 0.9.0.pre1
4
4
  ### Added
5
+ - the permissions api has been added!
5
6
  - added has_many and belongs_to on models. See docs.
6
7
  - you can now serve http/rest from Volt. Thanks to @jfahrer for his great work. Docs coming soon.
7
8
  - there is now a generator for controllers and HttpControllers.
8
- - the following were renamed to follow gem naming conventions:
9
- - volt-user-templates (now volt-user_templates)
10
- - volt-bootstrap-jumbotron-theme (now volt-bootstrap_jumbotron_theme)
11
9
  - fixed generated component code
12
10
  - added .order for sorting on the data store (since .sort is a ruby Enum method)
13
11
  - calling .then on ArrayModels has been changed to calling .fetch and .fetch_first. These both return a promise, and take an optional block
14
12
  - added .sync for synchronusly waiting on promises on the server only
15
13
  - added the ability to pass content into tags: (https://github.com/voltrb/docs/blob/master/en/docs/yield_binding.md)
16
- - the {action}_remove method had been changed to before_{action}_remove and after_{action}_remove to provide more hooks and a clearer understanding of when it is happening.
17
14
  - Changed it so content bindings escape all html (for CSRF - thanks @ChaosData)
18
15
  - Added formats, email, phone validators (thanks @lexun and @kxcrl)
19
16
  - each_with_index is now supported in views and the ```index``` value is no longer provided by default.
@@ -24,24 +21,31 @@
24
21
  - bindings will now resolve any values that are promises. (currently only content and attribute, if, each, and template coming soon)
25
22
  - ```store``` is now available inside of specs. If it is accessed in a spec, the database will be cleaned after the spec.
26
23
  - ```the_page``` is a shortcut to the page collection inside of specs. (Unfortunately, ```page``` is used by capybara, so for now we're using ```the_page```, we'll find a better solution in the future.)
24
+ - Add filtering to logging on password, and option to configure filtered args. Also, improve the way errors are displayed.
27
25
 
28
26
  ### Changed
27
+ - template bindings have been renamed to view. ```{{ view "path/for/view" }}``` instead of ```{{ template "path/for/view" }}```
28
+ - the {action}_remove method had been changed to before_{action}_remove and after_{action}_remove to provide more hooks and a clearer understanding of when it is happening.
29
+ - the following were renamed to follow gem naming conventions:
30
+ - volt-user-templates (now volt-user_templates)
31
+ - volt-bootstrap-jumbotron-theme (now volt-bootstrap_jumbotron_theme)
29
32
  - all plural attributes now return an empty ArrayModel. This is to simplify implementation and to unify store's interface.
30
33
  - main_path in generated projects now includes the a component param that can be used to easily point at controllers/views in other components.
31
34
  - previously the main component's controllers were not namespaced. We changed it so all controllers (including those in main) are namespaced. This is makes things more consistent and keeps expectations when working with components.
32
35
  - model attributes no longer return NilModels. Instead they just return nil. You can however add an ! to the end to "expand" the model to an empty model.
33
36
 
34
- ```page._new_todo # => now returns nil```
37
+ ```page._new_todo # => now returns nil```
35
38
 
36
- ```page._new_todo! # => returns an empty model```
39
+ ```page._new_todo! # => returns an empty model```
37
40
 
38
- So if you wanted to use a property on ```_new_todo``` without initializing ```_new_todo```, you could add the ! to the lookup.
41
+ So if you wanted to use a property on ```_new_todo``` without initializing ```_new_todo```, you could add the ! to the lookup.
39
42
  - Volt.user has been renamed to Volt.current_user so its clearer what it returns
40
43
  - _'s are no longer required for route constraints (so just use ```controller: 'main', action: 'index'``` now)
41
44
  - the underlying way queries are normalized and passed to the server has changed (no external api changes)
42
45
  - changed .find to .where to not conflict with ruby Enum's .find
43
46
  - Volt::TaskHandler is now Volt::Task
44
47
  - Move testing gems to the generated Gemfile for projects
48
+ - ```if ENV['BROWSER']``` is no longer required around integration tests. We now use rspec filtering on ```type: :feature``` if you aren't running with ENV['BROWSER']
45
49
 
46
50
  ### Removed
47
51
  - .false?, .true?, .or, and .and were removed since NilModels were removed. This means you get back a real nil value when accessing an undefined model attribute.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.0.pre3
1
+ 0.9.0.pre4
@@ -1,13 +1,18 @@
1
1
  class UserTasks < Volt::Task
2
2
  # Login a user, takes a login and password. Login can be either a username
3
3
  # or an e-mail based on Volt.config.public.auth.use_username
4
- def login(login, password)
4
+ #
5
+ # login_info is a key with login and password (login may be e-mail)
6
+ def login(login_info)
7
+ login = login_info['login']
8
+ password = login_info['password']
9
+
5
10
  query = { User.login_field => login }
6
11
 
7
12
  # During login we need access to the user's info even though we aren't the user
8
13
  Volt.skip_permissions do
9
14
  store._users.where(query).fetch_first do |user|
10
- fail 'User could not be found' unless user
15
+ fail VoltUserError, 'User could not be found' unless user
11
16
 
12
17
  match_pass = BCrypt::Password.new(user._hashed_password)
13
18
  fail 'Password did not match' unless match_pass == password
data/lib/volt.rb CHANGED
@@ -3,6 +3,7 @@ require 'volt/extra_core/extra_core'
3
3
  require 'volt/reactive/computation'
4
4
  require 'volt/reactive/dependency'
5
5
  require 'volt/utils/modes'
6
+ require 'volt/utils/volt_user_error'
6
7
 
7
8
  require 'volt/config'
8
9
  unless RUBY_PLATFORM == 'opal'
@@ -6,7 +6,9 @@ class Generate < Thor
6
6
  method_option :component, type: :string, default: 'main', banner: 'The component the model should be created in.', required: false
7
7
  def model(name, component = 'main')
8
8
  output_file = Dir.pwd + "/app/#{component.underscore}/models/#{name.underscore.singularize}.rb"
9
+ spec_file = Dir.pwd + "/spec/app/#{component.underscore}/models/#{name.underscore.pluralize}_spec.rb"
9
10
  template('model/model.rb.tt', output_file, model_name: name.camelize.singularize)
11
+ template('model/model_spec.rb.tt', spec_file, model_name: name.camelize.singularize)
10
12
  end
11
13
 
12
14
  desc 'component NAME', 'Creates a component named NAME in the app folder.'
@@ -14,8 +16,10 @@ class Generate < Thor
14
16
  def component(name)
15
17
  name = name.underscore
16
18
  component_folder = Dir.pwd + "/app/#{name}"
19
+ component_spec_folder = Dir.pwd + '/spec/app/' + name
17
20
  @component_name = name
18
21
  directory('component', component_folder, component_name: name)
22
+ directory('component_specs', component_spec_folder)
19
23
  end
20
24
 
21
25
 
@@ -31,7 +35,7 @@ class Generate < Thor
31
35
  require 'volt/cli/new_gem'
32
36
 
33
37
  if name =~ /[-]/
34
- Volt.logger.error("Gem names should use underscores for their names. Currently volt only supports a single namespace for a compoennt.")
38
+ Volt.logger.error("Gem names should use underscores for their names. Currently volt only supports a single namespace for a component.")
35
39
  return
36
40
  end
37
41
 
@@ -46,37 +50,51 @@ class Generate < Thor
46
50
  method_option :name, type: :string, banner: 'The name of the HTTP Controller.'
47
51
  method_option :component, type: :string, default: 'main', banner: 'The component the http_controller should be created in.', required: false
48
52
  def http_controller(name, component = 'main')
49
- output_file = Dir.pwd + "/app/#{component}/controllers/#{name.underscore.singularize}.rb"
50
- template('controller/http_controller.rb.tt', output_file, component_module: component.camelize, http_controller_name: name.camelize.singularize)
53
+ name = name.underscore.pluralize + '_controller' unless name =~ /_controller$/
54
+
55
+ output_file = Dir.pwd + "/app/#{component}/controllers/server/#{name.underscore}.rb"
56
+ spec_file = Dir.pwd + "/spec/app/#{component.underscore}/controllers/server/#{name}_spec.rb"
57
+
58
+ template('controller/http_controller.rb.tt', output_file, component_module: component.camelize, http_controller_name: name.camelize)
59
+ template('controller/http_controller_spec.rb.tt', spec_file, component_module: component.camelize, http_controller_name: name.camelize)
51
60
  end
52
61
 
53
62
  desc 'controller NAME COMPONENT', 'Creates a model controller named NAME in the app folder of the component named COMPONENT.'
54
63
  method_option :name, type: :string, banner: 'The name of the model controller.'
55
64
  method_option :component, type: :string, default: 'main', banner: 'The component the controller should be created in.', required: false
56
65
  def controller(name, component = 'main')
57
- output_file = Dir.pwd + "/app/#{component}/controllers/#{name.underscore.singularize}.rb"
58
- template('controller/model_controller.rb.tt', output_file, component_module: component.camelize, model_controller_name: name.camelize.singularize)
66
+ controller_name = name.underscore.singularize + '_controller' unless name =~ /_controller$/
67
+ output_file = Dir.pwd + "/app/#{component.underscore}/controllers/#{controller_name}.rb"
68
+ spec_file = Dir.pwd + "/spec/app/#{component.underscore}/integration/#{name.underscore.pluralize}_spec.rb"
69
+
70
+ template('controller/model_controller.rb.tt', output_file, component_module: component.camelize, model_controller_name: controller_name.camelize)
71
+ template('controller/model_controller_spec.rb.tt', spec_file, describe: name.underscore.pluralize )
59
72
  end
60
73
 
61
74
  desc 'task NAME COMPONENT', 'Creates a task named NAME in the app folder of the component named COMPONENT.'
62
75
  method_option :name, type: :string, banner: 'The name of the task.'
63
76
  method_option :component, type: :string, default: 'main', banner: 'The component the task should be created in.', required: false
64
77
  def task(name, component = 'main')
65
- output_file = Dir.pwd + "/app/#{component}/tasks/#{name.underscore.singularize}.rb"
78
+ name = name.underscore.singularize
79
+ output_file = Dir.pwd + "/app/#{component}/tasks/#{name}.rb"
80
+ spec_file = Dir.pwd + "/spec/app/#{component}/tasks/#{name}_spec.rb"
66
81
  template('task/task.rb.tt', output_file, task_name: name.camelize.singularize)
82
+ template('task/task_spec.rb.tt', spec_file, task_name: name.camelize.singularize)
67
83
  end
68
84
 
69
85
  desc 'view NAME COMPONENT', 'Creates a view named NAME in the app folder of the component named COMPONENT.'
70
86
  method_option :name, type: :string, banner: 'The name of the view.'
71
87
  method_option :component, type: :string, default: 'main', banner: 'The component the view should be created in.', required: false
72
88
  def view(name, component = 'main')
73
- output_file = Dir.pwd + "/app/#{component}/views/#{component}/#{name.underscore.singularize}.html"
74
- controller(name, component) unless controller?(name, component)
75
- template('view/view.rb.tt', output_file, view_name: name.camelize.singularize)
89
+ name = name.underscore.singularize
90
+ view_folder = Dir.pwd + "/app/#{component}/views/#{name}/"
91
+ directory('view', view_folder, view_name: name, component: component)
92
+ controller(name, component) unless controller_exists?(name, component)
76
93
  end
77
94
 
78
95
  private
79
- def controller?(name, component = 'main')
96
+
97
+ def controller_exists?(name, component = 'main')
80
98
  dir = Dir.pwd + "/app/#{component}/controllers/"
81
99
  File.exists?(dir + name.downcase.underscore.singularize + '.rb')
82
100
  end
@@ -12,7 +12,7 @@ module Volt
12
12
  @response_headers = HttpResponseHeader.new
13
13
  @response_body = []
14
14
  @request = request
15
- @params = params.symbolize_keys.merge(request.params)
15
+ @params = Volt::Model.new(params.symbolize_keys.merge(request.params))
16
16
  end
17
17
 
18
18
  def perform(action)
@@ -27,7 +27,7 @@ else
27
27
  @formatter = Volt::VoltLoggerFormatter.new
28
28
  end
29
29
 
30
- def log_dispatch(class_name, method_name, run_time, args)
30
+ def log_dispatch(class_name, method_name, run_time, args, error)
31
31
  @current = {
32
32
  args: args,
33
33
  class_name: class_name,
@@ -35,7 +35,19 @@ else
35
35
  run_time: run_time
36
36
  }
37
37
 
38
- log(Logger::INFO, task_dispatch_message)
38
+ level = error ? Logger::ERROR : Logger::INFO
39
+ text = TaskLogger.task_dispatch_message(self, args)
40
+
41
+
42
+ if error
43
+ text += "\n" + colorize(error.to_s, :red)
44
+ if error.is_a?(Exception) && !error.is_a?(VoltUserError)
45
+ text += "\n" + colorize(error.backtrace.join("\n"), :red)
46
+ end
47
+ end
48
+
49
+ log(level, text)
50
+
39
51
  end
40
52
 
41
53
  def args
@@ -75,15 +87,6 @@ else
75
87
  string.to_s
76
88
  end
77
89
  end
78
-
79
- def task_dispatch_message
80
- msg = "task #{class_name}##{method_name} in #{run_time}\n"
81
- if args.size > 0
82
- arg_str = args.map {|v| v.inspect }.join(', ')
83
- msg += "with args: #{arg_str}\n"
84
- end
85
- msg
86
- end
87
90
  end
88
91
 
89
92
  class VoltLoggerFormatter < Logger::Formatter
@@ -42,7 +42,13 @@ module Volt
42
42
  end.fail do |err|
43
43
  # TODO: need to make it so we can re-raise out of this promise
44
44
  Volt.logger.error("Error adding listener: #{err.inspect}")
45
- Volt.logger.error(err.backtrace)
45
+ Volt.logger.error(err.backtrace) if err.respond_to?(:backtrace)
46
+
47
+ # If we get back that the user signature is wrong, log the user out.
48
+ if err.to_s.start_with?('user id or hash is incorrectly signed')
49
+ # Delete the invalid cookie
50
+ $page.cookies.delete(:user_id)
51
+ end
46
52
 
47
53
  raise err
48
54
  end
@@ -1,7 +1,7 @@
1
- require 'volt/page/bindings/template_binding'
1
+ require 'volt/page/bindings/view_binding'
2
2
 
3
3
  # Component bindings are the same as template bindings, but handle components.
4
4
  module Volt
5
- class ComponentBinding < TemplateBinding
5
+ class ComponentBinding < ViewBinding
6
6
  end
7
7
  end
@@ -1,11 +1,11 @@
1
1
  require 'volt/page/bindings/base_binding'
2
2
  require 'volt/page/template_renderer'
3
- require 'volt/page/bindings/template_binding/grouped_controllers'
4
- require 'volt/page/bindings/template_binding/view_lookup_for_path'
3
+ require 'volt/page/bindings/view_binding/grouped_controllers'
4
+ require 'volt/page/bindings/view_binding/view_lookup_for_path'
5
5
 
6
6
 
7
7
  module Volt
8
- class TemplateBinding < BaseBinding
8
+ class ViewBinding < BaseBinding
9
9
 
10
10
  # @param [String] binding_in_path is the path this binding was rendered from. Used to
11
11
  # lookup paths in ViewLookupForPath
@@ -9,7 +9,7 @@ require 'volt/page/bindings/attribute_binding'
9
9
  require 'volt/page/bindings/content_binding'
10
10
  require 'volt/page/bindings/each_binding'
11
11
  require 'volt/page/bindings/if_binding'
12
- require 'volt/page/bindings/template_binding'
12
+ require 'volt/page/bindings/view_binding'
13
13
  require 'volt/page/bindings/yield_binding'
14
14
  require 'volt/page/bindings/component_binding'
15
15
  require 'volt/page/bindings/event_binding'
@@ -38,7 +38,10 @@ module Volt
38
38
  else
39
39
  fail "else does not take a conditional, #{content} was provided."
40
40
  end
41
+ when 'view'
42
+ add_template(args)
41
43
  when 'template'
44
+ Volt.logger.warn('Deprecation warning: The template binding has been renamed to view. Please update any views accordingly.')
42
45
  add_template(args)
43
46
  when 'yield'
44
47
  add_yield(args)
@@ -91,7 +94,7 @@ module Volt
91
94
  content = content.strip.gsub(/^\(/, '').gsub(/\)$/, '')
92
95
 
93
96
  @handler.html << "<!-- $#{@binding_number} --><!-- $/#{@binding_number} -->"
94
- save_binding(@binding_number, "lambda { |__p, __t, __c, __id| Volt::TemplateBinding.new(__p, __t, __c, __id, #{@path.inspect}, Proc.new { [#{content}] }) }")
97
+ save_binding(@binding_number, "lambda { |__p, __t, __c, __id| Volt::ViewBinding.new(__p, __t, __c, __id, #{@path.inspect}, Proc.new { [#{content}] }) }")
95
98
 
96
99
  @binding_number += 1
97
100
  end
@@ -62,7 +62,7 @@ module Volt
62
62
  $LOAD_PATH.unshift(app_folder)
63
63
 
64
64
  # Sort so we get consistent load order across platforms
65
- Dir["#{app_folder}/*/{controllers,models,tasks}/*.rb"].each do |ruby_file|
65
+ Dir["#{app_folder}/*/{lib,controllers,models,tasks}/*.rb"].each do |ruby_file|
66
66
  path = ruby_file.gsub(/^#{app_folder}\//, '')[0..-4]
67
67
  require(path)
68
68
  end
@@ -12,11 +12,19 @@ module Volt
12
12
  Volt.boot(app_path)
13
13
 
14
14
  unless RUBY_PLATFORM == 'opal'
15
- require 'volt/spec/capybara'
15
+ begin
16
+ require 'volt/spec/capybara'
16
17
 
17
- setup_capybara(app_path)
18
+ setup_capybara(app_path)
19
+ rescue LoadError => e
20
+ Volt.logger.warn("unable to load capybara, if you wish to use it for tests, be sure it is in the app's Gemfile")
21
+ end
18
22
  end
19
23
 
24
+ unless ENV['BROWSER']
25
+ # Not running integration tests with ENV['BROWSER']
26
+ RSpec.configuration.filter_run_excluding :type => :feature
27
+ end
20
28
 
21
29
  # Setup the spec collection accessors
22
30
  # RSpec.shared_context "volt collections", {} do
@@ -1,4 +1,5 @@
1
1
  # require 'ruby-prof'
2
+ require 'volt/utils/logging/task_logger'
2
3
 
3
4
  module Volt
4
5
  # The task dispatcher is responsible for taking incoming messages
@@ -47,14 +48,20 @@ module Volt
47
48
  # Unsafe method
48
49
  promise.reject(RuntimeError.new("unsafe method: #{method_name}"))
49
50
  end
51
+
52
+ # Called after task runs or fails
53
+ finish = proc do |error|
54
+ run_time = ((Time.now.to_f - start_time) * 1000).round(3)
55
+ Volt.logger.log_dispatch(class_name, method_name, run_time, args, error)
56
+ end
57
+
50
58
  # Run the promise and pass the return value/error back to the client
51
59
  promise.then do |result|
52
60
  channel.send_message('response', callback_id, result, nil)
53
61
 
54
- run_time = ((Time.now.to_f - start_time) * 1000).round(3)
55
- Volt.logger.log_dispatch(class_name, method_name, run_time, args)
62
+ finish.call
56
63
  end.fail do |error|
57
- Volt.logger.error(error)
64
+ finish.call(error)
58
65
  channel.send_message('response', callback_id, nil, error)
59
66
  end
60
67
  end
@@ -0,0 +1,42 @@
1
+ # TaskArgumentFilterer will recursively walk any arguemnts to a task and filter any
2
+ # hashes with a filtered key. By default only :password is filtered, but you can add
3
+ # more with Volt.config.filter_keys
4
+ class TaskArgumentFilterer
5
+ def self.filter(args)
6
+ self.new(args).run
7
+ end
8
+
9
+ def initialize(args)
10
+ # # Cache the filter args
11
+ @@filter_args ||= begin
12
+ # Load, with default, convert to symbols
13
+ arg_names = (Volt.config.filter_keys || [:password]).map(&:to_sym)
14
+ end
15
+
16
+ @args = args
17
+ end
18
+
19
+ def run
20
+ filter_args(@args)
21
+ end
22
+
23
+ private
24
+
25
+ def filter_args(args)
26
+ if args.is_a?(Array)
27
+ args.map {|v| filter_args(v) }
28
+ elsif args.is_a?(Hash)
29
+ args.map do |k,v|
30
+ if @@filter_args.include?(k.to_sym)
31
+ # filter
32
+ [k, '[FILTERED]']
33
+ else
34
+ # retunr unfiltered
35
+ [k, filter_args(v)]
36
+ end
37
+ end.to_h # <= convert back to hash
38
+ else
39
+ return args
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,14 @@
1
+ require 'volt/utils/logging/task_argument_filterer'
2
+
3
+ module Volt
4
+ class TaskLogger
5
+ def self.task_dispatch_message(logger, args)
6
+ msg = "task #{logger.class_name}##{logger.method_name} in #{logger.run_time}\n"
7
+ if args.size > 0
8
+ arg_str = TaskArgumentFilterer.filter(args).map {|v| v.inspect }.join(', ')
9
+ msg += "with args: #{arg_str}\n"
10
+ end
11
+ msg
12
+ end
13
+ end
14
+ end