cm-admin 0.5.6 → 0.5.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/Gemfile.lock +29 -23
  4. data/README.md +5 -1
  5. data/app/assets/stylesheets/cm_admin/base/scaffold.scss +21 -0
  6. data/app/assets/stylesheets/cm_admin/components/_drawer.scss +7 -1
  7. data/app/assets/stylesheets/cm_admin/scaffold.scss +12 -6
  8. data/app/controllers/cm_admin/application_controller.rb +3 -0
  9. data/app/policies/application_policy.rb +53 -0
  10. data/app/views/cm_admin/main/_associated_table.html.slim +2 -2
  11. data/app/views/cm_admin/main/_table.html.slim +19 -15
  12. data/app/views/cm_admin/main/_tabs.html.slim +4 -3
  13. data/app/views/cm_admin/main/_top_navbar.html.slim +4 -5
  14. data/app/views/cm_admin/main/associated_index.html.slim +1 -1
  15. data/app/views/cm_admin/main/index.html.slim +5 -2
  16. data/app/views/cm_admin/static/dashboard.html.slim +1 -0
  17. data/app/views/cm_admin/static/error_403.html.slim +4 -0
  18. data/cm_admin.gemspec +1 -0
  19. data/config/initializers/active_record_extension.rb +1 -1
  20. data/config/routes.rb +1 -1
  21. data/lib/cm_admin/configuration.rb +10 -0
  22. data/lib/cm_admin/model.rb +39 -4
  23. data/lib/cm_admin/models/action.rb +9 -1
  24. data/lib/cm_admin/models/controller_method.rb +3 -3
  25. data/lib/cm_admin/models/dsl_method.rb +13 -14
  26. data/lib/cm_admin/models/field.rb +2 -1
  27. data/lib/cm_admin/version.rb +1 -1
  28. data/lib/cm_admin/view_helpers/field_display_helper.rb +16 -7
  29. data/lib/cm_admin/view_helpers/form_helper.rb +7 -5
  30. data/lib/cm_admin/view_helpers/navigation_helper.rb +19 -17
  31. data/lib/cm_admin/view_helpers/page_info_helper.rb +0 -4
  32. data/lib/cm_admin.rb +13 -7
  33. data/lib/generators/cm_admin/install_generator.rb +11 -21
  34. data/lib/generators/cm_admin/templates/cm_admin_initializer.rb +4 -0
  35. data/lib/generators/cm_admin/templates/custom.css +0 -0
  36. data/lib/generators/cm_admin/templates/custom.js +0 -0
  37. metadata +27 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e71407dad6f3a42e093faa7247489382dd4b650b3c61f85b6758286a7d2ee45
4
- data.tar.gz: e50e11e94676d06e9044a58b84f20cb416d92e8a0a92507afa5ff362b98d9640
3
+ metadata.gz: b0f2b3549e1dfc742d740ac99368efcd98d19fb70f490581568816a2eb88d238
4
+ data.tar.gz: 515da90e85fdf498116babe7798decc32453d2667d95e9dc0eb74e1ab89c64db
5
5
  SHA512:
6
- metadata.gz: 07bf22fe0ea5157252da7a3b17b012f6842ce5da4815764fd6ace17af0203db2dd09158d97efc9f19c51e9df5529f742c7284e501b5879b3694e48aed4283cf3
7
- data.tar.gz: 9433f9fd8d71db8f7d1a95668e723cf655cc91e66df19b73d73f405336a7649e8c2a1f011c901a898990512a1e4eefe5092ed7f6502feabf75599a2e0ac0ff1d
6
+ metadata.gz: 8630a7ce57b1b00ca9497d2f4209ee8d86df18304a44f5fbf6ee85c8f70eda19bd9d415abc4502793eeee9f93aa5d4c83630555ae46b1e456fffa45cd0e3d922
7
+ data.tar.gz: 50c02b1132b2382e4adbdde2799c7f3104de07f95a421dbbe371e546424a62c3a000c4a487c494300f9bf5dc36ad7ec317cbeb2d0187802c565f1fac23321900
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ gem 'slim'
5
5
  gem "rake", "~> 12.0"
6
6
  gem "rspec", "~> 3.0"
7
7
  gem 'cocoon'
8
+ gem 'pundit'
8
9
 
9
10
  # Specify your gem's dependencies in cm_admin.gemspec
10
11
  gemspec
data/Gemfile.lock CHANGED
@@ -1,40 +1,40 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cm-admin (0.4.2)
4
+ cm-admin (0.5.7)
5
5
  axlsx_rails (~> 0.6.1)
6
6
  cocoon (~> 1.2.15)
7
7
  pagy (~> 4.11.0)
8
+ pundit (~> 2.2.0)
8
9
  slim (~> 4.1.0)
9
10
  webpacker (~> 5.2.1)
10
11
 
11
12
  GEM
12
13
  remote: https://rubygems.org/
13
14
  specs:
14
- actionpack (6.1.4.1)
15
- actionview (= 6.1.4.1)
16
- activesupport (= 6.1.4.1)
17
- rack (~> 2.0, >= 2.0.9)
15
+ actionpack (7.0.2.3)
16
+ actionview (= 7.0.2.3)
17
+ activesupport (= 7.0.2.3)
18
+ rack (~> 2.0, >= 2.2.0)
18
19
  rack-test (>= 0.6.3)
19
20
  rails-dom-testing (~> 2.0)
20
21
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
21
- actionview (6.1.4.1)
22
- activesupport (= 6.1.4.1)
22
+ actionview (7.0.2.3)
23
+ activesupport (= 7.0.2.3)
23
24
  builder (~> 3.1)
24
25
  erubi (~> 1.4)
25
26
  rails-dom-testing (~> 2.0)
26
27
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
27
- activesupport (6.1.4.1)
28
+ activesupport (7.0.2.3)
28
29
  concurrent-ruby (~> 1.0, >= 1.0.2)
29
30
  i18n (>= 1.6, < 2)
30
31
  minitest (>= 5.1)
31
32
  tzinfo (~> 2.0)
32
- zeitwerk (~> 2.3)
33
33
  axlsx_rails (0.6.1)
34
34
  actionpack (>= 3.1)
35
35
  caxlsx (>= 3.0)
36
36
  builder (3.2.4)
37
- caxlsx (3.1.1)
37
+ caxlsx (3.2.0)
38
38
  htmlentities (~> 4.3, >= 4.3.4)
39
39
  marcel (~> 1.0)
40
40
  nokogiri (~> 1.10, >= 1.10.4)
@@ -45,20 +45,24 @@ GEM
45
45
  diff-lcs (1.4.4)
46
46
  erubi (1.10.0)
47
47
  htmlentities (4.3.4)
48
- i18n (1.8.10)
48
+ i18n (1.10.0)
49
49
  concurrent-ruby (~> 1.0)
50
- loofah (2.12.0)
50
+ loofah (2.15.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
- minitest (5.14.4)
56
- nokogiri (1.12.5-x86_64-darwin)
55
+ mini_portile2 (2.8.0)
56
+ minitest (5.15.0)
57
+ nokogiri (1.13.3)
58
+ mini_portile2 (~> 2.8.0)
57
59
  racc (~> 1.4)
58
60
  pagy (4.11.0)
59
- racc (1.5.2)
61
+ pundit (2.2.0)
62
+ activesupport (>= 3.0.0)
63
+ racc (1.6.0)
60
64
  rack (2.2.3)
61
- rack-proxy (0.7.0)
65
+ rack-proxy (0.7.2)
62
66
  rack
63
67
  rack-test (1.1.0)
64
68
  rack (>= 1.0, < 3)
@@ -67,12 +71,13 @@ GEM
67
71
  nokogiri (>= 1.6)
68
72
  rails-html-sanitizer (1.4.2)
69
73
  loofah (~> 2.3)
70
- railties (6.1.4.1)
71
- actionpack (= 6.1.4.1)
72
- activesupport (= 6.1.4.1)
74
+ railties (7.0.2.3)
75
+ actionpack (= 7.0.2.3)
76
+ activesupport (= 7.0.2.3)
73
77
  method_source
74
- rake (>= 0.13)
78
+ rake (>= 12.2)
75
79
  thor (~> 1.0)
80
+ zeitwerk (~> 2.5)
76
81
  rake (12.3.3)
77
82
  rspec (3.10.0)
78
83
  rspec-core (~> 3.10.0)
@@ -93,7 +98,7 @@ GEM
93
98
  temple (>= 0.7.6, < 0.9)
94
99
  tilt (>= 2.0.6, < 2.1)
95
100
  temple (0.8.2)
96
- thor (1.1.0)
101
+ thor (1.2.1)
97
102
  tilt (2.0.10)
98
103
  tzinfo (2.0.4)
99
104
  concurrent-ruby (~> 1.0)
@@ -102,7 +107,7 @@ GEM
102
107
  rack-proxy (>= 0.6.1)
103
108
  railties (>= 5.2)
104
109
  semantic_range (>= 2.3.0)
105
- zeitwerk (2.4.2)
110
+ zeitwerk (2.5.4)
106
111
 
107
112
  PLATFORMS
108
113
  ruby
@@ -111,9 +116,10 @@ DEPENDENCIES
111
116
  cm-admin!
112
117
  cocoon
113
118
  pagy (~> 4.11.0)
119
+ pundit
114
120
  rake (~> 12.0)
115
121
  rspec (~> 3.0)
116
122
  slim
117
123
 
118
124
  BUNDLED WITH
119
- 2.0.2
125
+ 2.2.33
data/README.md CHANGED
@@ -24,7 +24,11 @@ Install the gem
24
24
 
25
25
  $ rails g cm_admin:install
26
26
 
27
- ## Usage
27
+ ## Documentation
28
+
29
+ You can find more detailed documentation [here](https://github.com/commutatus/cm-admin/wiki)
30
+
31
+ ## Demo
28
32
 
29
33
  For demo check [here](http://cm-admin.labs.commutatus.com/admin/users/)
30
34
 
@@ -79,6 +79,27 @@ a {
79
79
  overflow: auto;
80
80
  }
81
81
 
82
+ .input-wrapper {
83
+ margin-bottom: 24px;
84
+ input, select, .select2 {
85
+ width: 320px;
86
+ }
87
+ textarea {
88
+ width: 480px;
89
+ }
90
+ }
91
+ .input-wrapper.disabled {
92
+ input:disabled {
93
+ background-color: $grey-lightest-clr;
94
+ }
95
+ label {
96
+ color: $ink-lightest-clr;
97
+ }
98
+ }
99
+ .nested-fields .select2 {
100
+ width: 320px !important;
101
+ }
102
+
82
103
  .datetime-wrapper {
83
104
  position: relative;
84
105
  }
@@ -83,4 +83,10 @@
83
83
  left: -400px;
84
84
  opacity: 0;
85
85
  }
86
- }
86
+ }
87
+
88
+ .drawer-btn {
89
+ cursor: pointer;
90
+ margin-left: 8px;
91
+ @include font($size: $t4-text, $color: $brand-color);
92
+ }
@@ -1,16 +1,18 @@
1
+ @import "helpers/index.scss";
2
+
1
3
  .jGrowl {
2
- color: #1D2129 !important;
4
+ color: $ink-regular-clr !important;
3
5
  font-size: 14px !important;
4
6
  .success{
5
- background-color: #C1EDE2 !important;
7
+ background-color: $green-light-clr !important;
6
8
  }
7
9
  .notice {
8
- background-color: #CDE1FB !important;
10
+ background-color: $blue-light-clr !important;
9
11
  }
10
12
  .error {
11
- background-color: #FDCFCF !important;
13
+ background-color: $red-light-clr !important;
12
14
  }
13
-
15
+
14
16
  }
15
17
 
16
18
  .nested-field-wrapper {
@@ -21,4 +23,8 @@
21
23
  .nested-fields {
22
24
  margin-bottom: 16px;
23
25
  }
24
- }
26
+ }
27
+
28
+ .ink-light-clr {
29
+ color: $ink-lighter-clr;
30
+ }
@@ -1,11 +1,14 @@
1
1
  module CmAdmin
2
2
  class ApplicationController < ::ActionController::Base
3
+ include Pundit::Authorization
3
4
  # before_action :check_cm_admin
4
5
  layout 'cm_admin'
5
6
  helper CmAdmin::ViewHelpers
6
7
 
8
+
7
9
  def check_cm_admin
8
10
  redirect_to CmAdmin::Engine.mount_path + '/access-denied' unless defined?(::Current) && ::Current.cm_admin_user
9
11
  end
12
+
10
13
  end
11
14
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationPolicy
4
+ attr_reader :user, :record
5
+
6
+ def initialize(user, record)
7
+ @user = user
8
+ @record = record
9
+ end
10
+
11
+ def index?
12
+ false
13
+ end
14
+
15
+ def show?
16
+ true
17
+ end
18
+
19
+ def create?
20
+ false
21
+ end
22
+
23
+ def new?
24
+ create?
25
+ end
26
+
27
+ def update?
28
+ false
29
+ end
30
+
31
+ def edit?
32
+ update?
33
+ end
34
+
35
+ def destroy?
36
+ false
37
+ end
38
+
39
+ class Scope
40
+ def initialize(user, scope)
41
+ @user = user
42
+ @scope = scope
43
+ end
44
+
45
+ def resolve
46
+ raise NotImplementedError, "You must define #resolve in #{self.class}"
47
+ end
48
+
49
+ private
50
+
51
+ attr_reader :user, :scope
52
+ end
53
+ end
@@ -1,6 +1,6 @@
1
1
  .admin-table-index
2
2
  .table-top
3
- p.table-top__total-count = "#{@associated_ar_object.pagy.count} #{@associated_model&.ar_model&.table_name} found"
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
5
  button.secondary-btn.column-btn data-target="#columnActionModal" data-toggle="modal" type="button"
6
6
  span
@@ -51,7 +51,7 @@
51
51
  == render partial: 'cm_admin/main/cm_pagy_nav', locals: { pagy: @associated_ar_object.pagy }
52
52
 
53
53
  - @associated_ar_object.data.each do |ar_object|
54
- - @associated_model && @associated_model.available_actions.select{|act| act if act.route_type == 'member'}.each do |custom_action|
54
+ - @associated_model && @associated_model.available_actions.select{|act| act if (act.route_type == 'member' && act.display_type == :modal)}.each do |custom_action|
55
55
  .modal.fade id="#{custom_action.name.classify}Modal-#{ar_object.id.to_s}" aria-hidden="true" aria-labelledby="#{custom_action.name.classify}ModalLabel" tabindex="1"
56
56
  .modal-dialog
57
57
  .modal-content
@@ -31,21 +31,25 @@
31
31
  = show_field_value(ar_object, column)
32
32
  - if column.field_type == :drawer
33
33
  = render partial: column.drawer_partial, locals: { ar_object: ar_object}
34
- td.row-action-cell
35
- .row-action-tool
36
- button.secondary-btn.tool-btn type="button"
37
- span
38
- i.fa.fa-bars.bolder
39
- span
40
- i.fa.fa-angle-down
41
- .popup-card.table-export-popup.hidden
42
- .popup-option
43
- a href="#{page_url('edit', ar_object)}"
44
- | Edit
45
- - @model.available_actions.select{|act| act if act.route_type == 'member' && [:button, :modal].include?(act.display_type)}.each do |custom_action|
46
- - if custom_action.display_if.call(ar_object)
47
- .popup-option
48
- = link_to custom_action.name.titleize, custom_action.path.gsub(':id', ar_object.id.to_s), method: custom_action.verb
34
+
35
+ - edit_action = @model.available_actions.select{|act| act if act.action_type.eql?(:default) && act.name.eql?('edit')}
36
+ - custom_actions = @model.available_actions.select{|act| act if act.route_type == 'member' && [:button, :modal].include?(act.display_type)}
37
+ - if custom_actions.any? || edit_action.any?
38
+ td.row-action-cell
39
+ .row-action-tool
40
+ button.secondary-btn.tool-btn type="button"
41
+ span
42
+ i.fa.fa-bars.bolder
43
+ span
44
+ i.fa.fa-angle-down
45
+ .popup-card.table-export-popup.hidden
46
+ - if edit_action.any?
47
+ = link_to "#{page_url('edit', ar_object)}" do
48
+ .popup-option Edit
49
+ - custom_actions.each do |custom_action|
50
+ - if custom_action.display_if.call(ar_object)
51
+ = link_to custom_action.path.gsub(':id', ar_object.id.to_s), method: custom_action.verb do
52
+ .popup-option = custom_action.name.titleize
49
53
 
50
54
  .cm-pagination
51
55
  .cm-pagination__lhs Showing #{@ar_object.pagy.from} to #{@ar_object.pagy.to} out of #{@ar_object.pagy.count}
@@ -1,5 +1,6 @@
1
1
  ul.nav.nav-pills
2
2
  - @model.available_tabs.each do |nav_item|
3
- li.nav-item
4
- - nav_item_action_name = nav_item.custom_action.present? ? nav_item.custom_action : 'show'
5
- = 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.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' : ''}"
@@ -20,9 +20,9 @@
20
20
  li
21
21
  .popup-option.pointer data-bs-toggle='modal' data-bs-target='#exportmodal'
22
22
  span Export
23
-
24
- a.primary-btn.ml-2 href="#{page_url('new')}"
25
- | Add
23
+ - new_action = @model.available_actions.select{|act| act if act.action_type.eql?(:default) && act.name.eql?('new')}
24
+ - if new_action.any?
25
+ = link_to 'Add', "#{page_url('new')}", class: 'primary-btn ml-2'
26
26
  - @model.available_actions.select{|act| act if act.route_type == 'collection'}.each do |custom_action|
27
27
  - if custom_action.display_type == :button
28
28
  = link_to custom_action.name.titleize, @model.ar_model.table_name + '/' + custom_action.path, class: 'primary-btn ml-2', method: custom_action.verb
@@ -37,5 +37,4 @@
37
37
 
38
38
  - edit_action = @model.available_actions.select{|act| act if act.action_type.eql?(:default) && act.name.eql?('edit')}
39
39
  - if edit_action.any?
40
- a.primary-btn.ml-2 href="#{page_url('edit', @ar_object)}"
41
- = "Edit #{@model.name}"
40
+ = link_to "Edit #{@model.name}", "#{page_url('edit', @ar_object)}", class: 'primary-btn ml-2'
@@ -1,6 +1,6 @@
1
1
  .cm-index-page
2
2
  .index-page
3
- .index-page__table-container.pt-0
3
+ .index-page__table-container
4
4
  == render partial: 'cm_admin/main/associated_table'
5
5
 
6
6
  // = column_pop_up(@associated_model)
@@ -2,11 +2,14 @@
2
2
  .index-page.page-container
3
3
  .sticky-container
4
4
  == render 'cm_admin/main/top_navbar'
5
- - if @model.filters.present?
5
+ - if @model.filters.present? && @action.partial.nil?
6
6
  .index-page__filters
7
7
  == render partial: 'cm_admin/main/filters', locals: { filters: @model.filters }
8
8
  .index-page__table-container
9
- == render 'cm_admin/main/table'
9
+ - if @action.partial
10
+ == render @action.partial
11
+ - else
12
+ == render 'cm_admin/main/table'
10
13
 
11
14
  = column_pop_up(@model)
12
15
  = manage_column_pop_up(@model)
@@ -0,0 +1 @@
1
+ | Dashboard section
@@ -0,0 +1,4 @@
1
+ main.flex-shrink-0
2
+ .container
3
+ h1.mt-5 403
4
+ p.lead You do not have permission to access this page.
data/cm_admin.gemspec CHANGED
@@ -31,4 +31,5 @@ Gem::Specification.new do |spec|
31
31
  spec.add_runtime_dependency 'webpacker', '~> 5.2.1'
32
32
  spec.add_runtime_dependency 'axlsx_rails', '~> 0.6.1'
33
33
  spec.add_runtime_dependency 'cocoon', '~> 1.2.15'
34
+ spec.add_runtime_dependency 'pundit', '~> 2.2.0'
34
35
  end
@@ -2,7 +2,7 @@ ActiveSupport.on_load(:active_record) do
2
2
  module ActiveRecord
3
3
  class Base
4
4
  def self.cm_admin(&block)
5
- CmAdmin.config(self, &block)
5
+ CmAdmin.initialize_model(self, &block)
6
6
  end
7
7
  end
8
8
  end
data/config/routes.rb CHANGED
@@ -9,7 +9,7 @@ CmAdmin::Engine.routes.draw do
9
9
  end
10
10
 
11
11
  # Defining action routes for each model
12
- CmAdmin.cm_admin_models.each do |model|
12
+ CmAdmin.config.cm_admin_models.each do |model|
13
13
  model.available_actions.sort_by {|act| act.class}.each do |act|
14
14
  scope model.name.tableize do
15
15
  send(act.verb, act.path.present? ? act.path : act.name, to: "#{model.name.underscore}##{act.name}", as: "#{model.name.underscore}_#{act.name}")
@@ -0,0 +1,10 @@
1
+ module CmAdmin
2
+ class Configuration
3
+ attr_accessor :layout, :included_models, :cm_admin_models
4
+
5
+ def initialize
6
+ @included_models = []
7
+ @cm_admin_models = []
8
+ end
9
+ end
10
+ end
@@ -14,6 +14,7 @@ require_relative 'models/controller_method'
14
14
  require 'pagy'
15
15
  require 'axlsx'
16
16
  require 'cocoon'
17
+ require 'pundit'
17
18
 
18
19
  module CmAdmin
19
20
  class Model
@@ -21,7 +22,8 @@ module CmAdmin
21
22
  include Models::Blocks
22
23
  include Models::DslMethod
23
24
  include Models::ControllerMethod
24
- attr_accessor :available_actions, :actions_set, :available_fields, :permitted_fields, :current_action, :params, :filters, :available_tabs
25
+ attr_accessor :available_actions, :actions_set, :available_fields, :permitted_fields,
26
+ :current_action, :params, :filters, :available_tabs, :icon_name
25
27
  attr_reader :name, :ar_model, :is_visible_on_sidebar
26
28
 
27
29
  # Class variable for storing all actions
@@ -32,6 +34,7 @@ module CmAdmin
32
34
  @name = entity.name
33
35
  @ar_model = entity
34
36
  @is_visible_on_sidebar = true
37
+ @icon_name = 'fa fa-th-large'
35
38
  @available_actions ||= []
36
39
  @current_action = nil
37
40
  @available_tabs ||= []
@@ -42,6 +45,7 @@ module CmAdmin
42
45
  actions unless @actions_set
43
46
  $available_actions = @available_actions.dup
44
47
  self.class.all_actions.push(@available_actions)
48
+ define_policy
45
49
  define_controller
46
50
  end
47
51
 
@@ -51,7 +55,7 @@ module CmAdmin
51
55
  end
52
56
 
53
57
  def find_by(search_hash)
54
- CmAdmin.cm_admin_models.find { |x| x.name == search_hash[:name] }
58
+ CmAdmin.config.cm_admin_models.find { |x| x.name == search_hash[:name] }
55
59
  end
56
60
  end
57
61
 
@@ -59,7 +63,7 @@ module CmAdmin
59
63
  current_action = CmAdmin::Models::Action.find_by(self, name: action_name.to_s)
60
64
  if current_action
61
65
  @current_action = current_action
62
- @ar_object = @ar_model.find(params[:id])
66
+ @ar_object = @ar_model.name.classify.constantize.find(params[:id])
63
67
  if @current_action.child_records
64
68
  child_records = @ar_object.send(@current_action.child_records)
65
69
  @associated_model = CmAdmin::Model.find_by(name: @ar_model.reflect_on_association(@current_action.child_records).klass.name)
@@ -90,13 +94,37 @@ module CmAdmin
90
94
  @is_visible_on_sidebar = visible_option
91
95
  end
92
96
 
97
+ def set_icon(name)
98
+ @icon_name = name
99
+ end
100
+
93
101
 
94
102
  private
95
103
 
104
+ def define_policy
105
+ klass = Class.new(ApplicationPolicy) do
106
+ def initialize(user, record)
107
+ @user = user
108
+ @record = record
109
+ end
110
+
111
+ $available_actions.each do |action|
112
+ define_method :"#{action.name}?" do
113
+ accessible_by = action.accessible_by.map { |role| "user.#{role}" }.join(' || ')
114
+ eval(accessible_by)
115
+ end
116
+ end
117
+ end
118
+ CmAdmin.const_set "#{@name}Policy", klass
119
+ end
120
+
96
121
  # Controller defined for each model
97
122
  # If model is User, controller will be UsersController
98
123
  def define_controller
99
124
  klass = Class.new(CmAdmin::ApplicationController) do
125
+ include Pundit::Authorization
126
+ rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
127
+
100
128
  $available_actions.each do |action|
101
129
  define_method action.name.to_sym do
102
130
 
@@ -107,6 +135,7 @@ module CmAdmin
107
135
  @model.current_action = @action
108
136
  @ar_object = @model.try(@action.parent || action_name, params)
109
137
  @ar_object, @associated_model, @associated_ar_object = @model.custom_controller_action(action_name, params.permit!) if !@ar_object.present? && params[:id].present?
138
+ authorize controller_name.classify.constantize, policy_class: "CmAdmin::#{controller_name.classify}Policy".constantize
110
139
  aar_model = request.url.split('/')[-2].classify.constantize if params[:aar_id]
111
140
  @associated_ar_object = aar_model.find(params[:aar_id]) if params[:aar_id]
112
141
  nested_tables = @model.available_fields[:new].except(:fields).keys
@@ -141,7 +170,7 @@ module CmAdmin
141
170
  format.html { render action.partial }
142
171
  else
143
172
  if @action.code_block.call(@ar_object)
144
- redirect_url = @action.redirection_url || request.referrer || "/cm_admin/#{@model.ar_model.table_name}/#{@ar_object.id}"
173
+ redirect_url = @model.current_action.redirection_url || @action.redirection_url || request.referrer || "/cm_admin/#{@model.ar_model.table_name}/#{@ar_object.id}"
145
174
  format.html { redirect_to redirect_url }
146
175
  else
147
176
  format.html { redirect_to request.referrer }
@@ -157,6 +186,12 @@ module CmAdmin
157
186
  end
158
187
  end
159
188
  end
189
+ private
190
+
191
+ def user_not_authorized
192
+ flash[:alert] = 'You are not authorized to perform this action.'
193
+ redirect_to CmAdmin::Engine.mount_path + '/access-denied'
194
+ end
160
195
  end if $available_actions.present?
161
196
  CmAdmin.const_set "#{@name}Controller", klass
162
197
  end
@@ -6,7 +6,7 @@ module CmAdmin
6
6
  include Actions::Blocks
7
7
  attr_accessor :name, :verb, :layout_type, :layout, :partial, :path, :page_title, :page_description,
8
8
  :child_records, :is_nested_field, :nested_table_name, :parent, :display_if, :route_type, :code_block,
9
- :display_type, :action_type, :redirection_url, :sort_direction, :sort_column
9
+ :display_type, :action_type, :redirection_url, :sort_direction, :sort_column, :accessible_by
10
10
 
11
11
  VALID_SORT_DIRECTION = Set[:asc, :desc].freeze
12
12
 
@@ -34,6 +34,14 @@ module CmAdmin
34
34
  self.action_type = :default
35
35
  self.sort_column = :created_at
36
36
  self.sort_direction = :desc
37
+ self.accessible_by = CmAdmin.authorized_roles
38
+ end
39
+
40
+ def set_values(page_title, page_description, partial, accessible_by)
41
+ self.page_title = page_title
42
+ self.page_description = page_description
43
+ self.partial = partial
44
+ self.accessible_by = (CmAdmin.authorized_roles.dup << accessible_by).flatten.compact.uniq if accessible_by
37
45
  end
38
46
 
39
47
  class << self
@@ -5,7 +5,7 @@ module CmAdmin
5
5
 
6
6
  def show(params)
7
7
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
8
- @ar_object = @ar_model.find(params[:id])
8
+ @ar_object = @ar_model.name.classify.constantize.find(params[:id])
9
9
  end
10
10
 
11
11
  def index(params)
@@ -21,11 +21,11 @@ module CmAdmin
21
21
 
22
22
  def edit(params)
23
23
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'edit')
24
- @ar_object = @ar_model.find(params[:id])
24
+ @ar_object = @ar_model.name.classify.constantize.find(params[:id])
25
25
  end
26
26
 
27
27
  def update(params)
28
- @ar_object = @ar_model.find(params[:id])
28
+ @ar_object = @ar_model.name.classify.constantize.find(params[:id])
29
29
  @ar_object.assign_attributes(resource_params(params))
30
30
  @ar_object
31
31
  end
@@ -10,32 +10,28 @@ module CmAdmin
10
10
  # @current_action = CmAdmin::Models::CustomAction.find_by(self, name: name)
11
11
  end
12
12
 
13
- def cm_index(page_title: nil ,page_description: nil, &block)
13
+ def cm_index(page_title: nil, page_description: nil, partial: nil, accessible_by: nil, &block)
14
14
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'index')
15
- @current_action.page_title = page_title
16
- @current_action.page_description = page_description
15
+ @current_action.set_values(page_title, page_description, partial, accessible_by)
17
16
  yield
18
17
  # action.instance_eval(&block)
19
18
  end
20
19
 
21
- def cm_show(page_title: nil,page_description: nil,&block)
20
+ def cm_show(page_title: nil, page_description: nil, partial: nil, accessible_by: nil, &block)
22
21
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
23
- @current_action.page_title = page_title
24
- @current_action.page_description = page_description
22
+ @current_action.set_values(page_title, page_description, partial, accessible_by)
25
23
  yield
26
24
  end
27
25
 
28
- def cm_edit(page_title: nil,page_description: nil, &block)
26
+ def cm_edit(page_title: nil,page_description: nil, partial: nil, accessible_by: nil, &block)
29
27
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'edit')
30
- @current_action.page_title = page_title
31
- @current_action.page_description = page_description
28
+ @current_action.set_values(page_title, page_description, partial, accessible_by)
32
29
  yield
33
30
  end
34
31
 
35
- def cm_new(page_title: nil,page_description: nil,&block)
32
+ def cm_new(page_title: nil,page_description: nil, partial: nil, accessible_by: nil, &block)
36
33
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'new')
37
- @current_action.page_title = page_title
38
- @current_action.page_description = page_description
34
+ @current_action.set_values(page_title, page_description, partial, accessible_by)
39
35
  yield
40
36
  end
41
37
 
@@ -51,14 +47,16 @@ module CmAdmin
51
47
  end
52
48
  end
53
49
 
54
- def tab(tab_name, custom_action, associated_model: nil, layout_type: nil, layout: nil, partial: nil, &block)
50
+ def tab(tab_name, custom_action, associated_model: nil, layout_type: nil, layout: nil, partial: nil, accessible_by: nil, &block)
55
51
  if custom_action.to_s == ''
56
52
  @current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
53
+ @current_action.accessible_by = (CmAdmin.authorized_roles.dup << accessible_by).flatten.compact.uniq if accessible_by
57
54
  @available_tabs << CmAdmin::Models::Tab.new(tab_name, '', &block)
58
55
  else
59
56
  action = CmAdmin::Models::Action.new(name: custom_action.to_s, verb: :get, path: ':id/'+custom_action,
60
57
  layout_type: layout_type, layout: layout, partial: partial, child_records: associated_model,
61
58
  action_type: :custom, display_type: :page)
59
+ action.accessible_by = (CmAdmin.authorized_roles.dup << accessible_by).flatten.compact.uniq if accessible_by
62
60
  @available_actions << action
63
61
  @current_action = action
64
62
  @available_tabs << CmAdmin::Models::Tab.new(tab_name, custom_action, &block)
@@ -119,11 +117,12 @@ module CmAdmin
119
117
  # end
120
118
  # end
121
119
  # end
122
- def custom_action(name: nil, verb: nil, layout: nil, layout_type: nil, partial: nil, path: nil, display_type: nil, display_if: lambda { |arg| return true }, route_type: nil, &block)
120
+ def custom_action(name: nil, verb: nil, layout: nil, layout_type: nil, partial: nil, path: nil, display_type: nil, display_if: lambda { |arg| return true }, route_type: nil, accessible_by: nil, &block)
123
121
  action = CmAdmin::Models::CustomAction.new(
124
122
  name: name, verb: verb, layout: layout, layout_type: layout_type, partial: partial, path: path,
125
123
  parent: self.current_action.name, display_type: display_type, display_if: display_if,
126
124
  action_type: :custom, route_type: route_type, &block)
125
+ action.accessible_by = (CmAdmin.authorized_roles.dup << accessible_by).flatten.compact.uniq if accessible_by
127
126
  @available_actions << action
128
127
  # self.class.class_eval(&block)
129
128
  end
@@ -2,7 +2,8 @@ module CmAdmin
2
2
  module Models
3
3
  class Field
4
4
 
5
- attr_accessor :field_name, :label, :header, :field_type, :format, :precision, :helper_method, :preview, :custom_link, :precision
5
+ attr_accessor :field_name, :label, :header, :field_type, :format, :precision,
6
+ :helper_method, :preview, :custom_link, :precision, :prefix, :suffix
6
7
 
7
8
  def initialize(field_name, attributes = {})
8
9
  @field_name = field_name
@@ -1,3 +1,3 @@
1
1
  module CmAdmin
2
- VERSION = "0.5.6"
2
+ VERSION = "0.5.9"
3
3
  end
@@ -5,7 +5,7 @@ module CmAdmin
5
5
  def show_field(ar_object, field)
6
6
  content_tag(:div, class: "info-split") do
7
7
  concat show_field_label(ar_object, field)
8
- concat show_field_value(ar_object, field)
8
+ concat value_with_prefix_and_suffix(ar_object, field)
9
9
  end
10
10
  end
11
11
 
@@ -14,9 +14,18 @@ module CmAdmin
14
14
  p = field.label.present? ? field.label.to_s : field.field_name.to_s.titleize
15
15
  end
16
16
  end
17
-
18
- def show_field_value(ar_object, field)
17
+
18
+ def value_with_prefix_and_suffix(ar_object, field)
19
+ value = show_field_value(ar_object, field)
19
20
  content_tag(:div, class: "info-split__rhs") do
21
+ concat field.prefix
22
+ concat value
23
+ concat field.suffix
24
+ end
25
+ end
26
+
27
+ def show_field_value(ar_object, field)
28
+ content_tag(:span) do
20
29
  case field.field_type || :string
21
30
  when :integer
22
31
  ar_object.send(field.field_name).to_s
@@ -43,14 +52,14 @@ module CmAdmin
43
52
  ar_object.send(field.field_name).to_s.titleize
44
53
  when :tag
45
54
  content_tag :span, class: "status-tag default-#{ar_object.send(field.field_name.to_s + '_before_type_cast')}" do
46
- ar_object.send(field.field_name).to_s.titleize
55
+ ar_object.send(field.field_name).to_s.upcase
47
56
  end
48
57
  when :attachment
49
58
  concat show_attachment_value(ar_object, field)
50
59
  when :drawer
51
60
  content_tag :span do
52
61
  concat content_tag(:span, truncate(ar_object.send(field.field_name).to_s, length: 25))
53
- concat content_tag(:a, " View", class: "drawer-btn")
62
+ concat content_tag(:span, 'View', class: 'drawer-btn')
54
63
  end
55
64
  end
56
65
  end
@@ -60,12 +69,12 @@ module CmAdmin
60
69
  if ar_object.send(field.field_name).attached?
61
70
  if ar_object.send(field.field_name).class.name.include?('One')
62
71
  content_tag :a, href: rails_blob_path(ar_object.send(field.field_name), disposition: "attachment") do
63
- ar_object.send(field.field_name).filename.to_s
72
+ ar_object.send(field.field_name).filename.to_s
64
73
  end
65
74
  elsif ar_object.send(field.field_name).class.name.include?('Many')
66
75
  ar_object.send(field.field_name).map do |asset|
67
76
  content_tag :a, href: rails_blob_path(asset, disposition: "attachment") do
68
- asset.filename.to_s
77
+ asset.filename.to_s
69
78
  end
70
79
  end.join("\n").html_safe
71
80
  end
@@ -44,12 +44,14 @@ module CmAdmin
44
44
  if field.input_type.eql?(:hidden)
45
45
  concat input_field_for_column(f, field)
46
46
  else
47
- concat f.label field.label, class: 'field-label'
48
- concat tag.br
49
- concat(content_tag(:div, class: "datetime-wrapper") do
50
- concat input_field_for_column(f, field)
47
+ concat(content_tag(:div, class: "input-wrapper #{field.disabled ? 'disabled' : ''}") do
48
+ concat f.label field.label, field.label, class: "field-label"
49
+ concat tag.br
50
+ concat(content_tag(:div, class: "datetime-wrapper") do
51
+ concat input_field_for_column(f, field)
52
+ end)
53
+ concat tag.p resource.errors[field.field_name].first if resource.errors[field.field_name].present?
51
54
  end)
52
- concat tag.p resource.errors[field.field_name].first if resource.errors[field.field_name].present?
53
55
  end
54
56
  end
55
57
  else
@@ -4,26 +4,28 @@ module CmAdmin
4
4
  module NavigationHelper
5
5
  include Pagy::Frontend
6
6
  def navigation_links(navigation_type)
7
- CmAdmin.cm_admin_models.map { |model|
7
+ CmAdmin.config.cm_admin_models.map { |model|
8
8
  if model.is_visible_on_sidebar
9
9
  path = CmAdmin::Engine.mount_path + '/' + model.name.underscore.pluralize
10
- if navigation_type == "sidebar"
11
- content_tag(:a, href: path) do
12
- content_tag(:div, class: 'menu-item') do
13
- content_tag(:span, class: 'menu-icon') do
14
- concat tag.i class: 'fa fa-th-large'
15
- end +
16
- model.name
10
+ if policy([:cm_admin, model.name.classify.constantize]).index?
11
+ if navigation_type == "sidebar"
12
+ content_tag(:a, href: path) do
13
+ content_tag(:div, class: 'menu-item') do
14
+ content_tag(:span, class: 'menu-icon') do
15
+ concat tag.i class: "#{model.icon_name}"
16
+ end +
17
+ model.name.pluralize
18
+ end
17
19
  end
18
- end
19
- elsif navigation_type == "quick_links"
20
- content_tag(:a, href: path, class: 'visible') do
21
- content_tag(:div, class: 'result-item') do
22
- content_tag(:span) do
23
- concat tag.i class: 'fa fa-th-large'
24
- end +
25
- content_tag(:span) do
26
- model.name
20
+ elsif navigation_type == "quick_links"
21
+ content_tag(:a, href: path, class: 'visible') do
22
+ content_tag(:div, class: 'result-item') do
23
+ content_tag(:span) do
24
+ concat tag.i class: "#{model.icon_name}"
25
+ end +
26
+ content_tag(:span) do
27
+ model.name
28
+ end
27
29
  end
28
30
  end
29
31
  end
@@ -15,8 +15,6 @@ module CmAdmin
15
15
  case action_name
16
16
  when 'index'
17
17
  title + " list record"
18
- when 'show'
19
- title + " detail"
20
18
  when 'new'
21
19
  title + " create record"
22
20
  when 'edit'
@@ -36,8 +34,6 @@ module CmAdmin
36
34
  case action_name
37
35
  when 'index'
38
36
  title + " list record"
39
- when 'show'
40
- title + " detail"
41
37
  when 'new'
42
38
  title + " new record"
43
39
  when 'edit'
data/lib/cm_admin.rb CHANGED
@@ -4,14 +4,17 @@ require 'cm_admin/engine'
4
4
  require 'cm_admin/model'
5
5
  require 'cm_admin/view_helpers'
6
6
  require 'cm_admin/utils'
7
+ require 'cm_admin/configuration'
7
8
 
8
9
  module CmAdmin
9
10
  class Error < StandardError; end
10
11
 
11
- mattr_accessor :layout
12
+ mattr_accessor :layout, :authorized_roles
12
13
  mattr_accessor :included_models, :cm_admin_models
14
+ @@authorized_roles ||= []
13
15
  @@included_models ||= []
14
16
  @@cm_admin_models ||= []
17
+
15
18
 
16
19
  class << self
17
20
  def webpacker
@@ -21,15 +24,18 @@ module CmAdmin
21
24
  )
22
25
  end
23
26
 
24
- def setup
25
- yield self
27
+ def configure(&block)
28
+ instance_eval(&block)
26
29
  end
27
30
 
28
- def config(entity, &block)
31
+ def config
32
+ @config ||= Configuration.new
33
+ end
34
+
35
+ def initialize_model(entity, &block)
29
36
  if entity.is_a?(Class)
30
- unless CmAdmin::Model.find_by({name: entity.name})
31
- @@cm_admin_models << CmAdmin::Model.new(entity, &block)
32
- end
37
+ return if CmAdmin::Model.find_by({name: entity.name})
38
+ config.cm_admin_models << CmAdmin::Model.new(entity, &block)
33
39
  end
34
40
  end
35
41
  end
@@ -1,26 +1,16 @@
1
1
  require 'rails/generators'
2
2
 
3
- def add_required_gems
4
- gem 'slim'
5
- gem 'simple_form'
6
- system("yarn add bootstrap")
7
- system("yarn add @fortawesome/fontawesome-free")
8
- system("yarn add select2")
9
- system("yarn add daterangepicker")
10
- system("yarn add jgrowl")
11
- end
12
-
13
- def copy_layout_file
14
- copy_file "layouts/_side_navbar.html.slim", "app/views/layouts/_side_navbar.html.slim"
15
- copy_file "layouts/_navbar.html.slim", "app/views/layouts/_navbar.html.slim"
16
- remove_file "app/views/layouts/application.html.erb"
17
- copy_file "layouts/application.html.slim", "app/views/layouts/application.html.slim"
18
- end
3
+ module CmAdmin
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('templates', __dir__)
19
7
 
20
- def copy_asset_file
21
- copy_file "assets/images/cm.png", "app/assets/images/cm.png"
22
- directory "assets/stylesheets/", "app/assets/stylesheets/"
23
- remove_file "app/assets/stylesheets/application.css"
8
+ def copy_initializer
9
+ copy_file 'cm_admin_initializer.rb', 'config/initializers/cm_admin.rb'
10
+ copy_file 'custom.js', 'app/assets/javascripts/custom.js'
11
+ copy_file 'custom.css', 'app/assets/stylesheets/custom.css'
12
+ route 'mount CmAdmin::Engine => "/admin"'
13
+ end
24
14
  end
25
15
  end
26
- end
16
+ end
@@ -0,0 +1,4 @@
1
+ CmAdmin.setup do |config|
2
+ # Sets the default layout to be used for admin
3
+ config.layout = 'admin'
4
+ end
File without changes
File without changes
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cm-admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.6
4
+ version: 0.5.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - sajinmp
8
8
  - anbublacky
9
9
  - AdityaTiwari2102
10
- autorequire:
10
+ autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2022-03-02 00:00:00.000000000 Z
13
+ date: 2022-03-24 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: pagy
@@ -82,6 +82,20 @@ dependencies:
82
82
  - - "~>"
83
83
  - !ruby/object:Gem::Version
84
84
  version: 1.2.15
85
+ - !ruby/object:Gem::Dependency
86
+ name: pundit
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: 2.2.0
92
+ type: :runtime
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - "~>"
97
+ - !ruby/object:Gem::Version
98
+ version: 2.2.0
85
99
  description: This is an admin panel gem
86
100
  email:
87
101
  - sajinprasadkm@gmail.com
@@ -138,6 +152,7 @@ files:
138
152
  - app/javascript/packs/cm_admin/quick_search.js
139
153
  - app/javascript/packs/cm_admin/scaffolds.js
140
154
  - app/javascript/stylesheets/cm_admin/application.scss
155
+ - app/policies/application_policy.rb
141
156
  - app/views/cm_admin/main/_associated_table.html.slim
142
157
  - app/views/cm_admin/main/_cm_pagy_nav.html.slim
143
158
  - app/views/cm_admin/main/_drawer.html.slim
@@ -154,7 +169,9 @@ files:
154
169
  - app/views/cm_admin/main/index.html.slim
155
170
  - app/views/cm_admin/main/new.html.slim
156
171
  - app/views/cm_admin/main/show.html.slim
172
+ - app/views/cm_admin/static/dashboard.html.slim
157
173
  - app/views/cm_admin/static/error_401.html.slim
174
+ - app/views/cm_admin/static/error_403.html.slim
158
175
  - app/views/layouts/_custom_action_modals.html.slim
159
176
  - app/views/layouts/_flash_message.html.slim
160
177
  - app/views/layouts/_left_sidebar_nav.html.slim
@@ -176,6 +193,7 @@ files:
176
193
  - config/webpacker.yml
177
194
  - lib/.DS_Store
178
195
  - lib/cm_admin.rb
196
+ - lib/cm_admin/configuration.rb
179
197
  - lib/cm_admin/constants.rb
180
198
  - lib/cm_admin/engine.rb
181
199
  - lib/cm_admin/model.rb
@@ -204,6 +222,9 @@ files:
204
222
  - lib/cm_admin/view_helpers/navigation_helper.rb
205
223
  - lib/cm_admin/view_helpers/page_info_helper.rb
206
224
  - lib/generators/cm_admin/install_generator.rb
225
+ - lib/generators/cm_admin/templates/cm_admin_initializer.rb
226
+ - lib/generators/cm_admin/templates/custom.css
227
+ - lib/generators/cm_admin/templates/custom.js
207
228
  - lib/tasks/webpack_install.rake
208
229
  - package.json
209
230
  - postcss.config.js
@@ -215,7 +236,7 @@ licenses:
215
236
  metadata:
216
237
  homepage_uri: https://github.com/commutatus/cm-admin
217
238
  source_code_uri: https://github.com/commutatus/cm-admin
218
- post_install_message:
239
+ post_install_message:
219
240
  rdoc_options: []
220
241
  require_paths:
221
242
  - lib
@@ -230,8 +251,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
230
251
  - !ruby/object:Gem::Version
231
252
  version: '0'
232
253
  requirements: []
233
- rubygems_version: 3.0.3
234
- signing_key:
254
+ rubygems_version: 3.2.3
255
+ signing_key:
235
256
  specification_version: 4
236
257
  summary: This is an admin panel gem
237
258
  test_files: []