cm-admin 1.5.53 → 1.5.54

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: d136db7d97b8cb78d65d3dc1a2e27f709dd4065c142e9219e8969c33bb9e491a
4
- data.tar.gz: 7991bc93af63655d1ad93bf5604b834fd9ffd36e072e918d91fc88e5685ade5b
3
+ metadata.gz: 48f4b0a9c698fe7b2cfd60cfe47a12e0afa0d3bbcf64d67cadd584dab2532de0
4
+ data.tar.gz: 14a61034d53f304b0f4c8e8fe9a419983ae04d08097df6bc7d05fbeac012c7a1
5
5
  SHA512:
6
- metadata.gz: bace0b999baec89fc23fd5dac17b0a2248cbc5b330ff987db45208eb12463592cca7821b98f72423b536dece0fc7727592a431540d6f8ba3debe38594f23be5a
7
- data.tar.gz: 5e0e8358a5840e14ffc9c29f2264f97c40f345c2079d0deef52d1d136bdf79bf4db70e8d3bc7797235cac66897b9cbecb6847faf32c21a3c00b7f8eada96ddcd
6
+ metadata.gz: bfc1c6bda642cf1d3d45e8216f326150a6faf3d0aedc3ba84f607244ae394104a7ceb26f8a02476e4ac5c4da641fac86831668b3d951d08d6d416525dcacee89
7
+ data.tar.gz: ccdc8978d2195022972491299e9bc78eee5b615ab209f8cc649dcf0f0894edc33672232a7e1730396c8ac00ff9eff53a8c70ad1a60f25b4331daeeb2e7cad5fd
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cm-admin (1.5.53)
4
+ cm-admin (1.5.54)
5
5
  caxlsx_rails
6
6
  cocoon (~> 1.2.15)
7
7
  csv-importer (~> 0.8.2)
@@ -68,6 +68,41 @@ $(document).on("click", ".destroy-attachment button", function (e) {
68
68
  );
69
69
  });
70
70
 
71
+ $(document).on(
72
+ "click",
73
+ '[data-behaviour="permission-check-box"]',
74
+ function (e) {
75
+ var form_check = $(this).closest('.form-check')
76
+ var form_field = $(this).closest('.form-field')
77
+ if($(this).is(':checked')){
78
+ form_check.find('.cm-select-tag').removeClass('hidden')
79
+ } else {
80
+ form_check.find('.cm-select-tag').addClass('hidden')
81
+ }
82
+ if (form_field.find('[data-behaviour="permission-check-box"]:checked').length == form_field.find('[data-behaviour="permission-check-box"]').length) {
83
+ form_field.find('[data-behaviour="permission-check-all"]').prop('checked', true)
84
+ }
85
+ else {
86
+ form_field.find('[data-behaviour="permission-check-all"]').prop('checked', false)
87
+ }
88
+ }
89
+ );
90
+
91
+ $(document).on(
92
+ "click",
93
+ '[data-behaviour="permission-check-all"]',
94
+ function (e) {
95
+ var form_field = $(this).closest('.form-field')
96
+ if($(this).is(':checked')){
97
+ form_field.find('[data-behaviour="permission-check-box"]').prop('checked', true)
98
+ form_field.find('.cm-select-tag').removeClass('hidden')
99
+ } else {
100
+ form_field.find('[data-behaviour="permission-check-box"]').prop('checked', false)
101
+ form_field.find('.cm-select-tag').addClass('hidden')
102
+ }
103
+ }
104
+ );
105
+
71
106
  window.addEventListener("popstate", (e) => window.location.reload());
72
107
 
73
108
  function setup_select_2_ajax() {
@@ -4,6 +4,7 @@
4
4
  @import "./helpers/index.scss";
5
5
  @import "./pages/import_page";
6
6
  @import "./pages/history_page";
7
+ @import "./pages/permission_page";
7
8
  @import "./base/table";
8
9
  @import "./base/navbar";
9
10
  @import "./base/sidebar";
@@ -0,0 +1,28 @@
1
+ .permission-form {
2
+ // Margin negative since we are using tab as form.
3
+ margin: -24px !important;
4
+ .form-container__inner {
5
+ padding: 16px !important;
6
+ }
7
+ .form-check {
8
+ display: flex;
9
+ margin-bottom: 16px !important;
10
+ }
11
+ .select2-container {
12
+ width: 124px !important;
13
+ }
14
+ &__checkbox-wrapper {
15
+ padding-top: 6px;
16
+ }
17
+
18
+ .cm-checkbox-label {
19
+ .action-name {
20
+ float: left;
21
+ margin-right: 10px;
22
+ }
23
+ .cm-select-tag {
24
+ float: left;
25
+ }
26
+ }
27
+
28
+ }
@@ -8,6 +8,7 @@ module CmAdmin
8
8
  def cm_index(params)
9
9
  @current_action = CmAdmin::Models::Action.find_by(@model, name: 'index')
10
10
  # Based on the params the filter and pagination object to be set
11
+ authorize @ar_object, policy_class: "CmAdmin::#{controller_name.classify}Policy".constantize if defined? "CmAdmin::#{controller_name.classify}Policy".constantize
11
12
  records = "CmAdmin::#{@model.name}Policy::Scope".constantize.new(Current.user, @model.name.constantize).resolve
12
13
  records = apply_scopes(records)
13
14
  if (['table', 'card'].include?(params[:view_type]) || [:table, :card].include?(@current_action.view_type))
@@ -0,0 +1,2 @@
1
+ class CmPermission < ApplicationRecord
2
+ end
@@ -0,0 +1,9 @@
1
+ class CmRole < ApplicationRecord
2
+ include CmAdmin::CmRole
3
+
4
+ has_many :cm_permissions
5
+
6
+ validates :name, uniqueness: true, presence: true
7
+
8
+ has_paper_trail
9
+ end
@@ -0,0 +1,56 @@
1
+ module CmAdmin::CmRole
2
+ extend ActiveSupport::Concern
3
+ included do
4
+ cm_admin do
5
+ actions only: []
6
+ set_icon "fa fa-database"
7
+ cm_index do
8
+ page_title 'Role'
9
+
10
+ filter [:name], :search, placeholder: 'Search'
11
+
12
+ column :name
13
+ column :created_at, field_type: :date, format: '%d %b, %Y'
14
+ column :updated_at, field_type: :date, format: '%d %b, %Y'
15
+ end
16
+
17
+ cm_show page_title: :name do
18
+ custom_action name: 'create_role_permission', route_type: 'member', verb: 'post', path: ':id/create_role_permission',
19
+ display_type: :route do
20
+ # allowed_params = params.permit(role_permission: []).to_h
21
+ @role = CmRole.find(params[:id])
22
+ params[:role_permission].except(:submit).each do |model_name, action_arr|
23
+ @role.cm_permissions.where(ar_model_name: model_name).where.not(action_name: action_arr.select{ |k,v| k if v.has_key?('is_checked')}.keys).destroy_all
24
+ action_arr.each do |action_name, selected_option|
25
+ if selected_option.has_key?('is_checked')
26
+ permission = @role.cm_permissions.where(action_name: action_name, ar_model_name: model_name).first_or_create
27
+ permission.update(scope_name: selected_option['scope_name'])
28
+ end
29
+ end
30
+ end
31
+ @role
32
+ end
33
+ tab :profile, '' do
34
+ cm_show_section 'Role details' do
35
+ field :name
36
+ field :created_at, field_type: :date, format: '%d %b, %Y'
37
+ field :updated_at, field_type: :date, format: '%d %b, %Y'
38
+ end
39
+ end
40
+ tab :permissions, 'permissions', layout_type: 'cm_association_show', partial: '/cm_admin/roles/permissions'
41
+ end
42
+
43
+ cm_new page_title: 'Add Role', page_description: 'Enter all details to add role' do
44
+ cm_section 'Details' do
45
+ form_field :name, input_type: :string
46
+ end
47
+ end
48
+
49
+ cm_edit page_title: 'Edit Role', page_description: 'Enter all details to edit role' do
50
+ cm_section 'Details' do
51
+ form_field :name, input_type: :string
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,37 @@
1
+ .form-page.permission-form
2
+ .form-page__body
3
+ .form-container
4
+ = form_for CmPermission.new, url: cm_admin.send('cm_role_create_role_permission_path', @ar_object), method: :post do |f|
5
+ - CmAdmin.config.cm_admin_models.each do |model|
6
+ - next if model.override_policy == true
7
+ .row
8
+ .col.form-container
9
+ p.form-title
10
+ = model.model_name
11
+ .form-container__inner
12
+ .row
13
+ .col
14
+ .form-field.disabled
15
+ .form-check
16
+ .permission-form__checkbox-wrapper
17
+ - saved_permission = @ar_object.cm_permissions.where(ar_model_name: model.name)
18
+ - available_actions = model.available_actions.reject {|x| ['custom_action_modal', 'custom_action', 'create', 'update'].include?(x.name)}
19
+ - is_checked = (saved_permission.count == available_actions.count)
20
+ input.form-check-input[type="checkbox" value="" data-behaviour="permission-check-all" checked=is_checked]
21
+ .cm-checkbox-label
22
+ span.action-name
23
+ | All
24
+ - model.available_actions.each do |action|
25
+ - permission = @ar_object.cm_permissions.where(ar_model_name: model.name, action_name: action.name).first
26
+ - unless ['custom_action_modal', 'custom_action', 'create', 'update'].include?(action.name)
27
+ .form-check
28
+ .permission-form__checkbox-wrapper
29
+ input.form-check-input[type="checkbox" value="#{action.name}" checked=permission.present? name="role_permission[#{model.name}][#{action.name}][is_checked]" data-behaviour="permission-check-box"]
30
+ .cm-checkbox-label
31
+ span.action-name
32
+ = action.display_name || action.name.titleize
33
+ .cm-select-tag class="#{permission.present? ? '' : 'hidden'}"
34
+ = select_tag(:policy_scope_name, options_for_select(model.policy_scopes.map{|policy_hash| [policy_hash[:display_name], policy_hash[:scope_name]]}, permission&.scope_name), {name: "role_permission[#{model.name}][#{action.name}][scope_name]", class: 'select-2', id: "policy-scope-#{model.name}-#{action.name}"})
35
+ div
36
+ = f.submit 'Save Changes', class: "btn-cta"
37
+ = link_to 'Discard', cm_admin.send('cm_role_index_path'), class: "btn btn-outline-dark ml-10"
@@ -0,0 +1,78 @@
1
+ # Role and Permission Management
2
+
3
+ ## Overview
4
+
5
+ We can manage the roles and permission through CmAdmin. CmAdmin creates pundit policies dynamically and helps us the manage the permission through a interface.
6
+
7
+ ## Features
8
+
9
+ - **Create Role:** We can create any role we want on the application
10
+ - **Manage Permissions:** All the possible actions are listed for each role and we can enable or disable permission for each role.
11
+
12
+ ## Usage
13
+
14
+ - To add role and permission table
15
+
16
+ ```
17
+ rake cm_admin:install_role
18
+ ```
19
+
20
+ - Rake task creates a default migration
21
+
22
+ - Create a role column on the user table. Note: The column name has to be `cm_role_id` else policy will fail
23
+
24
+ ```
25
+ rails g migration AddCmRoleToUser cm_role:references
26
+ ```
27
+
28
+ - Assign the role to the user. Right now only one role can be assigned to a user.
29
+
30
+ - Assigning the params in the current attribute.
31
+ ```
32
+ In the `app/models/current.rb` add request_params as attribure
33
+
34
+ In the `app/controllers/concerns/authentation.rb` set the request_params. This helps cm-admin identify which action is being performed in the pundit policy.
35
+
36
+ module Authentication
37
+ extend ActiveSupport::Concern
38
+
39
+ included do
40
+ before_action :check_current_user
41
+ before_action :set_params
42
+ end
43
+ ...
44
+ def set_params
45
+ if params
46
+ Current.request_params = params
47
+ end
48
+ end
49
+ end
50
+ ```
51
+
52
+
53
+ ## Override policy
54
+
55
+ By default, the Roles and policy gets enabled for all the models on the application. We can override the policy with the following
56
+
57
+ ```
58
+ ...
59
+ cm_admin do
60
+ actions only: []
61
+ set_icon "fa fa-user"
62
+ override_pundit_policy true
63
+ cm_index do
64
+ page_title 'User'
65
+ ....
66
+ ```
67
+
68
+ and create a policy file on the application for the respective model. eg: `app/policies/cm_admin/user_policy.rb`
69
+ ```
70
+ class CmAdmin::UserPolicy < ApplicationPolicy
71
+
72
+
73
+ def index?
74
+ true
75
+ end
76
+ ...
77
+ end
78
+ ```
@@ -30,7 +30,8 @@ module CmAdmin
30
30
  include CmAdmin::Engine.routes.url_helpers
31
31
 
32
32
  attr_accessor :available_actions, :actions_set, :available_fields, :additional_permitted_fields,
33
- :current_action, :params, :filters, :available_tabs, :icon_name, :bulk_actions, :display_name, :alerts
33
+ :current_action, :params, :filters, :available_tabs, :icon_name, :bulk_actions, :display_name,
34
+ :policy_scopes, :override_policy, :alerts
34
35
  attr_reader :name, :ar_model, :is_visible_on_sidebar, :importer
35
36
 
36
37
  def initialize(entity, &block)
@@ -45,12 +46,15 @@ module CmAdmin
45
46
  @available_tabs ||= []
46
47
  @available_fields ||= { index: [], show: [], edit: [], new: [] }
47
48
  @params = nil
49
+ @override_policy = false
48
50
  @filters ||= []
51
+ @policy_scopes ||= [{display_name: 'Full Access', scope_name: 'all'}]
49
52
  @alerts = []
50
53
  instance_eval(&block) if block_given?
51
54
  actions unless @actions_set
52
55
  $available_actions = @available_actions.dup
53
56
  define_controller
57
+ define_pundit_policy(@ar_model) unless @override_policy
54
58
  end
55
59
 
56
60
  class << self
@@ -102,6 +106,10 @@ module CmAdmin
102
106
  @icon_name = name
103
107
  end
104
108
 
109
+ def override_pundit_policy(override_status=false)
110
+ @override_policy = override_status
111
+ end
112
+
105
113
  def set_display_name(name)
106
114
  @display_name = name
107
115
  end
@@ -122,6 +130,10 @@ module CmAdmin
122
130
  @display_name.present? ? @display_name : @name
123
131
  end
124
132
 
133
+ def set_policy_scopes(scopes=[])
134
+ @policy_scopes = ([{display_name: 'Full Access', scope_name: 'all'}] + scopes).uniq
135
+ end
136
+
125
137
  # Shared between export controller and resource controller
126
138
  def filter_params(params)
127
139
  # OPTIMIZE: Need to check if we can permit the filter_params in a better way
@@ -167,5 +179,45 @@ module CmAdmin
167
179
  end if $available_actions.present?
168
180
  CmAdmin.const_set "#{@name}Controller", klass
169
181
  end
182
+
183
+ def define_pundit_policy(ar_model)
184
+ klass = Class.new(ApplicationPolicy) do
185
+
186
+ $available_actions.each do |action|
187
+ define_method "#{action.name}?".to_sym do
188
+
189
+ return false unless Current.user.respond_to?(:cm_role_id)
190
+ return false if Current.user.cm_role.nil?
191
+
192
+ Current.user.cm_role.cm_permissions.where(action_name: action.name, ar_model_name: ar_model.name).present?
193
+ end
194
+ end
195
+
196
+ end if $available_actions.present?
197
+ policy = CmAdmin.const_set "#{ar_model.name}Policy", klass
198
+
199
+ klass = Class.new(policy) do
200
+ def initialize(user, scope)
201
+ @user = user
202
+ @scope = scope
203
+ end
204
+
205
+ define_method :resolve do
206
+ action_name = Current.request_params.dig("action")
207
+ permission = Current.user.cm_role.cm_permissions.find_by(action_name: action_name, ar_model_name: ar_model.name)
208
+ if permission.present? && permission.scope_name.present?
209
+ scope.send(permission.scope_name)
210
+ else
211
+ scope.all
212
+ end
213
+ end
214
+
215
+ private
216
+
217
+ attr_reader :user, :scope
218
+ end
219
+
220
+ policy.const_set 'Scope', klass
221
+ end
170
222
  end
171
223
  end
@@ -1,3 +1,3 @@
1
1
  module CmAdmin
2
- VERSION = '1.5.53'
2
+ VERSION = '1.5.54'
3
3
  end
@@ -0,0 +1,28 @@
1
+ require 'rails/generators'
2
+
3
+ module CmAdmin
4
+ module Generators
5
+ class InstallRoleGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('templates', __dir__)
7
+
8
+ def create_migration
9
+ generate 'migration', 'CreateCmRole name:string'
10
+ generate 'migration', 'CreateCmPermission action_name:string action_display_name:string ar_model_name:string scope_name:string cm_role:references'
11
+ rake 'db:migrate'
12
+ puts "Created migration"
13
+ end
14
+
15
+ def create_default_role
16
+ ::CmRole.create(name: 'Admin')
17
+ CmAdmin.config.cm_admin_models.each do |model|
18
+ model.available_actions.each do |action|
19
+ next if ['custom_action_modal', 'custom_action', 'create', 'update'].include?(action.name)
20
+
21
+ ::CmRole.find_by(name: 'Admin').cm_permissions.where(ar_model_name: model.name, action_name: action.name).first_or_create!
22
+ end
23
+ end
24
+ puts "Created default role"
25
+ end
26
+ end
27
+ end
28
+ end