puffer 0.0.29 → 0.0.30

Sign up to get free protection for your applications and to get access to all the features.
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