puffer 0.0.29 → 0.0.30

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.
Files changed (85) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +56 -52
  3. data/README.md +51 -43
  4. data/VERSION +1 -1
  5. data/app/assets/javascripts/puffer/application.js +3 -1
  6. data/app/assets/stylesheets/puffer/application.css +2 -0
  7. data/app/assets/stylesheets/puffer/puffer.css +5 -9
  8. data/app/components/base_component.rb +0 -1
  9. data/app/components/boolean/index.html.erb +1 -1
  10. data/app/components/boolean_component.rb +1 -1
  11. data/app/components/references_many/index.html.erb +1 -0
  12. data/app/components/references_many_component.rb +8 -0
  13. data/app/components/references_one_component.rb +6 -1
  14. data/app/components/select/filter.html.erb +2 -0
  15. data/app/components/select/form.html.erb +1 -1
  16. data/app/components/select_component.rb +13 -2
  17. data/app/controllers/admin/puffer_users_controller.rb +5 -1
  18. data/app/controllers/admin/sessions_controller.rb +4 -1
  19. data/app/controllers/puffer/base.rb +1 -1
  20. data/app/controllers/puffer/sessions_base.rb +3 -0
  21. data/app/controllers/puffer/tree_base.rb +4 -4
  22. data/app/helpers/puffer_helper.rb +16 -15
  23. data/app/models/puffer/puffer_user.rb +11 -10
  24. data/app/models/puffer_user.rb +14 -2
  25. data/app/views/layouts/puffer.html.erb +16 -17
  26. data/app/views/layouts/puffer_base.html.erb +1 -2
  27. data/app/views/layouts/puffer_dashboard.html.erb +2 -2
  28. data/app/views/puffer/base/edit.html.erb +12 -3
  29. data/app/views/puffer/base/new.html.erb +12 -3
  30. data/app/views/puffer/dashboard_base/index.html.erb +5 -5
  31. data/lib/generators/puffer/component/component_generator.rb +0 -1
  32. data/lib/generators/puffer/controller/controller_generator.rb +1 -1
  33. data/lib/generators/puffer/controller/templates/controller.rb +8 -0
  34. data/lib/puffer.rb +77 -13
  35. data/lib/puffer/component.rb +14 -9
  36. data/lib/puffer/controller/auth.rb +41 -2
  37. data/lib/puffer/controller/config.rb +1 -1
  38. data/lib/puffer/controller/mutate.rb +15 -6
  39. data/lib/puffer/extensions/core.rb +4 -0
  40. data/lib/puffer/extensions/directive_processor.rb +36 -0
  41. data/lib/puffer/extensions/form.rb +1 -1
  42. data/lib/puffer/extensions/mapper.rb +74 -149
  43. data/lib/puffer/field.rb +2 -4
  44. data/lib/puffer/field_set.rb +3 -15
  45. data/lib/puffer/filters.rb +105 -0
  46. data/lib/puffer/orm_adapter/active_record.rb +33 -0
  47. data/lib/puffer/orm_adapter/base.rb +4 -0
  48. data/lib/puffer/orm_adapter/mongoid.rb +29 -0
  49. data/lib/puffer/resource.rb +63 -62
  50. data/lib/puffer/resource/node.rb +71 -0
  51. data/lib/puffer/resource/routing.rb +4 -4
  52. data/lib/puffer/resource/tree.rb +36 -0
  53. data/puffer.gemspec +28 -8
  54. data/spec/dummy/app/controllers/admin/posts_controller.rb +1 -1
  55. data/spec/dummy/app/controllers/admin/users_controller.rb +1 -0
  56. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  57. data/spec/dummy/app/controllers/orms/active_record_orm_primals_controller.rb +36 -0
  58. data/spec/dummy/app/controllers/orms/mongoid_orm_primals_controller.rb +42 -0
  59. data/spec/dummy/app/models/active_record_orm.rb +5 -0
  60. data/spec/dummy/app/models/active_record_orm/primal.rb +2 -0
  61. data/spec/dummy/app/models/{mongoid_test.rb → mongoid_orm.rb} +1 -1
  62. data/spec/dummy/app/models/mongoid_orm/primal.rb +46 -0
  63. data/spec/dummy/config/environments/development.rb +3 -0
  64. data/spec/dummy/config/routes.rb +2 -1
  65. data/spec/dummy/db/migrate/20110930183902_create_active_record_orm_primals.rb +17 -0
  66. data/spec/dummy/db/schema.rb +15 -1
  67. data/spec/fabricators/active_record_orm/primal.rb +13 -0
  68. data/spec/fabricators/mongoid_orm/primal.rb +12 -0
  69. data/spec/generators/puffer/component/component_generator_spec.rb +32 -0
  70. data/spec/generators/puffer/controller/controller_generator_spec.rb +31 -0
  71. data/spec/helpers/puffer_helper_spec.rb +62 -0
  72. data/spec/lib/filters_spec.rb +21 -0
  73. data/spec/lib/orm_adapter/active_record_spec.rb +33 -0
  74. data/spec/lib/orm_adapter/base_shared.rb +97 -0
  75. data/spec/lib/orm_adapter/mongoid_spec.rb +46 -0
  76. data/spec/lib/resource/routing_spec.rb +5 -5
  77. data/spec/lib/resource/tree_spec.rb +31 -0
  78. data/spec/lib/resource_spec.rb +36 -37
  79. data/spec/spec_helper.rb +3 -2
  80. metadata +71 -43
  81. data/app/views/puffer/base/_form.html.erb +0 -11
  82. data/lib/generators/puffer/component/templates/component_spec.rb +0 -19
  83. data/lib/puffer/resource/scoping.rb +0 -19
  84. data/spec/dummy/app/controllers/orms/mongoid_tests_controller.rb +0 -19
  85. data/spec/lib/params_spec.rb +0 -120
@@ -56,8 +56,8 @@ module Puffer
56
56
 
57
57
  helper ComponentHelper, PufferHelper
58
58
 
59
- attr_accessor :parent_controller, :field, :opts, :identifer
60
- delegate :env, :request, :params, :session, :resource, :_members, :_collections, :to => :parent_controller
59
+ attr_accessor :parent_controller, :field, :opts, :identifer, :resource
60
+ delegate :env, :request, :params, :session, :_members, :_collections, :to => :parent_controller
61
61
  helper_method :params, :session, :resource, :_members, :_collections, :parent_controller, :field, :opts, :identifer, :component_id, :event_url, :event_path, :record, :records
62
62
 
63
63
  def initialize field
@@ -67,12 +67,17 @@ module Puffer
67
67
 
68
68
  def process parent_controller, context, *args
69
69
  @parent_controller = parent_controller
70
- @identifer = params[:identifer] || generate_identifer
71
70
  super context, *args
72
71
  end
73
72
 
74
73
  def send_action method_name, *args
75
74
  @opts = args.extract_options!
75
+ if @opts[:record]
76
+ @resource = Puffer::Resource.new(params.merge(:member => @opts[:record]), parent_controller)
77
+ else
78
+ @resource = parent_controller.resource
79
+ end
80
+ @identifer = params[:identifer] || generate_identifer
76
81
  send method_name, *args
77
82
  end
78
83
 
@@ -104,27 +109,27 @@ module Puffer
104
109
  end
105
110
 
106
111
  def event_url name, options = {}
107
- resource.collection_url :event, (options || {}).merge(event_options(name))
112
+ resource.collection_url (options || {}).merge(event_options(name))
108
113
  end
109
114
 
110
115
  def event_path name, options = {}
111
- resource.collection_path :event, (options || {}).merge(event_options(name))
116
+ resource.collection_path (options || {}).merge(event_options(name))
112
117
  end
113
118
 
114
119
  def event_options name
115
- {:event => name, :field => field.to_s, :fieldset => field.field_set.name, :identifer => identifer}
120
+ {:action => :event, :event => name, :field => field.to_s, :fieldset => field.field_set.name, :identifer => identifer}
116
121
  end
117
122
 
118
123
  def record
119
- @record || instance_variable_get("@#{resource.model_name}")
124
+ @record || instance_variable_get("@#{resource.name.singularize}")
120
125
  end
121
126
 
122
127
  def records
123
- @records || instance_variable_get("@#{resource.model_name.pluralize}")
128
+ @records || instance_variable_get("@#{resource.name.pluralize}")
124
129
  end
125
130
 
126
131
  def component_id
127
- @component_id ||= "component_#{identifer}"
132
+ "component_#{identifer}"
128
133
  end
129
134
 
130
135
  private
@@ -1,5 +1,15 @@
1
1
  module Puffer
2
2
  module Controller
3
+ # Module provides authentification methods and helpers for puffer
4
+ # controllers. Puffer's authentification system is simple. In general, you
5
+ # should use different kinds of routing and controllers namespaces for
6
+ # partial access of different user types.
7
+ #
8
+ # Method +has_puffer_access?+ with current namespace name as a parameter.
9
+ # If you want to use appication's own auth system - just redefine this
10
+ # method in your ApplicationController.
11
+ #
12
+ # Also see Puffer::SessionsBase.
3
13
  module Auth
4
14
  extend ActiveSupport::Concern
5
15
 
@@ -9,17 +19,46 @@ module Puffer
9
19
 
10
20
  module InstanceMethods
11
21
 
22
+ # Return current user instance, used for authorization. This method can
23
+ # be redefined in ApplicationController if you want to use application's
24
+ # auth system.
25
+ #
26
+ # ex:
27
+ #
28
+ # class ApplicationController < ActionController::Base
29
+ # def current_puffer_user
30
+ # current_user
31
+ # end
32
+ # end
33
+ #
34
+ # In this case returner user model instance should respond to has_role?
35
+ # method, or you should properly redefine +has_puffer_access?+ See
36
+ # +has_puffer_access?+ source and docs.
12
37
  def current_puffer_user
13
- @current_puffer_user ||= super rescue PufferUser.find(session[:puffer_user_id]) if session[:puffer_user_id]
38
+ @current_puffer_user ||= super rescue (PufferUser.find(session[:puffer_user_id]) if session[:puffer_user_id])
14
39
  end
15
40
 
41
+ # Used in before_filter to prevent unauthorized access
16
42
  def require_puffer_user
17
- unless has_puffer_access?(namespace)
43
+ unless has_puffer_access?(puffer_namespace)
18
44
  redirect_to new_admin_session_url(:return_to => request.fullpath)
19
45
  return false
20
46
  end
21
47
  end
22
48
 
49
+ # This method is also part of auth system and it can be redefined at the
50
+ # ApplicationController.
51
+ #
52
+ # ex:
53
+ #
54
+ # class ApplicationController < ActionController::Base
55
+ # # <tt>current_puffer_user.admin?</tt>
56
+ # # <tt>current_puffer_user.manager?</tt>
57
+ # # <tt>current_puffer_user.seo?</tt>
58
+ # def has_puffer_access? namespace
59
+ # current_puffer_user.send("#{namespace}?")
60
+ # end
61
+ # end
23
62
  def has_puffer_access? namespace
24
63
  super rescue (current_puffer_user && current_puffer_user.has_role?(namespace))
25
64
  end
@@ -4,7 +4,7 @@ module Puffer
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  included do
7
- puffer_class_attribute :group
7
+ puffer_class_attribute :group, :default
8
8
  puffer_class_attribute :model_name
9
9
  puffer_class_attribute :destroy, true
10
10
 
@@ -6,14 +6,23 @@ module Puffer
6
6
  included do
7
7
  layout 'puffer'
8
8
  helper :puffer
9
- delegate :model, :model_name, :to => 'self.class'
10
- helper_method :namespace, :resource, :record, :records
9
+ delegate :puffer_filters_class, :model, :model_name, :to => 'self.class'
10
+ helper_method :puffer_filters, :puffer_namespace, :resource, :record, :records
11
11
  end
12
12
 
13
13
  module InstanceMethods
14
14
 
15
- def namespace
16
- params[:namespace] || self.class.namespace
15
+ def process_action method_name, *args
16
+ params[:puffer] = Rails.application.routes.resources_tree[params[:puffer]] if params[:puffer]
17
+ super
18
+ end
19
+
20
+ def puffer_filters
21
+ @puffer_filters ||= puffer_filters_class.new params[puffer_filters_class.model_name.param_key]
22
+ end
23
+
24
+ def puffer_namespace
25
+ resource.scope
17
26
  end
18
27
 
19
28
  def resource
@@ -36,8 +45,8 @@ module Puffer
36
45
  true
37
46
  end
38
47
 
39
- def namespace
40
- to_s.underscore.split('/').first
48
+ def puffer_filters_class
49
+ @puffer_filters_class ||= Puffer::Filters.controller_filters(self)
41
50
  end
42
51
 
43
52
  def model_name
@@ -28,6 +28,10 @@ module Puffer
28
28
  end
29
29
 
30
30
  module Array
31
+ def to_fieldset
32
+ Puffer::FieldSet.new.concat self
33
+ end
34
+
31
35
  def to_includes
32
36
  map do |field|
33
37
  sections = field.split('.').map(&:to_sym)
@@ -0,0 +1,36 @@
1
+ require 'sprockets'
2
+
3
+ module Puffer
4
+ module Extensions
5
+ module DirectiveProcessor
6
+ extend ActiveSupport::Concern
7
+
8
+ module InstanceMethods
9
+
10
+ def process_require_all_directive(path)
11
+ raise ArgumentError, "require_all argument must be relative" unless relative?(path)
12
+
13
+ context.environment.paths.each do |root_path|
14
+ root = Pathname.new(root_path).join(path).expand_path
15
+
16
+ if root.exist? && root.directory?
17
+ context.depend_on(root)
18
+
19
+ Dir["#{root}/*"].sort.each do |filename|
20
+ if filename == self.file
21
+ next
22
+ elsif context.asset_requirable?(filename)
23
+ context.require_asset(filename)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+
36
+ Sprockets::DirectiveProcessor.send :include, Puffer::Extensions::DirectiveProcessor
@@ -6,7 +6,7 @@ module Puffer
6
6
  field = args.first.is_a?(Puffer::Field) ? args.first : Puffer::Field.new(*args)
7
7
  field.resource = object.class
8
8
  template = instance_variable_get :@template
9
- field.render template.controller, :form, :form => self
9
+ field.render template.controller, :form, :form => self, :record => object
10
10
  end
11
11
 
12
12
  end
@@ -1,189 +1,114 @@
1
1
  module Puffer
2
2
  module Extensions
3
+ # Extends rails mapper to provide resources nesting tree structure with
4
+ # request params. Route defaults contains <tt>:puffer</tt> key with node
5
+ # index in resources tree nodes array. See <tt>Puffer::Resource::Tree</tt>
6
+ #
7
+ # Resource tree depends on routes resources nesting.
8
+ #
9
+ # ex:
10
+ #
11
+ # namespace :admin do
12
+ # resources :users do
13
+ # resource :profile
14
+ # resources :articles
15
+ # end
16
+ # resources :orders
17
+ # end
18
+ #
19
+ # will produce:
20
+ #
21
+ # [
22
+ # {:scope => 'admin', :current => :users, :children => [:profile, :articles], :ancestors => []},
23
+ # {:scope => 'admin', :current => :profile, :children => [], :ancestors => [:users]},
24
+ # {:scope => 'admin', :current => :articles, :children => [], :ancestors => [:users]},
25
+ # {:scope => 'admin', :current => :orders, :children => [], :ancestors => []},
26
+ # ]
27
+ #
28
+ # a complete tree structure with nodes array to acces with node index
29
+ # (<tt>Puffer::Resource::Tree#to_struct</tt>).
30
+ #
31
+ # Also this mapper extension adds come aaditional routes for every pufer
32
+ # controller and namespace.
3
33
  module Mapper
4
34
  extend ActiveSupport::Concern
5
35
 
6
36
  included do
7
- alias_method_chain :resource, :puffer
8
- alias_method_chain :resources, :puffer
37
+ alias_method_chain :namespace, :puffer
38
+ alias_method_chain :resource_scope, :puffer
9
39
  end
10
40
 
11
41
  module InstanceMethods
12
42
 
13
- def resource_with_puffer *resources, &block
14
- puffer_resource(*Marshal.load(Marshal.dump(resources)), &block) || resource_without_puffer(*resources, &block)
15
- end
16
-
17
- def resources_with_puffer *resources, &block
18
- puffer_resources(*Marshal.load(Marshal.dump(resources)), &block) || resources_without_puffer(*resources, &block)
19
- end
20
-
21
- def puffer_controller controller
22
- if controller.configuration.group
23
- puffer = ::Rails.application.routes.puffer
24
- namespace = @scope[:module]
25
-
26
- unless puffer[namespace]
27
- @scope[:module] = 'admin'
28
- root :to => 'dashboard#index', :namespace => namespace
29
- @scope[:module] = namespace
30
- end
31
-
32
- puffer[namespace] ||= ActiveSupport::OrderedHash.new
33
- puffer[namespace][controller.configuration.group] ||= []
34
- puffer[namespace][controller.configuration.group] << controller
35
- end
36
- end
37
-
38
- def puffer_resource(*resources, &block)
39
- options = resources.extract_options!
40
-
41
- if apply_common_behavior_for(:resource, resources, options, &block)
42
- return self
43
- end
44
-
45
- resource = ActionDispatch::Routing::Mapper::Resources::SingletonResource.new(resources.pop, options)
46
- controller = "#{[@scope[:module], resource.controller].compact.join("/")}_controller".camelize.constantize rescue nil
43
+ def namespace_with_puffer path, options = {}
44
+ defaults :puffer_scope => path.to_sym do
45
+ namespace_without_puffer path, options do
46
+ yield
47
47
 
48
- return if controller.nil? || (controller && !controller.puffer?)
49
-
50
- @scope[:ancestors] ||= []
51
- @scope[:children] ||= []
52
-
53
- puffer_controller controller if @scope[:ancestors] == []
54
-
55
- resource_scope(resource) do
56
- siblings = @scope[:children].dup
57
- @scope[:children] = []
58
- @scope[:ancestors].push resource.singular.to_sym
59
-
60
- yield if block_given?
61
-
62
- @scope[:ancestors].pop
63
- options = {:plural => false, :ancestors => @scope[:ancestors].dup, :children => @scope[:children].dup}
64
- siblings.push resource.singular.to_sym
65
- @scope[:children] = siblings
66
-
67
- collection do
68
- get '/event/:fieldset/:field/:event(/:identifer)', options.merge(:action => :event, :as => :event)
69
- post :create, options
70
- controller._collections.each do |action|
71
- opts = action.route.extract_options!.dup
72
- action.route.push options.reverse_merge(opts)
73
- send *action.route
48
+ if ::Rails.application.routes.resources_tree.any? {|node| node.scope == @scope[:module].to_sym}
49
+ old, @scope[:module] = @scope[:module], 'admin'
50
+ root :to => 'dashboard#index'
51
+ @scope[:module] = old
74
52
  end
75
53
  end
76
-
77
- new do
78
- get :new, options
79
- end
80
-
81
- member do
82
- get :edit, options
83
- get :show, options
84
- put :update, options
85
- delete :destroy, options
86
- controller._members.each do |action|
87
- opts = action.route.extract_options!.dup
88
- action.route.push options.reverse_merge(opts)
89
- send *action.route
90
- end
91
- end
92
-
93
54
  end
94
-
95
- self
96
55
  end
97
56
 
98
- def puffer_resources(*resources, &block)
99
- options = resources.extract_options!
100
-
101
- if apply_common_behavior_for(:resources, resources, options, &block)
102
- return self
103
- end
104
-
105
- resource = ActionDispatch::Routing::Mapper::Resources::Resource.new(resources.pop, options)
106
- controller = "#{[@scope[:module], resource.controller].compact.join("/")}_controller".camelize.constantize rescue nil
107
-
108
- return if controller.nil? || (controller && !controller.puffer?)
109
-
110
- @scope[:ancestors] ||= []
111
- @scope[:children] ||= []
112
-
113
- puffer_controller controller if @scope[:ancestors] == []
114
-
115
- resource_scope(resource) do
116
- siblings = @scope[:children].dup
117
- @scope[:children] = []
118
- @scope[:ancestors].push resource.plural.to_sym
119
-
120
- yield if block_given?
121
-
122
- @scope[:ancestors].pop
123
- options = {:plural => true, :ancestors => @scope[:ancestors].dup, :children => @scope[:children].dup}
124
- siblings.push resource.plural.to_sym
125
- @scope[:children] = siblings
126
-
127
-
128
- collection do
129
- get :index, options
130
- get '/event/:fieldset/:field/:event(/:identifer)', options.merge(:action => :event, :as => :event)
131
- post :create, options
132
- controller._collections.each do |action|
133
- opts = action.route.extract_options!.dup
134
- action.route.push options.reverse_merge(opts)
135
- send *action.route
136
- end
137
- end
138
-
139
- new do
140
- get :new, options
141
- end
142
-
143
- member do
144
- get :edit, options
145
- get :show, options
146
- put :update, options
147
- delete :destroy, options
148
- controller._members.each do |action|
149
- opts = action.route.extract_options!.dup
150
- action.route.push options.reverse_merge(opts)
151
- send *action.route
57
+ def resource_scope_with_puffer resource, &block
58
+ controller = "#{[@scope[:module], resource.controller].compact.join("/")}_controller".camelize.constantize# rescue nil
59
+ if controller && controller.puffer?
60
+ singular = resource.is_a? ActionDispatch::Routing::Mapper::Resources::SingletonResource
61
+ name = (singular ? resource.singular : resource.plural).to_sym
62
+
63
+ resource_node = ::Rails.application.routes.resources_tree.append_node swallow_nil{@scope[:defaults][:puffer]},
64
+ :name => name, :scope => @scope[:module].to_sym, :controller => controller, :singular => singular
65
+
66
+ defaults :puffer => resource_node do
67
+ resource_scope_without_puffer resource do
68
+ block.call if block
69
+
70
+ member do
71
+ controller._members.each do |action|
72
+ send *action.route
73
+ end
74
+ end
75
+
76
+ collection do
77
+ controller._collections.each do |action|
78
+ send *action.route
79
+ end
80
+ get '/event/:fieldset/:field/:event(/:identifer)', :action => :event, :as => :event
81
+ end
152
82
  end
153
83
  end
84
+ else
85
+ resource_scope_without_puffer resource, &block
154
86
  end
155
-
156
- self
157
87
  end
158
88
 
159
89
  end
160
-
161
90
  end
162
91
 
163
92
  module RouteSet
93
+ extend ActiveSupport::Concern
164
94
 
165
- def self.included base
166
- base.class_eval do
167
- include InstanceMethods
168
-
169
- alias_method_chain :clear!, :puffer
170
- attr_writer :puffer
95
+ included do
96
+ alias_method_chain :clear!, :puffer
97
+ attr_writer :resources_tree
171
98
 
172
- def puffer
173
- @puffer ||= ActiveSupport::OrderedHash.new
174
- end
99
+ def resources_tree
100
+ @resources_tree ||= Puffer::Resource::Tree.new
175
101
  end
176
102
  end
177
103
 
178
104
  module InstanceMethods
179
105
 
180
106
  def clear_with_puffer!
181
- self.puffer = ActiveSupport::OrderedHash.new
107
+ @resources_tree = nil
182
108
  clear_without_puffer!
183
109
  end
184
110
 
185
111
  end
186
-
187
112
  end
188
113
 
189
114
  end