act_as_permission_controllable 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![aapc](https://user-images.githubusercontent.com/1284703/29483144-bd8abd5a-84d2-11e7-99de-3741b727621c.png)
|
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: []
|