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 +4 -4
- data/Gemfile.lock +1 -1
- data/app/assets/javascripts/cm_admin/scaffolds.js +35 -0
- data/app/assets/stylesheets/cm_admin/cm_admin.css.scss +1 -0
- data/app/assets/stylesheets/cm_admin/pages/permission_page.scss +28 -0
- data/app/controllers/cm_admin/resource_controller.rb +1 -0
- data/app/models/cm_permission.rb +2 -0
- data/app/models/cm_role.rb +9 -0
- data/app/models/concerns/cm_admin/cm_role.rb +56 -0
- data/app/views/cm_admin/roles/permissions.html.slim +37 -0
- data/docs/RoleManagement.md +78 -0
- data/lib/cm_admin/model.rb +53 -1
- data/lib/cm_admin/version.rb +1 -1
- data/lib/generators/cm_admin/install_role_generator.rb +28 -0
- data/package-lock.json +184 -102
- data/package.json +1 -1
- data/yarn.lock +161 -59
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 48f4b0a9c698fe7b2cfd60cfe47a12e0afa0d3bbcf64d67cadd584dab2532de0
|
4
|
+
data.tar.gz: 14a61034d53f304b0f4c8e8fe9a419983ae04d08097df6bc7d05fbeac012c7a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfc1c6bda642cf1d3d45e8216f326150a6faf3d0aedc3ba84f607244ae394104a7ceb26f8a02476e4ac5c4da641fac86831668b3d951d08d6d416525dcacee89
|
7
|
+
data.tar.gz: ccdc8978d2195022972491299e9bc78eee5b615ab209f8cc649dcf0f0894edc33672232a7e1730396c8ac00ff9eff53a8c70ad1a60f25b4331daeeb2e7cad5fd
|
data/Gemfile.lock
CHANGED
@@ -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() {
|
@@ -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,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
|
+
```
|
data/lib/cm_admin/model.rb
CHANGED
@@ -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,
|
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
|
data/lib/cm_admin/version.rb
CHANGED
@@ -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
|