cm-admin 0.7.2 → 0.7.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72119a5aae30fb36067825d4ed89fc085907b1a31a7b79e18dd30690b8379991
4
- data.tar.gz: 917b3dc2d4d59d4099c77e169694579f1d82c5dc53664025fb98edbd9ccc3ff3
3
+ metadata.gz: 8603d897651307b80517b9918c60ab3d2d62abdc2931af5ea7d8def1453b4865
4
+ data.tar.gz: 0afafa900d9c51bee526e9781df8dd41baf1603cf768bb8db3e1d8353fc4adc0
5
5
  SHA512:
6
- metadata.gz: 42bbbf83a0d81aa5d193cb23a3469ed3392f13fe573605a55886611805c2e388e3a3664c2be6202eea743f13658cd6faf7870a2ba786339620d87484b823ccab
7
- data.tar.gz: e6474599f0f7de99642a056713baf93f9f7dcb6352d2385fc080059d310fa22b4b7199c28dff7b9a36be9d025aacf0fa395206e225e4ec26843befa2a640a3d3
6
+ metadata.gz: '02398dcf148b0d90bd6de2dfd2fdeae4fd4d3353d75c33433a75518da87c6d6c739349279f9f6f3a4632256c37e463009838e9ec21821d224728730a8656b87b'
7
+ data.tar.gz: 2f390a32636c40fdeb3afc5128ad824135565450d0b833aafc9ac828d8d4178d5dda2316e01f654a45266514a4a31e0b22985c41d3e1b10cf049ee56b6cf663c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cm-admin (0.5.7)
4
+ cm-admin (0.7.5)
5
5
  axlsx_rails (~> 0.6.1)
6
6
  cocoon (~> 1.2.15)
7
7
  pagy (~> 4.11.0)
@@ -47,29 +47,27 @@ GEM
47
47
  htmlentities (4.3.4)
48
48
  i18n (1.10.0)
49
49
  concurrent-ruby (~> 1.0)
50
- loofah (2.15.0)
50
+ loofah (2.18.0)
51
51
  crass (~> 1.0.2)
52
52
  nokogiri (>= 1.5.9)
53
53
  marcel (1.0.2)
54
54
  method_source (1.0.0)
55
- mini_portile2 (2.8.0)
56
55
  minitest (5.15.0)
57
- nokogiri (1.13.4)
58
- mini_portile2 (~> 2.8.0)
56
+ nokogiri (1.13.6-arm64-darwin)
59
57
  racc (~> 1.4)
60
58
  pagy (4.11.0)
61
59
  pundit (2.2.0)
62
60
  activesupport (>= 3.0.0)
63
61
  racc (1.6.0)
64
- rack (2.2.3)
62
+ rack (2.2.4)
65
63
  rack-proxy (0.7.2)
66
64
  rack
67
- rack-test (1.1.0)
68
- rack (>= 1.0, < 3)
65
+ rack-test (2.0.2)
66
+ rack (>= 1.3)
69
67
  rails-dom-testing (2.0.3)
70
68
  activesupport (>= 4.2.0)
71
69
  nokogiri (>= 1.6)
72
- rails-html-sanitizer (1.4.2)
70
+ rails-html-sanitizer (1.4.3)
73
71
  loofah (~> 2.3)
74
72
  railties (7.0.2.3)
75
73
  actionpack (= 7.0.2.3)
@@ -107,7 +105,7 @@ GEM
107
105
  rack-proxy (>= 0.6.1)
108
106
  railties (>= 5.2)
109
107
  semantic_range (>= 2.3.0)
110
- zeitwerk (2.5.4)
108
+ zeitwerk (2.6.0)
111
109
 
112
110
  PLATFORMS
113
111
  ruby
data/README.md CHANGED
@@ -30,7 +30,7 @@ You can find more detailed documentation [here](https://github.com/commutatus/cm
30
30
 
31
31
  ## Demo
32
32
 
33
- For demo check [here](http://cm-admin.labs.commutatus.com/admin/users/)
33
+ For demo check [here](http://cm-admin.labs.commutatus.com)
34
34
  For demo repo check [here](https://github.com/commutatus/cm-admin-panel-demo)
35
35
 
36
36
  ## Development
@@ -1,6 +1,7 @@
1
1
  module CmAdmin
2
2
  class ApplicationController < ::ActionController::Base
3
3
  include Pundit::Authorization
4
+ include Pagy::Backend
4
5
  # before_action :check_cm_admin
5
6
  layout 'cm_admin'
6
7
  helper CmAdmin::ViewHelpers
@@ -0,0 +1,192 @@
1
+ module CmAdmin
2
+ class ResourceController < ApplicationController
3
+ include Pundit::Authorization
4
+ include Pagy::Backend
5
+
6
+ def cm_index(params)
7
+ @current_action = CmAdmin::Models::Action.find_by(@model, name: 'index')
8
+ # Based on the params the filter and pagination object to be set
9
+ @ar_object = filter_by(params, nil, @model.filter_params(params))
10
+ # resource_identifier
11
+ respond_to do |format|
12
+ if request.xhr?
13
+ format.html { render partial: '/cm_admin/main/table' }
14
+ else
15
+ format.html { render '/cm_admin/main/' + action_name }
16
+ end
17
+ end
18
+ end
19
+
20
+ def cm_show(params)
21
+ @current_action = CmAdmin::Models::Action.find_by(@model, name: 'show')
22
+ scoped_model = "CmAdmin::#{@model.name}Policy::Scope".constantize.new(Current.user, @model.name.constantize).resolve
23
+ @ar_object = scoped_model.find(params[:id])
24
+ resource_identifier
25
+ respond_to do |format|
26
+ format.html { render '/cm_admin/main/' + action_name }
27
+ end
28
+ end
29
+
30
+ def cm_new(params)
31
+ @current_action = CmAdmin::Models::Action.find_by(@model, name: 'new')
32
+ @ar_object = @model.ar_model.new
33
+ resource_identifier
34
+ respond_to do |format|
35
+ format.html { render '/cm_admin/main/' + action_name }
36
+ end
37
+ end
38
+
39
+ def cm_edit(params)
40
+ @current_action = CmAdmin::Models::Action.find_by(@model, name: 'edit')
41
+ @ar_object = @model.ar_model.name.classify.constantize.find(params[:id])
42
+ resource_identifier
43
+ respond_to do |format|
44
+ format.html { render '/cm_admin/main/' + action_name }
45
+ end
46
+ end
47
+
48
+ def cm_update(params)
49
+ @ar_object = @model.ar_model.name.classify.constantize.find(params[:id])
50
+ @ar_object.assign_attributes(resource_params(params))
51
+ resource_identifier
52
+ resource_responder
53
+ end
54
+
55
+ def cm_create(params)
56
+ @ar_object = @model.ar_model.name.classify.constantize.new(resource_params(params))
57
+ resource_identifier
58
+ resource_responder
59
+ end
60
+
61
+ def cm_destroy(params)
62
+ @ar_object = @model.ar_model.name.classify.constantize.find(params[:id])
63
+ respond_to do |format|
64
+ if @ar_object.destroy
65
+ format.html { redirect_back fallback_location: cm_admin.send("#{@model.name.underscore}_index_path"), notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is successful" }
66
+ else
67
+ format.html { redirect_back fallback_location: cm_admin.send("#{@model.name.underscore}_index_path"), notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is unsuccessful" }
68
+ end
69
+ end
70
+ end
71
+
72
+ def cm_custom_method(params)
73
+ scoped_model = "CmAdmin::#{@model.name}Policy::Scope".constantize.new(Current.user, @model.name.constantize).resolve
74
+ resource_identifier
75
+ respond_to do |format|
76
+ if @action.action_type == :custom
77
+ if @action.child_records
78
+ format.html { render @action.layout }
79
+ elsif @action.display_type == :page
80
+ data = @action.parent == "index" ? @ar_object.data : @ar_object
81
+ format.html { render @action.partial }
82
+ else
83
+ ar_object = @action.code_block.call(@ar_object)
84
+ if ar_object.errors.empty?
85
+ redirect_url = @model.current_action.redirection_url || @action.redirection_url || request.referrer || "/cm_admin/#{@model.ar_model.table_name}/#{@ar_object.id}"
86
+ format.html { redirect_to redirect_url, notice: "#{@action.name.titleize} is successful" }
87
+ else
88
+ error_messages = ar_object.errors.full_messages.map{|error_message| "<li>#{error_message}</li>"}.join
89
+ format.html { redirect_to request.referrer, alert: "<b>#{@action.name.titleize} is unsuccessful</b><br /><ul>#{error_messages}</ul>" }
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ def resource_identifier
97
+ @ar_object, @associated_model, @associated_ar_object = custom_controller_action(action_name, params.permit!) if !@ar_object.present? && params[:id].present?
98
+ authorize controller_name.classify.constantize, policy_class: "CmAdmin::#{controller_name.classify}Policy".constantize if defined? "CmAdmin::#{controller_name.classify}Policy".constantize
99
+ aar_model = request.url.split('/')[-2].classify.constantize if params[:aar_id]
100
+ @associated_ar_object = aar_model.find(params[:aar_id]) if params[:aar_id]
101
+ nested_tables = @model.available_fields[:new].except(:fields).keys
102
+ nested_tables += @model.available_fields[:edit].except(:fields).keys
103
+ @reflections = @model.ar_model.reflect_on_all_associations
104
+ nested_tables.each do |table_name|
105
+ reflection = @reflections.select {|x| x if x.name == table_name}.first
106
+ if reflection.macro == :has_many
107
+ @ar_object.send(table_name).build if action_name == "new" || action_name == "edit"
108
+ elsif action_name == "new"
109
+ @ar_object.send(('build_' + table_name.to_s).to_sym)
110
+ end
111
+ end
112
+ end
113
+
114
+ def resource_responder
115
+ respond_to do |format|
116
+ if params["referrer"]
117
+ redirect_url = params["referrer"]
118
+ else
119
+ redirect_url = CmAdmin::Engine.mount_path + "/#{@model.name.underscore.pluralize}/#{@ar_object.id}"
120
+ end
121
+ if @ar_object.save
122
+ format.html { redirect_to redirect_url, notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is successful" }
123
+ else
124
+ format.html { render '/cm_admin/main/new', notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is unsuccessful" }
125
+ end
126
+ end
127
+ end
128
+
129
+ def custom_controller_action(action_name, params)
130
+ current_action = CmAdmin::Models::Action.find_by(@model, name: action_name.to_s)
131
+ if current_action
132
+ @current_action = current_action
133
+ @ar_object = @model.ar_model.name.classify.constantize.find(params[:id])
134
+ if @current_action.child_records
135
+ child_records = @ar_object.send(@current_action.child_records)
136
+ @associated_model = CmAdmin::Model.find_by(name: @model.ar_model.reflect_on_association(@current_action.child_records).klass.name)
137
+ if child_records.is_a? ActiveRecord::Relation
138
+ @associated_ar_object = filter_by(params, child_records)
139
+ else
140
+ @associated_ar_object = child_records
141
+ end
142
+ return @ar_object, @associated_model, @associated_ar_object
143
+ end
144
+ return @ar_object
145
+ end
146
+ end
147
+
148
+ def filter_by(params, records, filter_params={}, sort_params={})
149
+ filtered_result = OpenStruct.new
150
+ sort_column = "created_at"
151
+ sort_direction = %w[asc desc].include?(sort_params[:sort_direction]) ? sort_params[:sort_direction] : "asc"
152
+ sort_params = {sort_column: sort_column, sort_direction: sort_direction}
153
+
154
+ records = "CmAdmin::#{@model.name}Policy::Scope".constantize.new(Current.user, @model.name.constantize).resolve if records.nil?
155
+ records = records.order("#{@current_action.sort_column} #{@current_action.sort_direction}")
156
+
157
+ final_data = CmAdmin::Models::Filter.filtered_data(filter_params, records, @model.filters)
158
+ pagy, records = pagy(final_data)
159
+ filtered_result.data = records
160
+ filtered_result.pagy = pagy
161
+ # filtered_result.facets = paginate(page, raw_data.size)
162
+ # filtered_result.sort = sort_params
163
+ # filtered_result.facets.sort = sort_params
164
+ return filtered_result
165
+ end
166
+
167
+ def resource_params(params)
168
+ permittable_fields = @permitted_fields || @model.ar_model.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym)
169
+ permittable_fields += @model.ar_model.name.constantize.reflect_on_all_associations.map {|x|
170
+ next if x.options[:polymorphic]
171
+ if x.class.name.include?('HasOne')
172
+ x.name.to_s.gsub('_attachment', '').gsub('rich_text_', '').to_sym
173
+ elsif x.class.name.include?('HasMany')
174
+ Hash[x.name.to_s.gsub('_attachment', ''), []]
175
+ end
176
+ }.compact
177
+ nested_tables = @model.available_fields[:new].except(:fields).keys
178
+ nested_tables += @model.available_fields[:edit].except(:fields).keys
179
+ nested_fields = nested_tables.uniq.map {|table|
180
+ Hash[
181
+ table.to_s + '_attributes',
182
+ table.to_s.classify.constantize.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym) + [:id, :_destroy]
183
+ ]
184
+ }
185
+ permittable_fields += nested_fields
186
+ @model.ar_model.columns.map { |col| permittable_fields << col.name.split('_cents') if col.name.include?('_cents') }
187
+
188
+ params.require(@model.name.underscore.to_sym).permit(*permittable_fields)
189
+ end
190
+
191
+ end
192
+ end
@@ -13,5 +13,16 @@ module CmAdmin
13
13
  return true unless policy([:cm_admin, model_name.classify.constantize]).methods.include?(:"#{action_name}?")
14
14
  policy([:cm_admin, model_name.classify.constantize]).send(:"#{action_name}?")
15
15
  end
16
+
17
+ def action(action_name)
18
+ case action_name.to_sym
19
+ when :update
20
+ return :edit
21
+ when :create
22
+ return :new
23
+ else
24
+ return action_name.to_sym
25
+ end
26
+ end
16
27
  end
17
28
  end
@@ -2,6 +2,11 @@
2
2
  .table-top
3
3
  p.table-top__total-count = "#{@associated_ar_object.pagy.count} #{@action.child_records.to_s.gsub('_', ' ')} found"
4
4
  .table-top__column-action
5
+ - if @associated_model && @associated_model.available_actions.map(&:name).include?('new')
6
+ - association = @ar_object.class.reflect_on_all_associations.select{|x| x.name == @associated_model.name.tableize.to_sym }.first
7
+ - polymorphic_name = (association && association.inverse_of && association.inverse_of.options[:polymorphic]) ? association.inverse_of.name : ''
8
+ a href="#{CmAdmin::Engine.mount_path}/#{@associated_model.name.tableize}/new?associated_id=#{@ar_object.id}&associated_class=#{@ar_object.class.name.underscore}&polymorphic_name=#{polymorphic_name}&referrer=#{request.path}"
9
+ button.secondary-btn.column-btn Add
5
10
  / button.secondary-btn.column-btn data-target="#columnActionModal" data-toggle="modal" type="button"
6
11
  / span
7
12
  / i.fa.fa-columns.bolder
@@ -17,7 +22,7 @@
17
22
  / span
18
23
  / input.cm-checkbox type="checkbox"
19
24
  - @model.available_fields[@action.name.to_sym].each do |column|
20
- th = column.header
25
+ th = column.header
21
26
  tbody.cm-table__body
22
27
  - @associated_ar_object.data.each do |ar_object|
23
28
  tr.body-row
@@ -25,9 +30,12 @@
25
30
  / td.check-box-space
26
31
  / span
27
32
  / input.cm-checkbox type="checkbox"
28
- - @model.available_fields[@action.name.to_sym].each do |column|
33
+ - @model.available_fields[@action.name.to_sym].each_with_index do |column, index|
29
34
  td class="text-ellipsis"
30
- span class="#{column.cm_css_class}" = show_field_value(ar_object, column)
35
+ - if index == 0 && @associated_model && @associated_model.available_actions.map(&:name).include?('show')
36
+ a href="#{CmAdmin::Engine.mount_path}/#{@associated_model.name.tableize}/#{ar_object.id}" = show_field_value(ar_object, column)
37
+ - else
38
+ span class="#{column.cm_css_class}" = show_field_value(ar_object, column)
31
39
  - associated_model_actions = @associated_model && @associated_model.available_actions.select{|act| act if act.route_type == 'member'}
32
40
  - if associated_model_actions.present?
33
41
  td.row-action-cell
@@ -1,5 +1,5 @@
1
1
  .nested-fields
2
- - @model.available_fields[action_name.to_sym][assoc_name].each do |field|
2
+ - @model.available_fields[ action(action_name) ][assoc_name].each do |field|
3
3
  .row
4
4
  .col-sm-10
5
5
  = input_field_for_column(f, field)
@@ -34,8 +34,9 @@
34
34
  = render partial: column.drawer_partial, locals: { ar_object: ar_object}
35
35
 
36
36
  - edit_action = @model.available_actions.select{|act| act if act.action_type.eql?(:default) && act.name.eql?('edit')}
37
+ - destroy_action = @model.available_actions.select{|act| act if act.action_type.eql?(:default) && act.name.eql?('destroy')}
37
38
  - custom_actions = @model.available_actions.select{|act| act if act.route_type == 'member' && [:button, :modal].include?(act.display_type)}
38
- - if custom_actions.any? || edit_action.any?
39
+ - if custom_actions.any? || edit_action.any? || destroy_action.any?
39
40
  td.row-action-cell
40
41
  .row-action-tool
41
42
  button.secondary-btn.tool-btn type="button"
@@ -50,6 +51,12 @@
50
51
  span
51
52
  i.fa.fa-edit
52
53
  | Edit
54
+ - if destroy_action.any? && policy([:cm_admin, @model.name.classify.constantize]).destroy?
55
+ = link_to "#{page_url('destroy', ar_object)}", method: :delete do
56
+ .popup-option
57
+ span
58
+ i.fa.fa-trash
59
+ | Destroy
53
60
  - custom_actions.each do |custom_action|
54
61
  - if custom_action.name.present? && has_valid_policy(@model.name, custom_action.name)
55
62
  - if custom_action.display_if.call(ar_object)
@@ -1,6 +1,7 @@
1
1
  ul.nav.nav-pills
2
2
  - @model.available_tabs.each do |nav_item|
3
- - if nav_item.custom_action.empty? || (nav_item.custom_action.present? && policy([:cm_admin, @model.name.classify.constantize]).send(:"#{nav_item.custom_action}?"))
4
- li.nav-item
5
- - nav_item_action_name = nav_item.custom_action.present? ? nav_item.custom_action : 'show'
6
- = link_to nav_item.nav_item_name.to_s.titleize, "/cm_admin/#{@model.name.underscore.pluralize}/#{@ar_object.id}/#{nav_item.custom_action}", class: "nav-link #{ nav_item_action_name == action_name ? 'active' : ''}"
3
+ - if nav_item.display_if.call(@ar_object)
4
+ - if nav_item.custom_action.empty? || (nav_item.custom_action.present? && policy([:cm_admin, @model.name.classify.constantize]).send(:"#{nav_item.custom_action}?"))
5
+ li.nav-item
6
+ - nav_item_action_name = nav_item.custom_action.present? ? nav_item.custom_action : 'show'
7
+ = link_to nav_item.nav_item_name.to_s.titleize, "/cm_admin/#{@model.name.underscore.pluralize}/#{@ar_object.id}/#{nav_item.custom_action}", class: "nav-link #{ nav_item_action_name == action_name ? 'active' : ''}"
@@ -10,7 +10,6 @@ require_relative 'models/export'
10
10
  require_relative 'models/cm_show_section'
11
11
  require_relative 'models/tab'
12
12
  require_relative 'models/dsl_method'
13
- require_relative 'models/controller_method'
14
13
  require 'pagy'
15
14
  require 'axlsx'
16
15
  require 'cocoon'
@@ -21,7 +20,6 @@ module CmAdmin
21
20
  include Pagy::Backend
22
21
  include Models::Blocks
23
22
  include Models::DslMethod
24
- include Models::ControllerMethod
25
23
  attr_accessor :available_actions, :actions_set, :available_fields, :permitted_fields,
26
24
  :current_action, :params, :filters, :available_tabs, :icon_name
27
25
  attr_reader :name, :ar_model, :is_visible_on_sidebar
@@ -89,12 +87,13 @@ module CmAdmin
89
87
  @icon_name = name
90
88
  end
91
89
 
90
+ # Shared between export controller and resource controller
92
91
  def filter_params(params)
93
92
  # OPTIMIZE: Need to check if we can permit the filter_params in a better way
94
- date_columns = @filters.select{|x| x.filter_type.eql?(:date)}.map(&:db_column_name)
95
- range_columns = @filters.select{|x| x.filter_type.eql?(:range)}.map(&:db_column_name)
96
- single_select_columns = @filters.select{|x| x.filter_type.eql?(:single_select)}.map(&:db_column_name)
97
- multi_select_columns = @filters.select{|x| x.filter_type.eql?(:multi_select)}.map{|x| Hash["#{x.db_column_name}", []]}
93
+ date_columns = self.filters.select{|x| x.filter_type.eql?(:date)}.map(&:db_column_name)
94
+ range_columns = self.filters.select{|x| x.filter_type.eql?(:range)}.map(&:db_column_name)
95
+ single_select_columns = self.filters.select{|x| x.filter_type.eql?(:single_select)}.map(&:db_column_name)
96
+ multi_select_columns = self.filters.select{|x| x.filter_type.eql?(:multi_select)}.map{|x| Hash["#{x.db_column_name}", []]}
98
97
 
99
98
  params.require(:filters).permit(:search, date: date_columns, range: range_columns, single_select: single_select_columns, multi_select: multi_select_columns) if params[:filters]
100
99
  end
@@ -104,7 +103,7 @@ module CmAdmin
104
103
  # Controller defined for each model
105
104
  # If model is User, controller will be UsersController
106
105
  def define_controller
107
- klass = Class.new(CmAdmin::ApplicationController) do
106
+ klass = Class.new(CmAdmin::ResourceController) do
108
107
  include Pundit::Authorization
109
108
  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
110
109
 
@@ -116,66 +115,14 @@ module CmAdmin
116
115
  @model.params = params
117
116
  @action = CmAdmin::Models::Action.find_by(@model, name: action_name)
118
117
  @model.current_action = @action
119
- @ar_object = @model.try(@action.parent || action_name, params)
120
- @ar_object, @associated_model, @associated_ar_object = @model.custom_controller_action(action_name, params.permit!) if !@ar_object.present? && params[:id].present?
121
- authorize controller_name.classify.constantize, policy_class: "CmAdmin::#{controller_name.classify}Policy".constantize if defined? "CmAdmin::#{controller_name.classify}Policy".constantize
122
- aar_model = request.url.split('/')[-2].classify.constantize if params[:aar_id]
123
- @associated_ar_object = aar_model.find(params[:aar_id]) if params[:aar_id]
124
- nested_tables = @model.available_fields[:new].except(:fields).keys
125
- nested_tables += @model.available_fields[:edit].except(:fields).keys
126
- @reflections = @model.ar_model.reflect_on_all_associations
127
- nested_tables.each do |table_name|
128
- reflection = @reflections.select {|x| x if x.name == table_name}.first
129
- if reflection.macro == :has_many
130
- @ar_object.send(table_name).build if action_name == "new" || action_name == "edit"
131
- else
132
- @ar_object.send(('build_' + table_name.to_s).to_sym) if action_name == "new"
133
- end
134
- end
135
- respond_to do |format|
136
- if %w(show index new edit).include?(action_name)
137
- if request.xhr? && action_name.eql?('index')
138
- format.html { render partial: '/cm_admin/main/table' }
139
- else
140
- format.html { render '/cm_admin/main/'+action_name }
141
- end
142
- elsif %w(create update destroy).include?(action_name)
143
- if %w(create update).include?(action_name)
144
- redirect_url = CmAdmin::Engine.mount_path + "/#{@model.name.underscore.pluralize}/#{@ar_object.id}"
145
- else
146
- redirect_url = CmAdmin::Engine.mount_path + "/#{@model.name.underscore.pluralize}"
147
- end
148
- if @ar_object.save
149
- format.html { redirect_to redirect_url, notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is successful" }
150
- else
151
- format.html { render '/cm_admin/main/new', notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is unsuccessful" }
152
- end
153
- elsif action.action_type == :custom
154
- if action.child_records
155
- format.html { render action.layout }
156
- elsif action.display_type == :page
157
- data = @action.parent == "index" ? @ar_object.data : @ar_object
158
- format.html { render action.partial }
159
- else
160
- ar_object = @action.code_block.call(@ar_object)
161
- if ar_object.errors.empty?
162
- redirect_url = @model.current_action.redirection_url || @action.redirection_url || request.referrer || "/cm_admin/#{@model.ar_model.table_name}/#{@ar_object.id}"
163
- format.html { redirect_to redirect_url, notice: "#{@action.name.titleize} is successful" }
164
- else
165
- error_messages = ar_object.errors.full_messages.map{|error_message| "<li>#{error_message}</li>"}.join
166
- format.html { redirect_to request.referrer, alert: "<b>#{@action.name.titleize} is unsuccessful</b><br /><ul>#{error_messages}</ul>" }
167
- end
168
- end
169
- elsif action.layout.present?
170
- if request.xhr? && action.partial.present?
171
- format.html { render partial: action.partial }
172
- else
173
- format.html { render action.layout }
174
- end
175
- end
176
- end
118
+ send(@action.controller_action_name, params)
119
+ # @ar_object = @model.try(@action.parent || action_name, params)
177
120
  end
178
121
  end
122
+
123
+ def pundit_user
124
+ Current.user
125
+ end
179
126
  private
180
127
 
181
128
  def user_not_authorized
@@ -43,6 +43,16 @@ module CmAdmin
43
43
  self.partial = partial
44
44
  end
45
45
 
46
+ def controller_action_name
47
+ if self.action_type == :custom
48
+ 'cm_custom_method'
49
+ elsif self.parent
50
+ 'cm_' + self.parent
51
+ else
52
+ 'cm_' + name
53
+ end
54
+ end
55
+
46
56
  class << self
47
57
  def find_by(model, search_hash)
48
58
  model.available_actions.find { |i| i.name == search_hash[:name] }
@@ -39,17 +39,17 @@ module CmAdmin
39
39
  end
40
40
  end
41
41
 
42
- def tab(tab_name, custom_action, associated_model: nil, layout_type: nil, layout: nil, partial: nil, &block)
42
+ def tab(tab_name, custom_action, associated_model: nil, layout_type: nil, layout: nil, partial: nil, display_if: nil, &block)
43
43
  if custom_action.to_s == ''
44
44
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
45
- @available_tabs << CmAdmin::Models::Tab.new(tab_name, '', &block)
45
+ @available_tabs << CmAdmin::Models::Tab.new(tab_name, '', display_if, &block)
46
46
  else
47
47
  action = CmAdmin::Models::Action.new(name: custom_action.to_s, verb: :get, path: ':id/'+custom_action,
48
48
  layout_type: layout_type, layout: layout, partial: partial, child_records: associated_model,
49
49
  action_type: :custom, display_type: :page)
50
50
  @available_actions << action
51
51
  @current_action = action
52
- @available_tabs << CmAdmin::Models::Tab.new(tab_name, custom_action, &block)
52
+ @available_tabs << CmAdmin::Models::Tab.new(tab_name, custom_action, display_if, &block)
53
53
  end
54
54
  yield if block
55
55
  end
@@ -1,7 +1,7 @@
1
1
  module CmAdmin
2
2
  module Models
3
3
  class FormField
4
- attr_accessor :field_name, :label, :header, :input_type, :collection, :custom_value, :disabled
4
+ attr_accessor :field_name, :label, :header, :input_type, :collection, :custom_value, :disabled, :collection_method
5
5
  VALID_INPUT_TYPES = [:integer, :decimal, :string, :single_select, :multi_select, :date, :date_time, :text, :single_file_upload, :multi_file_upload, :hidden, :rich_text].freeze
6
6
 
7
7
  def initialize(field_name, input_type, attributes = {})
@@ -2,11 +2,12 @@ module CmAdmin
2
2
  module Models
3
3
  class Tab
4
4
 
5
- attr_accessor :nav_item_name, :custom_action
5
+ attr_accessor :nav_item_name, :custom_action, :display_if
6
6
 
7
- def initialize(nav_item_name, custom_action)
7
+ def initialize(nav_item_name, custom_action, display_if)
8
8
  @nav_item_name = nav_item_name
9
9
  @custom_action = custom_action
10
+ @display_if = display_if || lambda { |arg| return true }
10
11
  end
11
12
  end
12
13
  end
@@ -1,3 +1,3 @@
1
1
  module CmAdmin
2
- VERSION = "0.7.2"
2
+ VERSION = "0.7.5"
3
3
  end
@@ -13,9 +13,9 @@ module CmAdmin
13
13
  when :string
14
14
  return f.text_field field.field_name, class: "normal-input #{required_class}", disabled: field.disabled, value: value, placeholder: "Enter #{field.field_name.to_s.downcase.gsub('_', ' ')}"
15
15
  when :single_select
16
- return f.select field.field_name, options_for_select((field.collection || []), value), {include_blank: "Select #{field.field_name.to_s.downcase.gsub('_', ' ')}"}, class: "normal-input #{required_class} select-2", disabled: field.disabled
16
+ return f.select field.field_name, options_for_select(select_collection_value(field), value), {include_blank: "Select #{field.field_name.to_s.downcase.gsub('_', ' ')}"}, class: "normal-input #{required_class} select-2", disabled: field.disabled
17
17
  when :multi_select
18
- return f.select field.field_name, options_for_select((field.collection || []), value), {include_blank: "Select #{field.field_name.to_s.downcase.gsub('_', ' ')}"}, class: "normal-input #{required_class} select-2", disabled: field.disabled, multiple: true
18
+ return f.select field.field_name, options_for_select(select_collection_value(field), value), {include_blank: "Select #{field.field_name.to_s.downcase.gsub('_', ' ')}"}, class: "normal-input #{required_class} select-2", disabled: field.disabled, multiple: true
19
19
  when :date
20
20
  return f.text_field field.field_name, class: "normal-input #{required_class}", disabled: field.disabled, value: value&.strftime('%d-%m-%Y'), placeholder: "Enter #{field.field_name.to_s.downcase.gsub('_', ' ')}", data: { behaviour: 'date-only' }
21
21
  when :date_time
@@ -32,6 +32,16 @@ module CmAdmin
32
32
  return f.hidden_field field.field_name, value: field.custom_value
33
33
  end
34
34
  end
35
+
36
+ def select_collection_value(field)
37
+ if field.collection_method
38
+ collection = send(field.collection_method)
39
+ elsif field.collection
40
+ collection = field.collection
41
+ else
42
+ collection = []
43
+ end
44
+ end
35
45
  end
36
46
  end
37
47
  end
@@ -38,6 +38,15 @@ module CmAdmin
38
38
 
39
39
  def set_form_for_fields(resource, available_fields_hash, url, method)
40
40
  form_for(resource, url: url, method: method, html: { class: "cm_#{resource.class.name.downcase}_form" } ) do |f|
41
+ if params[:referrer]
42
+ concat f.text_field "referrer", class: "normal-input", hidden: true, value: params[:referrer], name: 'referrer'
43
+ end
44
+ if params[:polymorphic_name].present?
45
+ concat f.text_field params[:polymorphic_name] + '_type', class: "normal-input", hidden: true, value: params[:associated_class].classify
46
+ concat f.text_field params[:polymorphic_name] + '_id', class: "normal-input", hidden: true, value: params[:associated_id]
47
+ elsif params[:associated_class] && params[:associated_id]
48
+ concat f.text_field params[:associated_class] + '_id', class: "normal-input", hidden: true, value: params[:associated_id]
49
+ end
41
50
  available_fields_hash.each do |key, fields_array|
42
51
  if key == :fields
43
52
  fields_array.each do |field|
@@ -51,6 +51,8 @@ module CmAdmin
51
51
  base_path + '/new'
52
52
  when 'edit'
53
53
  base_path + "/#{ar_object.id}" + '/edit'
54
+ when 'destroy'
55
+ base_path + "/#{ar_object.id}"
54
56
  end
55
57
  end
56
58
 
@@ -0,0 +1,31 @@
1
+ require 'rails/generators'
2
+
3
+ module CmAdmin
4
+ module Generators
5
+ class AddAuthenticationGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('templates', __dir__)
7
+
8
+ # This generator is used to add authentication, if no auth system is present.
9
+ # Adds authentication through devise and sets up the current user.
10
+ def add_authentication
11
+ gem "devise"
12
+ generate "devise:install"
13
+ model_name = ask("What would you like the user model to be called? [user]")
14
+ generate "devise", model_name
15
+ rake "db:migrate"
16
+ copy_file 'application_controller.rb', 'app/controllers/cm_admin/application_controller.rb'
17
+ gsub_file 'app/controllers/cm_admin/application_controller.rb', 'authenticate_user', "authenticate_#{model_name}"
18
+ copy_file 'authentication.rb', 'app/controllers/concerns/authentication.rb'
19
+ gsub_file 'app/controllers/concerns/authentication.rb', 'current_user', "current_#{model_name}"
20
+ copy_file 'current.rb', 'app/models/current.rb'
21
+ inject_into_file "app/models/#{model_name.underscore}.rb", before: "end\n" do <<-'RUBY'
22
+ # Remove this once role is setup and mentioned in zcm_admin.rb
23
+ def super_admin?
24
+ true
25
+ end
26
+ RUBY
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,8 @@
1
+ module CmAdmin
2
+ class ApplicationController < ActionController::Base
3
+ include Authentication
4
+ before_action :authenticate_user!
5
+ layout 'cm_admin'
6
+ helper CmAdmin::ViewHelpers
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+ module Authentication
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_action :check_current_user
6
+ end
7
+
8
+ private
9
+ def check_current_user
10
+ if current_user
11
+ Current.user = current_user
12
+ end
13
+ end
14
+ end
@@ -1,4 +1,6 @@
1
1
  CmAdmin.configure do |config|
2
2
  # Sets the default layout to be used for admin
3
3
  config.layout = 'admin'
4
+ # config.authorized_roles = [:super_admin?]
5
+ # config.included_models = [Admin]
4
6
  end
@@ -0,0 +1,9 @@
1
+ class Current < ActiveSupport::CurrentAttributes
2
+ attribute :user, :request_id, :user_agent, :ip_address
3
+
4
+ resets { Time.zone = nil }
5
+
6
+ def user=(user)
7
+ super
8
+ end
9
+ end
@@ -1 +1 @@
1
- 09d7dd65a776413eb9615ccfd2071782565b6619
1
+ 00ac6841e4fa3607e5f705b375dada0dcaf2c84d
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cm-admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.7.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - sajinmp
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2022-06-08 00:00:00.000000000 Z
13
+ date: 2022-07-05 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: pagy
@@ -144,6 +144,7 @@ files:
144
144
  - app/assets/stylesheets/cm_admin/scaffold.scss
145
145
  - app/controllers/cm_admin/application_controller.rb
146
146
  - app/controllers/cm_admin/exports_controller.rb
147
+ - app/controllers/cm_admin/resource_controller.rb
147
148
  - app/controllers/cm_admin/static_controller.rb
148
149
  - app/helpers/cm_admin/application_helper.rb
149
150
  - app/helpers/cm_admin/custom_helper.rb
@@ -203,7 +204,6 @@ files:
203
204
  - lib/cm_admin/models/blocks.rb
204
205
  - lib/cm_admin/models/cm_show_section.rb
205
206
  - lib/cm_admin/models/column.rb
206
- - lib/cm_admin/models/controller_method.rb
207
207
  - lib/cm_admin/models/custom_action.rb
208
208
  - lib/cm_admin/models/dsl_method.rb
209
209
  - lib/cm_admin/models/export.rb
@@ -221,11 +221,15 @@ files:
221
221
  - lib/cm_admin/view_helpers/manage_column_popup_helper.rb
222
222
  - lib/cm_admin/view_helpers/navigation_helper.rb
223
223
  - lib/cm_admin/view_helpers/page_info_helper.rb
224
+ - lib/generators/cm_admin/add_authentication_generator.rb
224
225
  - lib/generators/cm_admin/install_generator.rb
225
226
  - lib/generators/cm_admin/policy_generator.rb
226
227
  - lib/generators/cm_admin/templates/actiontext.scss
228
+ - lib/generators/cm_admin/templates/application_controller.rb
227
229
  - lib/generators/cm_admin/templates/application_policy.rb
230
+ - lib/generators/cm_admin/templates/authentication.rb
228
231
  - lib/generators/cm_admin/templates/cm_admin_initializer.rb
232
+ - lib/generators/cm_admin/templates/current.rb
229
233
  - lib/generators/cm_admin/templates/custom.css
230
234
  - lib/generators/cm_admin/templates/custom.js
231
235
  - lib/generators/cm_admin/templates/policy.rb
@@ -1,86 +0,0 @@
1
- module CmAdmin
2
- module Models
3
- module ControllerMethod
4
- extend ActiveSupport::Concern
5
-
6
- def show(params)
7
- @current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
8
- scoped_model = "CmAdmin::#{self.name}Policy::Scope".constantize.new(Current.user, self.name.constantize).resolve
9
- @ar_object = scoped_model.find(params[:id])
10
- end
11
-
12
- def index(params)
13
- @current_action = CmAdmin::Models::Action.find_by(self, name: 'index')
14
- # Based on the params the filter and pagination object to be set
15
- @ar_object = filter_by(params, nil, filter_params(params))
16
- end
17
-
18
- def new(params)
19
- @current_action = CmAdmin::Models::Action.find_by(self, name: 'new')
20
- @ar_object = @ar_model.new
21
- end
22
-
23
- def edit(params)
24
- @current_action = CmAdmin::Models::Action.find_by(self, name: 'edit')
25
- @ar_object = @ar_model.name.classify.constantize.find(params[:id])
26
- end
27
-
28
- def update(params)
29
- @ar_object = @ar_model.name.classify.constantize.find(params[:id])
30
- @ar_object.assign_attributes(resource_params(params))
31
- @ar_object
32
- end
33
-
34
-
35
- def create(params)
36
- @ar_object = @ar_model.name.classify.constantize.new(resource_params(params))
37
- end
38
-
39
- def filter_by(params, records, filter_params={}, sort_params={})
40
- filtered_result = OpenStruct.new
41
- sort_column = "created_at"
42
- sort_direction = %w[asc desc].include?(sort_params[:sort_direction]) ? sort_params[:sort_direction] : "asc"
43
- sort_params = {sort_column: sort_column, sort_direction: sort_direction}
44
-
45
- records = "CmAdmin::#{self.name}Policy::Scope".constantize.new(Current.user, self.name.constantize).resolve if records.nil?
46
- records = records.order("#{current_action.sort_column} #{current_action.sort_direction}")
47
-
48
- final_data = CmAdmin::Models::Filter.filtered_data(filter_params, records, @filters)
49
- pagy, records = pagy(final_data)
50
- filtered_result.data = records
51
- filtered_result.pagy = pagy
52
- # filtered_result.facets = paginate(page, raw_data.size)
53
- # filtered_result.sort = sort_params
54
- # filtered_result.facets.sort = sort_params
55
- return filtered_result
56
- end
57
-
58
- def resource_params(params)
59
- permittable_fields = @permitted_fields || @ar_model.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym)
60
- permittable_fields += @ar_model.name.constantize.reflect_on_all_associations.map {|x|
61
- if x.klass.name == "ActiveStorage::Attachment"
62
- if x.class.name.include?('HasOne')
63
- x.name
64
- elsif x.class.name.include?('HasMany')
65
- Hash[x.name.to_s, []]
66
- end
67
- elsif x.klass.name == "ActionText::RichText"
68
- x.name.to_s.gsub('rich_text_', '').to_sym
69
- end
70
- }.compact
71
- nested_tables = self.available_fields[:new].except(:fields).keys
72
- nested_tables += self.available_fields[:edit].except(:fields).keys
73
- nested_fields = nested_tables.uniq.map {|table|
74
- Hash[
75
- table.to_s + '_attributes',
76
- table.to_s.classify.constantize.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym) + [:id, :_destroy]
77
- ]
78
- }
79
- permittable_fields += nested_fields
80
- @ar_model.columns.map { |col| permittable_fields << col.name.split('_cents') if col.name.include?('_cents') }
81
-
82
- params.require(self.name.underscore.to_sym).permit(*permittable_fields)
83
- end
84
- end
85
- end
86
- end