act_as_permission_controllable 0.1.0
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +212 -0
- data/Rakefile +33 -0
- data/app/views/act_as_permission_controllable/forbidden.html.erb +13 -0
- data/app/views/act_as_permission_controllable/permissions.html.erb +84 -0
- data/config/locales/en.yml +15 -0
- data/config/locales/zh_CN.yml +15 -0
- data/lib/act_as_permission_controllable.rb +8 -0
- data/lib/act_as_permission_controllable/ability.rb +18 -0
- data/lib/act_as_permission_controllable/act.rb +34 -0
- data/lib/act_as_permission_controllable/action.rb +35 -0
- data/lib/act_as_permission_controllable/controller.rb +90 -0
- data/lib/act_as_permission_controllable/helper.rb +15 -0
- data/lib/act_as_permission_controllable/i18n.rb +1 -0
- data/lib/act_as_permission_controllable/model.rb +93 -0
- data/lib/act_as_permission_controllable/railtie.rb +18 -0
- data/lib/act_as_permission_controllable/version.rb +3 -0
- data/lib/tasks/act_as_permission_controllable_tasks.rake +4 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b4379261968ca8f86b6ca67b33cf64c035320386
|
4
|
+
data.tar.gz: 40b729251abe3516f8d70d3e2873d6ff38785296
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 02e1a461c3171a6701efbdd49a4eca78e8808b1da050c8f2d2ca2d823f28f13dd9d3da041f0381a0312fffd87e32ce0b1b7443afc7e12c592c033351d51ea846
|
7
|
+
data.tar.gz: 39dead1069325510c18ab99d1439ee91d5b52fdd3a05e9c0b5aa84a2a94c8483829f5a9ba7b0512674b4c2d559201769d7b74ec15f8d83688ad4249db04bc80c
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2017 Cai Guanhao (Choi Goon-ho)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
# ActAsPermissionControllable
|
2
|
+
|
3
|
+
*Control user / admin permissions with cancancan.*
|
4
|
+
|
5
|
+
Easily integrate cancancan into your application with permission control of every controller action.
|
6
|
+
|
7
|
+

|
8
|
+
|
9
|
+
## Installation
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'act_as_permission_controllable'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
```bash
|
19
|
+
$ bundle
|
20
|
+
```
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
```bash
|
25
|
+
$ gem install act_as_permission_controllable
|
26
|
+
```
|
27
|
+
|
28
|
+
## Migration
|
29
|
+
Add a `permissions` JSONB field to your model:
|
30
|
+
|
31
|
+
```bash
|
32
|
+
rails g migration AddPermissionsToAdmins permissions:jsonb
|
33
|
+
```
|
34
|
+
|
35
|
+
Add `default: {}, nil: false`:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
class AddPermissionsToAdmins < ActiveRecord::Migration[5.1]
|
39
|
+
def change
|
40
|
+
add_column :admins, :permissions, :jsonb, default: {}, nil: false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
## Model
|
46
|
+
Add `act_as_permission_controllable` to your model:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
class Admin < ApplicationRecord
|
50
|
+
act_as_permission_controllable # methods added: ban, permit, assign_permissions, can?
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
Create `app/models/ability.rb`:
|
55
|
+
```ruby
|
56
|
+
class Ability
|
57
|
+
include ActAsPermissionControllable::Ability
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
## Controller
|
62
|
+
Add `grant_permission` to your base controller.
|
63
|
+
Controllers inherited from it will need authorization.
|
64
|
+
You can rescue from `CanCan::AccessDenied` error to show permission error message.
|
65
|
+
You also need to define `current_ability` for `cancancan` to work.
|
66
|
+
```ruby
|
67
|
+
class Admin::BaseController < ApplicationController
|
68
|
+
|
69
|
+
# ... other code ...
|
70
|
+
|
71
|
+
grant_permission
|
72
|
+
|
73
|
+
rescue_from CanCan::AccessDenied do |exception|
|
74
|
+
respond_to do |format|
|
75
|
+
format.json {
|
76
|
+
render json: { message: exception.message }, status: 403
|
77
|
+
}
|
78
|
+
format.html {
|
79
|
+
render 'act_as_permission_controllable/forbidden', layout: 'admin', status: 403, locals: { exception: exception }
|
80
|
+
}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def current_ability
|
87
|
+
@current_ability ||= Ability.new(current_admin)
|
88
|
+
end
|
89
|
+
|
90
|
+
# ... other code ...
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
If you don't want a controller to check user permission, use `skip_grant_permission`.
|
95
|
+
```ruby
|
96
|
+
class Admin::HomeController < Admin::BaseController
|
97
|
+
skip_grant_permission
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
101
|
+
If your controller has different index page:
|
102
|
+
```ruby
|
103
|
+
class Admin::AdminsController < Admin::BaseController
|
104
|
+
grant_permission index: :welcome
|
105
|
+
|
106
|
+
def welcome
|
107
|
+
end
|
108
|
+
end
|
109
|
+
```
|
110
|
+
|
111
|
+
To edit permissions on the web page, add actions to your routes:
|
112
|
+
```ruby
|
113
|
+
resources :admins do
|
114
|
+
member do
|
115
|
+
match :permissions, via: [ :get, :post ]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
```
|
119
|
+
|
120
|
+
And in your controller:
|
121
|
+
```ruby
|
122
|
+
class Admin::AdminsController < Admin::BaseController
|
123
|
+
# ... other code ...
|
124
|
+
|
125
|
+
def permissions
|
126
|
+
if request.post?
|
127
|
+
@admin.assign_permissions(params.fetch(:actions, []))
|
128
|
+
if @admin.save
|
129
|
+
flash[:notice] = 'OK!'
|
130
|
+
else
|
131
|
+
flash[:error] = 'ERROR!'
|
132
|
+
end
|
133
|
+
redirect_to params[:referer].presence || permissions_admin_admin_path(@admin)
|
134
|
+
return
|
135
|
+
end
|
136
|
+
|
137
|
+
render 'act_as_permission_controllable/permissions'
|
138
|
+
end
|
139
|
+
|
140
|
+
# ... other code ...
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
## View
|
145
|
+
You can use `controllable_nav_items` to list permitted pages for current user:
|
146
|
+
```erb
|
147
|
+
<ul class="nav navbar-nav">
|
148
|
+
<% controllable_nav_items do |item| %>
|
149
|
+
<%= content_tag :li, class: (name = item.controller_name) == controller.controller_name ? 'active' : nil do %>
|
150
|
+
<%= link_to item.i18n_name, (url_for(controller: name, action: item.index) rescue nil) %>
|
151
|
+
<% end %>
|
152
|
+
<% end %>
|
153
|
+
</ul>
|
154
|
+
```
|
155
|
+
|
156
|
+
## I18n
|
157
|
+
You can customize the names of each controller action and the order of each controller:
|
158
|
+
```yaml
|
159
|
+
# config/locales/aapc.en.yml
|
160
|
+
en:
|
161
|
+
act_as_permission_controllable:
|
162
|
+
order:
|
163
|
+
- Admin::OrdersController
|
164
|
+
- Admin::SettingsController
|
165
|
+
- Admin::AdminsController
|
166
|
+
controllers:
|
167
|
+
Admin::AdminsController: 'Admins'
|
168
|
+
Admin::OrdersController: 'Orders'
|
169
|
+
Admin::SettingsController: 'Settings'
|
170
|
+
actions:
|
171
|
+
Admin::AdminsController:
|
172
|
+
permissions: 'View and Set Permissions'
|
173
|
+
Admin::OrdersController:
|
174
|
+
export: 'Export Orders'
|
175
|
+
```
|
176
|
+
|
177
|
+
## Methods
|
178
|
+
### `ban(subject, *actions)` and `permit(subject, *actions)`
|
179
|
+
```ruby
|
180
|
+
# permit multiple actions of a controller
|
181
|
+
Admin.find(1).permit(:user, :create, :update, :destroy).save
|
182
|
+
|
183
|
+
# permit all actions in user controller
|
184
|
+
Admin.find(1).permit(:user, :all).save
|
185
|
+
|
186
|
+
# ban all except some permissions
|
187
|
+
Admin.find(1).ban(:all).permit(:settings, :update).save
|
188
|
+
|
189
|
+
# permit all except some permissions
|
190
|
+
Admin.find(1).permit(:all).ban(:admin, :permissions).save
|
191
|
+
|
192
|
+
# you can use controller class name as subject
|
193
|
+
Admin.find(1).ban(:all).permit('Admin::SettingsController', :update).save
|
194
|
+
```
|
195
|
+
|
196
|
+
### `can?(action, subject)`
|
197
|
+
```ruby
|
198
|
+
if current_admin.can?(:destroy, :user)
|
199
|
+
# admin can destroy user
|
200
|
+
end
|
201
|
+
```
|
202
|
+
|
203
|
+
## Example
|
204
|
+
You can run the app in `test/dummy` directory and visit `http://admin.localhost.com:3000`.
|
205
|
+
|
206
|
+
## Contributing
|
207
|
+
|
208
|
+
You can open issues or pull requests on [GitHub](https://github.com/caiguanhao/act_as_permission_controllable).
|
209
|
+
|
210
|
+
## License
|
211
|
+
|
212
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'ActAsPermissionControllable'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
require 'bundler/gem_tasks'
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'test'
|
28
|
+
t.pattern = 'test/**/*_test.rb'
|
29
|
+
t.verbose = false
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
task default: :test
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<h1 class="text-danger"><sub class="glyphicon glyphicon-exclamation-sign"></sub> <%= t('act_as_permission_controllable.views.forbidden') %></h1>
|
2
|
+
|
3
|
+
<h4><%= t('act_as_permission_controllable.views.forbidden_page') %></h4>
|
4
|
+
|
5
|
+
<% if can?(:permissions, :admin) %>
|
6
|
+
<hr>
|
7
|
+
<div class="pull-right">
|
8
|
+
<small><code><%= "Admin.find(#{current_admin.id}).permit!(:#{exception.subject}, :#{exception.action})" %></code></small>
|
9
|
+
</div>
|
10
|
+
<div>
|
11
|
+
<%= link_to t('act_as_permission_controllable.views.edit_permissions'), permissions_admin_admin_path(current_admin), class: 'btn btn-default' %>
|
12
|
+
</div>
|
13
|
+
<% end %>
|
@@ -0,0 +1,84 @@
|
|
1
|
+
<% can_update = can? :permissions, :admin %>
|
2
|
+
|
3
|
+
<%= form_tag permissions_admin_admin_path(@admin), method: :post do %>
|
4
|
+
<%= hidden_field_tag :referer, request.headers['Referer'] %>
|
5
|
+
<table class="table table-permissions" id="table-permissions">
|
6
|
+
<thead>
|
7
|
+
<tr>
|
8
|
+
<td colspan="5">
|
9
|
+
<%= submit_tag t('act_as_permission_controllable.views.update_permissions'),
|
10
|
+
class: 'btn btn-default pull-right', disabled: !can_update %>
|
11
|
+
<h4>
|
12
|
+
<%= t('act_as_permission_controllable.views.update_permissions') %>
|
13
|
+
<%= "(#{@admin.permission_count}/#{Admin.total_permission_count})" %>
|
14
|
+
<small>
|
15
|
+
<a class="toggle-checkboxes" href data-target="table-permissions">toggle</a>
|
16
|
+
</small>
|
17
|
+
</h4>
|
18
|
+
</td>
|
19
|
+
</tr>
|
20
|
+
</thead>
|
21
|
+
<tbody>
|
22
|
+
<% controllable_controllers.each_slice(5) do |slice| %>
|
23
|
+
<tr>
|
24
|
+
<% slice.each do |controller| %>
|
25
|
+
<td width="20%">
|
26
|
+
<strong>
|
27
|
+
<%= controller.i18n_name %>
|
28
|
+
</strong>
|
29
|
+
<small>
|
30
|
+
<a class="toggle-checkboxes" href data-target="checkboxes-<%= @cb = @cb.to_i + 1 %>">toggle</a>
|
31
|
+
</small>
|
32
|
+
<div class="checkboxes" id="checkboxes-<%= @cb %>">
|
33
|
+
<% controller.actions.each do |action| %>
|
34
|
+
<div class="checkbox">
|
35
|
+
<label>
|
36
|
+
<%= check_box_tag "actions[#{action.controller.to_s}][]", action,
|
37
|
+
action.permitted_in?(@admin.permissions), id: nil, disabled: !can_update %>
|
38
|
+
<%= action.i18n_name %>
|
39
|
+
</label>
|
40
|
+
</div>
|
41
|
+
<% end %>
|
42
|
+
</div>
|
43
|
+
</td>
|
44
|
+
<% end %>
|
45
|
+
</tr>
|
46
|
+
<% end %>
|
47
|
+
</tbody>
|
48
|
+
<tfoot>
|
49
|
+
<tr>
|
50
|
+
<td class="active" colspan="5">
|
51
|
+
<%= submit_tag t('act_as_permission_controllable.views.update_permissions'),
|
52
|
+
class: 'btn btn-default', disabled: !can_update %>
|
53
|
+
</td>
|
54
|
+
</tr>
|
55
|
+
</tfoot>
|
56
|
+
</table>
|
57
|
+
<% end %>
|
58
|
+
|
59
|
+
<script>
|
60
|
+
(function () {
|
61
|
+
document.addEventListener('click', function (e) {
|
62
|
+
if (/\btoggle-checkboxes\b/.test(e.target.className)) {
|
63
|
+
e.preventDefault();
|
64
|
+
var target = e.target.dataset.target;
|
65
|
+
if (!target) return;
|
66
|
+
var targetElement = document.getElementById(target);
|
67
|
+
if (!targetElement) return;
|
68
|
+
var cbs = targetElement.querySelectorAll('input[type="checkbox"]');
|
69
|
+
var i;
|
70
|
+
var length = cbs.length;
|
71
|
+
var allChecked = true;
|
72
|
+
for (i = 0; i < length; i++) {
|
73
|
+
if (!cbs[i].checked) {
|
74
|
+
allChecked = false;
|
75
|
+
break;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
for (i = 0; i < length; i++) {
|
79
|
+
cbs[i].checked = !allChecked;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}, false);
|
83
|
+
})();
|
84
|
+
</script>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
en:
|
2
|
+
act_as_permission_controllable:
|
3
|
+
views:
|
4
|
+
forbidden: Forbidden
|
5
|
+
forbidden_page: Sorry, you're not allowed to visit the page you requested.
|
6
|
+
edit_permissions: Edit Permissions
|
7
|
+
update_permissions: Update Permissions
|
8
|
+
actions:
|
9
|
+
new: 'New %{model}'
|
10
|
+
create: 'Create New %{model}'
|
11
|
+
index: '%{model} List'
|
12
|
+
show: '%{model} Details'
|
13
|
+
edit: 'Edit %{model}'
|
14
|
+
update: 'Update %{model}'
|
15
|
+
destroy: 'Delete %{model}'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
zh_CN:
|
2
|
+
act_as_permission_controllable:
|
3
|
+
views:
|
4
|
+
forbidden: 禁止访问
|
5
|
+
forbidden_page: 抱歉,管理员不允许你访问特定页面。
|
6
|
+
edit_permissions: 修改权限设置
|
7
|
+
update_permissions: 更新权限设置
|
8
|
+
actions:
|
9
|
+
new: '新建%{model}'
|
10
|
+
create: '创建%{model}'
|
11
|
+
index: '%{model}列表'
|
12
|
+
show: '%{model}详细页'
|
13
|
+
edit: '编辑%{model}'
|
14
|
+
update: '更改%{model}'
|
15
|
+
destroy: '删除%{model}'
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'act_as_permission_controllable/act'
|
2
|
+
require 'act_as_permission_controllable/ability'
|
3
|
+
require 'act_as_permission_controllable/action'
|
4
|
+
require 'act_as_permission_controllable/controller'
|
5
|
+
require 'act_as_permission_controllable/helper'
|
6
|
+
require 'act_as_permission_controllable/i18n'
|
7
|
+
require 'act_as_permission_controllable/railtie'
|
8
|
+
require 'cancancan'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ActAsPermissionControllable
|
2
|
+
module Ability
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
include CanCan::Ability
|
7
|
+
|
8
|
+
def initialize(user)
|
9
|
+
return if !user || !(Hash === user.permissions)
|
10
|
+
user.permissions.each do |controller_name, actions|
|
11
|
+
controller = controller_name.safe_constantize
|
12
|
+
next if controller.nil?
|
13
|
+
can actions.map(&:to_sym), controller.controller_name.singularize.to_sym
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'act_as_permission_controllable/model'
|
2
|
+
|
3
|
+
module ActAsPermissionControllable
|
4
|
+
module Act
|
5
|
+
module Model
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def act_as_permission_controllable
|
10
|
+
include ActAsPermissionControllable::Model
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Controller
|
16
|
+
extend ActiveSupport::Concern
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def grant_permission(options = {})
|
20
|
+
ActAsPermissionControllable::Controller.set(self, options.slice(:index))
|
21
|
+
|
22
|
+
def self.inherited(subclass)
|
23
|
+
ActAsPermissionControllable::Controller.set(subclass, {})
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def skip_grant_permission
|
29
|
+
ActAsPermissionControllable::Controller.remove(self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ActAsPermissionControllable
|
2
|
+
class Action
|
3
|
+
def self.actions_for_controller(controller)
|
4
|
+
controller.public_instance_methods(include_super = false).map { |action| self.new(action, controller) }
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(action, controller)
|
8
|
+
@action = action
|
9
|
+
@controller = controller
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
@action.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def controller
|
17
|
+
@controller
|
18
|
+
end
|
19
|
+
|
20
|
+
def permitted_in?(permission_hash)
|
21
|
+
actions = permission_hash[controller.to_s]
|
22
|
+
(Array === actions) && actions.map(&:to_s).include?(to_s)
|
23
|
+
end
|
24
|
+
|
25
|
+
def i18n_name
|
26
|
+
model = Controller.new(controller).i18n_name
|
27
|
+
defaults = [
|
28
|
+
:"act_as_permission_controllable.actions.#{to_s}",
|
29
|
+
to_s.titleize,
|
30
|
+
]
|
31
|
+
I18n.translate(:"act_as_permission_controllable.actions.#{controller.to_s}.#{to_s}",
|
32
|
+
model: model, default: defaults)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module ActAsPermissionControllable
|
2
|
+
class Controller
|
3
|
+
mattr_accessor :permission_controllable_controllers do
|
4
|
+
Hash.new
|
5
|
+
end
|
6
|
+
|
7
|
+
mattr_accessor :preload_controller do
|
8
|
+
-> {
|
9
|
+
if ::Rails.application.config.cache_classes != true
|
10
|
+
::Dir["#{::Rails.root}/app/controllers/**/*_controller.rb"].each do |file|
|
11
|
+
require file
|
12
|
+
end
|
13
|
+
end
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.set(controller, options)
|
18
|
+
if !self.permission_controllable_controllers[controller.to_s]
|
19
|
+
controller.authorize_resource(class: false) # cancancan
|
20
|
+
end
|
21
|
+
self.permission_controllable_controllers[controller.to_s] = options
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.remove(controller)
|
25
|
+
if self.permission_controllable_controllers[controller.to_s]
|
26
|
+
self.permission_controllable_controllers.delete(controller.to_s)
|
27
|
+
controller.skip_authorize_resource # cancancan
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.get_controllers(sorted: false)
|
32
|
+
self.preload_controller.call if Proc === self.preload_controller
|
33
|
+
|
34
|
+
controllers = self.permission_controllable_controllers.map { |controller, _|
|
35
|
+
self.new(controller)
|
36
|
+
}.select(&:controllable?)
|
37
|
+
|
38
|
+
if sorted
|
39
|
+
order = I18n.t('act_as_permission_controllable.order', default: [[]])
|
40
|
+
controllers = controllers.sort_by(&:controller_name).sort_by.with_index { |controller, i|
|
41
|
+
[ order.index(controller.to_s) || order.size, i ]
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
controllers
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(controller)
|
49
|
+
@controller = case controller
|
50
|
+
when Symbol then controller.to_s.safe_constantize
|
51
|
+
when String then controller.safe_constantize
|
52
|
+
else controller
|
53
|
+
end
|
54
|
+
@data = self.class.permission_controllable_controllers[@controller.to_s]
|
55
|
+
end
|
56
|
+
|
57
|
+
def nil?
|
58
|
+
@controller.nil?
|
59
|
+
end
|
60
|
+
|
61
|
+
def controllable?
|
62
|
+
!!@data && actions.present?
|
63
|
+
end
|
64
|
+
|
65
|
+
def controller_name
|
66
|
+
@controller.controller_name
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_s
|
70
|
+
@controller.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
def i18n_name
|
74
|
+
name = controller_name.singularize
|
75
|
+
defaults = [
|
76
|
+
:"activerecord.models.#{name}",
|
77
|
+
name.camelize,
|
78
|
+
]
|
79
|
+
I18n.translate(:"act_as_permission_controllable.controllers.#{to_s}", default: defaults)
|
80
|
+
end
|
81
|
+
|
82
|
+
def actions
|
83
|
+
Action.actions_for_controller(@controller)
|
84
|
+
end
|
85
|
+
|
86
|
+
def index
|
87
|
+
@data[:index].presence || :index
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActAsPermissionControllable
|
2
|
+
module Helper
|
3
|
+
def controllable_nav_items(user = current_admin, &block)
|
4
|
+
@_controllable_nav_items ||= controllable_controllers.select do |controller|
|
5
|
+
actions = user.permissions[controller.to_s]
|
6
|
+
actions && actions.map(&:to_s).include?(controller.index.to_s)
|
7
|
+
end
|
8
|
+
block_given? ? @_controllable_nav_items.each(&block) : @_controllable_nav_items
|
9
|
+
end
|
10
|
+
|
11
|
+
def controllable_controllers
|
12
|
+
@_controllable_controllers ||= Controller.get_controllers(sorted: true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
I18n.load_path += ::Dir[File.expand_path('../../../config/locales/*.yml', __FILE__)]
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module ActAsPermissionControllable
|
2
|
+
module Model
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def ban(subject, *actions)
|
7
|
+
control_permissions :ban, subject, *actions
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
def permit(subject, *actions)
|
12
|
+
control_permissions :permit, subject, *actions
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def assign_permissions(attributes)
|
17
|
+
return if !attributes.respond_to?(:each)
|
18
|
+
perms, controllers = {}, Controller.get_controllers.map { |c| [ c.to_s, c ] }.to_h
|
19
|
+
attributes.each do |name, actions|
|
20
|
+
next if !(Array === actions)
|
21
|
+
next if (controller = controllers[name.to_s]).nil?
|
22
|
+
perms[name.to_s] = controller.actions.map(&:to_s) & actions.map(&:to_s)
|
23
|
+
end
|
24
|
+
self.permissions = perms
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.total_permission_count
|
28
|
+
Controller.get_controllers.sum { |controller| controller.actions.size }
|
29
|
+
end
|
30
|
+
|
31
|
+
def permission_count
|
32
|
+
c = 0
|
33
|
+
Controller.get_controllers.each do |controller|
|
34
|
+
if actions = self.permissions[controller.to_s]
|
35
|
+
c += (controller.actions.map(&:to_s) & actions.map(&:to_s)).size
|
36
|
+
end
|
37
|
+
end
|
38
|
+
c
|
39
|
+
end
|
40
|
+
|
41
|
+
def can?(*args)
|
42
|
+
@current_ability ||= ::Ability.new(self)
|
43
|
+
@current_ability.can?(*args)
|
44
|
+
end
|
45
|
+
|
46
|
+
after_commit do
|
47
|
+
@current_ability = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def control_permissions(type, subject, *actions)
|
53
|
+
type = type.to_s
|
54
|
+
|
55
|
+
if subject == :all
|
56
|
+
Controller.get_controllers.each do |controller|
|
57
|
+
if type == 'permit'
|
58
|
+
self.permissions[controller.to_s] = controller.actions.map(&:to_s)
|
59
|
+
elsif type == 'ban'
|
60
|
+
self.permissions.delete(controller.to_s)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
return
|
64
|
+
end
|
65
|
+
|
66
|
+
subject = subject.to_s
|
67
|
+
controller = Controller.get_controllers.find do |controller|
|
68
|
+
name, key = controller.controller_name, controller.to_s
|
69
|
+
subject == key || subject == name || subject == name.singularize
|
70
|
+
end
|
71
|
+
|
72
|
+
return if controller.nil?
|
73
|
+
|
74
|
+
key = controller.to_s
|
75
|
+
self.permissions[key] ||= []
|
76
|
+
if actions == [ :all ]
|
77
|
+
actions = controller.actions.map(&:to_s)
|
78
|
+
else
|
79
|
+
actions = actions.flatten.map(&:to_s)
|
80
|
+
end
|
81
|
+
if type == 'permit'
|
82
|
+
self.permissions[key] += actions
|
83
|
+
elsif type == 'ban'
|
84
|
+
self.permissions[key] -= actions
|
85
|
+
end
|
86
|
+
self.permissions[key].uniq!
|
87
|
+
self.permissions.delete(key) if self.permissions[key].empty?
|
88
|
+
|
89
|
+
return
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ActAsImportable
|
2
|
+
class Railtie < ::Rails::Railtie
|
3
|
+
initializer "act_as_permission_controllable.active_record" do |app|
|
4
|
+
ActiveSupport.on_load :active_record do
|
5
|
+
ActiveRecord::Base.send :include, ActAsPermissionControllable::Act::Model
|
6
|
+
end
|
7
|
+
|
8
|
+
ActiveSupport.on_load :action_controller do
|
9
|
+
ActionController::Base.send :include, ActAsPermissionControllable::Act::Controller
|
10
|
+
ActionController::Base.append_view_path File.expand_path('../../../app/views', __FILE__)
|
11
|
+
end
|
12
|
+
|
13
|
+
ActiveSupport.on_load :action_view do
|
14
|
+
ActionView::Base.send :include, ActAsPermissionControllable::Helper
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: act_as_permission_controllable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cai Guanhao (Choi Goon-ho)
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-08-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 5.0.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '5.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 5.0.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: cancancan
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.10'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.10'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: pg
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.21.0
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.21.0
|
61
|
+
description: Easily integrate cancancan into your application with permission control
|
62
|
+
of every controller action.
|
63
|
+
email:
|
64
|
+
- caiguanhao@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- MIT-LICENSE
|
70
|
+
- README.md
|
71
|
+
- Rakefile
|
72
|
+
- app/views/act_as_permission_controllable/forbidden.html.erb
|
73
|
+
- app/views/act_as_permission_controllable/permissions.html.erb
|
74
|
+
- config/locales/en.yml
|
75
|
+
- config/locales/zh_CN.yml
|
76
|
+
- lib/act_as_permission_controllable.rb
|
77
|
+
- lib/act_as_permission_controllable/ability.rb
|
78
|
+
- lib/act_as_permission_controllable/act.rb
|
79
|
+
- lib/act_as_permission_controllable/action.rb
|
80
|
+
- lib/act_as_permission_controllable/controller.rb
|
81
|
+
- lib/act_as_permission_controllable/helper.rb
|
82
|
+
- lib/act_as_permission_controllable/i18n.rb
|
83
|
+
- lib/act_as_permission_controllable/model.rb
|
84
|
+
- lib/act_as_permission_controllable/railtie.rb
|
85
|
+
- lib/act_as_permission_controllable/version.rb
|
86
|
+
- lib/tasks/act_as_permission_controllable_tasks.rake
|
87
|
+
homepage: https://github.com/caiguanhao/act_as_permission_controllable
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.5.2
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Control user / admin permissions with cancancan.
|
111
|
+
test_files: []
|