permitter 0.0.1
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.rdoc +302 -0
- data/Rakefile +32 -0
- data/lib/generators/permitter/permission/USAGE +5 -0
- data/lib/generators/permitter/permission/permission_generator.rb +16 -0
- data/lib/generators/permitter/permission/templates/permission.rb +22 -0
- data/lib/generators/permitter/permission/templates/permission_spec.rb +17 -0
- data/lib/permitter.rb +4 -0
- data/lib/permitter/controller_additions.rb +43 -0
- data/lib/permitter/exceptions.rb +17 -0
- data/lib/permitter/matchers.rb +11 -0
- data/lib/permitter/model_additions.rb +30 -0
- data/lib/permitter/permission.rb +72 -0
- data/lib/permitter/version.rb +3 -0
- data/spec/README.rdoc +21 -0
- data/spec/controllers/projects_controller_spec.rb +243 -0
- data/spec/controllers/users_controller_spec.rb +77 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +19 -0
- data/spec/dummy/app/controllers/projects_controller.rb +49 -0
- data/spec/dummy/app/controllers/users_controller.rb +17 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/permission.rb +26 -0
- data/spec/dummy/app/models/project.rb +3 -0
- data/spec/dummy/app/models/user.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/app/views/projects/edit.html.erb +0 -0
- data/spec/dummy/app/views/projects/index.html.erb +0 -0
- data/spec/dummy/app/views/projects/new.html.erb +0 -0
- data/spec/dummy/app/views/projects/show.html.erb +0 -0
- data/spec/dummy/app/views/users/index.html.erb +0 -0
- data/spec/dummy/app/views/users/show.html.erb +0 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +23 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +59 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20131205175023_create_projects.rb +10 -0
- data/spec/dummy/db/migrate/20131205175100_create_users.rb +10 -0
- data/spec/dummy/db/migrate/20131210152022_add_columns_to_projects.rb +5 -0
- data/spec/dummy/db/schema.rb +31 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +825 -0
- data/spec/dummy/log/test.log +44662 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/project.rb +6 -0
- data/spec/factories/user.rb +10 -0
- data/spec/models/permission_spec.rb +72 -0
- data/spec/permitter/controller_additions_spec.rb +44 -0
- data/spec/permitter/exceptions_spec.rb +36 -0
- data/spec/permitter/matchers_spec.rb +9 -0
- data/spec/permitter/model_additions_spec.rb +138 -0
- data/spec/permitter/permission_spec.rb +84 -0
- data/spec/spec_helper.rb +32 -0
- metadata +278 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
module Permitter
|
2
|
+
class Unauthorized < StandardError
|
3
|
+
attr_reader :action, :subject
|
4
|
+
attr_writer :default_message
|
5
|
+
|
6
|
+
def initialize(message = nil, action = nil, subject = nil)
|
7
|
+
@message = message
|
8
|
+
@action = action
|
9
|
+
@subject = subject
|
10
|
+
@default_message = "You are not authorized to access this page."
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
@message || @default_message
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
RSpec::Matchers.define :allow_action do |*args|
|
2
|
+
match do |permission|
|
3
|
+
expect(permission.allowed_action?(*args)).to be true
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
RSpec::Matchers.define :allow_param do |*args|
|
8
|
+
match do |permission|
|
9
|
+
expect(permission.allowed_param?(*args)).to be true
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Permitter
|
2
|
+
module ModelAdditions
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
require 'squeel'
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def permitted_by(permissions, action = :show)
|
12
|
+
status = permissions.allow_all? ? true : permissions.allowed_action(self.table_name, action)
|
13
|
+
|
14
|
+
if status.class == Proc
|
15
|
+
where(&status)
|
16
|
+
else
|
17
|
+
status ? all : none
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if defined? ActiveRecord::Base
|
27
|
+
ActiveRecord::Base.class_eval do
|
28
|
+
include Permitter::ModelAdditions
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Permitter
|
2
|
+
module Permission
|
3
|
+
|
4
|
+
def allowed_action?(controller, action, resource = nil)
|
5
|
+
if allow_all?
|
6
|
+
true
|
7
|
+
elsif @allowed_actions
|
8
|
+
allowed = @allowed_actions[[controller.to_s, action.to_s]]
|
9
|
+
(allowed && (allowed == true || resource && allowed.call(resource))) == true
|
10
|
+
else
|
11
|
+
false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def allowed_param?(resource, attribute)
|
16
|
+
if allow_all?
|
17
|
+
true
|
18
|
+
elsif @allowed_params && @allowed_params[resource]
|
19
|
+
@allowed_params[resource].include? attribute
|
20
|
+
else
|
21
|
+
false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def allowed_action(controller, action)
|
26
|
+
if @allowed_actions
|
27
|
+
@allowed_actions[[controller.to_s, action.to_s]]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def allow_action(controllers, actions, &block)
|
32
|
+
@allowed_actions ||= {}
|
33
|
+
Array(controllers).flatten.each do |controller|
|
34
|
+
Array(actions).flatten.each do |action|
|
35
|
+
@allowed_actions[[controller.to_s, action.to_s]] = block || true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def allow_param(resources, attributes)
|
41
|
+
@allowed_params ||= {}
|
42
|
+
resource_array = Array(resources).flatten
|
43
|
+
attribute_array = Array(attributes).flatten
|
44
|
+
|
45
|
+
resource_array.each do |resource|
|
46
|
+
@allowed_params[resource] ||= []
|
47
|
+
@allowed_params[resource] += attribute_array
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def allow_all
|
52
|
+
@allow_all = true
|
53
|
+
end
|
54
|
+
|
55
|
+
def allow_all?
|
56
|
+
@allow_all ||= false
|
57
|
+
end
|
58
|
+
|
59
|
+
def permit_params!(params)
|
60
|
+
if @allow_all
|
61
|
+
params.permit!
|
62
|
+
elsif @allowed_params
|
63
|
+
@allowed_params.each do |resource, attributes|
|
64
|
+
if params[resource].respond_to? :permit
|
65
|
+
params[resource] = params[resource].permit(*attributes)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
data/spec/README.rdoc
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
= Permitter Specs
|
2
|
+
|
3
|
+
== Running the specs
|
4
|
+
|
5
|
+
To run the specs first run the +bundle+ command to install the necessary gems.
|
6
|
+
|
7
|
+
bundle
|
8
|
+
|
9
|
+
Then the migrations for the dummy app must be run. Move to the dummy app root and run the migrations.
|
10
|
+
|
11
|
+
cd spec/dummy
|
12
|
+
rake db:migrate
|
13
|
+
rake test:prepare
|
14
|
+
cd ../..
|
15
|
+
|
16
|
+
Finally, from the root of the gem, run the +rake+ command to run the specs.
|
17
|
+
|
18
|
+
rake
|
19
|
+
|
20
|
+
The specs currently require Ruby >= 1.9.3
|
21
|
+
They may or may not work with other Ruby versions.
|
@@ -0,0 +1,243 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ProjectsController do
|
4
|
+
before { @controller.stub(:current_user) { nil } }
|
5
|
+
let(:user) { build(:user) }
|
6
|
+
let(:user1) { create(:user) }
|
7
|
+
let(:user2) { create(:user) }
|
8
|
+
let(:admin) { build(:admin) }
|
9
|
+
let(:project) { create(:project) }
|
10
|
+
let(:project1) { create(:project, user: user1) }
|
11
|
+
let(:project2) { create(:project, user: user2) }
|
12
|
+
|
13
|
+
describe "GET #index" do
|
14
|
+
before { get :index }
|
15
|
+
|
16
|
+
it "responds successfully" do
|
17
|
+
expect(response).to be_success
|
18
|
+
expect(response.status).to eq(200)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "renders the index template" do
|
22
|
+
expect(response).to render_template("index")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "loads all of the projects into @projects" do
|
26
|
+
expect(assigns(:projects)).to eq(Project.all)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
describe "GET #show" do
|
32
|
+
before do
|
33
|
+
unless example.metadata[:skip_before]
|
34
|
+
@controller.stub(:current_user) { user }
|
35
|
+
get :show, id: project.id
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "responds unsuccessfully if user not signed in", skip_before: true do
|
40
|
+
get :show, id: project.id
|
41
|
+
expect(response).to_not be_success
|
42
|
+
expect(response.status).to eq(302)
|
43
|
+
expect(response).to redirect_to(projects_url)
|
44
|
+
expect(flash.alert).to eq("You are not authorized to access this page.")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "responds successfully if user signed in" do
|
48
|
+
expect(response).to be_success
|
49
|
+
expect(response.status).to eq(200)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "renders the show template" do
|
53
|
+
expect(response).to render_template("show")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "loads the project into @project" do
|
57
|
+
expect(assigns(:project)).to eq(project)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
describe "GET #new" do
|
63
|
+
before do
|
64
|
+
unless example.metadata[:skip_before]
|
65
|
+
@controller.stub(:current_user) { user }
|
66
|
+
get :new
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it "responds unsuccessfully if user not signed in", skip_before: true do
|
71
|
+
get :new
|
72
|
+
expect(response).to_not be_success
|
73
|
+
expect(response.status).to eq(302)
|
74
|
+
expect(response).to redirect_to(projects_url)
|
75
|
+
expect(flash.alert).to eq("You are not authorized to access this page.")
|
76
|
+
end
|
77
|
+
|
78
|
+
it "responds successfully if user signed in" do
|
79
|
+
expect(response).to be_success
|
80
|
+
expect(response.status).to eq(200)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "renders the new template" do
|
84
|
+
expect(response).to render_template("new")
|
85
|
+
end
|
86
|
+
|
87
|
+
it "builds a new project into @project" do
|
88
|
+
expect(assigns(:project)).to be_a_new(Project)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
describe "POST #create" do
|
94
|
+
let(:title) { 'Title' }
|
95
|
+
let(:sticky) { true }
|
96
|
+
before do
|
97
|
+
unless example.metadata[:skip_before]
|
98
|
+
@controller.stub(:current_user) { user }
|
99
|
+
post :create, project: {title: title, sticky: sticky}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it "responds unsuccessfully if user not signed in", skip_before: true do
|
104
|
+
post :create
|
105
|
+
expect(response.status).to eq(302)
|
106
|
+
expect(response).to redirect_to(projects_url)
|
107
|
+
expect(flash.alert).to eq("You are not authorized to access this page.")
|
108
|
+
end
|
109
|
+
|
110
|
+
it "responds successfully if user signed in" do
|
111
|
+
expect(response.status).to eq(302)
|
112
|
+
expect(response).to redirect_to(project_url(assigns(:project)))
|
113
|
+
expect(flash.notice).to eq("Project was successfully created.")
|
114
|
+
end
|
115
|
+
|
116
|
+
it "creates a new project" do
|
117
|
+
expect(assigns(:project)).to eq(Project.last)
|
118
|
+
end
|
119
|
+
|
120
|
+
it "does not assign sticky variable" do
|
121
|
+
expect(assigns(:project).title).to eq(title)
|
122
|
+
expect(assigns(:project).sticky).to be_nil
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
describe "GET #edit" do
|
128
|
+
before do
|
129
|
+
unless example.metadata[:skip_before]
|
130
|
+
@controller.stub(:current_user) { user1 }
|
131
|
+
get :edit, id: project1.id
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
it "responds unsuccessfully if user not signed in", skip_before: true do
|
136
|
+
get :edit, id: project.id
|
137
|
+
expect(response).to_not be_success
|
138
|
+
expect(response.status).to eq(302)
|
139
|
+
expect(response).to redirect_to(projects_url)
|
140
|
+
expect(flash.alert).to eq("You are not authorized to access this page.")
|
141
|
+
end
|
142
|
+
|
143
|
+
it "responds unsuccessfully if user not associated with project", skip_before: true do
|
144
|
+
@controller.stub(:current_user) { user1 }
|
145
|
+
get :edit, id: project2.id
|
146
|
+
expect(response).to_not be_success
|
147
|
+
expect(response.status).to eq(302)
|
148
|
+
expect(response).to redirect_to(projects_url)
|
149
|
+
expect(flash.alert).to eq("You are not authorized to access this page.")
|
150
|
+
end
|
151
|
+
|
152
|
+
it "responds successfully if user associated with project" do
|
153
|
+
expect(response.status).to eq(200)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "renders the edit template" do
|
157
|
+
expect(response).to render_template("edit")
|
158
|
+
end
|
159
|
+
|
160
|
+
it "loads the project into @project" do
|
161
|
+
expect(assigns(:project)).to eq(project1)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
describe "PATCH #update" do
|
167
|
+
let(:title) { 'Updated Title' }
|
168
|
+
let(:sticky) { true }
|
169
|
+
|
170
|
+
before do
|
171
|
+
unless example.metadata[:skip_before]
|
172
|
+
@controller.stub(:current_user) { user1 }
|
173
|
+
@original_title = project1.title
|
174
|
+
@original_sticky = project1.sticky
|
175
|
+
patch :update, id: project1.id, project: {title: title, sticky: sticky}
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it "responds unsuccessfully if user not signed in", skip_before: true do
|
180
|
+
patch :update, id: project.id
|
181
|
+
expect(response).to_not be_success
|
182
|
+
expect(response.status).to eq(302)
|
183
|
+
expect(response).to redirect_to(projects_url)
|
184
|
+
expect(flash.alert).to eq("You are not authorized to access this page.")
|
185
|
+
end
|
186
|
+
|
187
|
+
it "responds unsuccessfully if user not associated with project", skip_before: true do
|
188
|
+
@controller.stub(:current_user) { user1 }
|
189
|
+
patch :update, id: project2.id
|
190
|
+
expect(response).to_not be_success
|
191
|
+
expect(response.status).to eq(302)
|
192
|
+
expect(response).to redirect_to(projects_url)
|
193
|
+
expect(flash.alert).to eq("You are not authorized to access this page.")
|
194
|
+
end
|
195
|
+
|
196
|
+
it "responds successfully if user associated with project" do
|
197
|
+
expect(response.status).to eq(302)
|
198
|
+
expect(response).to redirect_to(project_url(assigns(:project)))
|
199
|
+
expect(flash.notice).to eq("Project was successfully updated.")
|
200
|
+
end
|
201
|
+
|
202
|
+
it "updates a project" do
|
203
|
+
expect(assigns(:project).title).to eq(title)
|
204
|
+
expect(assigns(:project).title).to_not eq(@original_title)
|
205
|
+
end
|
206
|
+
|
207
|
+
it "does not update sticky" do
|
208
|
+
expect(assigns(:project).sticky).to eq(@original_sticky)
|
209
|
+
expect(assigns(:project).sticky).to_not eq(sticky)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
describe "DELETE #destroy" do
|
215
|
+
|
216
|
+
it "responds unsuccessfully if user not signed in" do
|
217
|
+
delete :destroy, id: project.id
|
218
|
+
expect(flash.alert).to eq("You are not authorized to access this page.")
|
219
|
+
end
|
220
|
+
|
221
|
+
it "responds unsuccessfully if user not an admin" do
|
222
|
+
@controller.stub(:current_user) { user1 }
|
223
|
+
delete :destroy, id: project1.id
|
224
|
+
expect(flash.alert).to eq("You are not authorized to access this page.")
|
225
|
+
end
|
226
|
+
|
227
|
+
it "responds successfully if user an admin" do
|
228
|
+
@controller.stub(:current_user) { admin }
|
229
|
+
delete :destroy, id: project.id
|
230
|
+
expect(flash.alert).to be nil
|
231
|
+
end
|
232
|
+
|
233
|
+
it "destroys a project" do
|
234
|
+
expect(Project.all).to include(project)
|
235
|
+
|
236
|
+
@controller.stub(:current_user) { admin }
|
237
|
+
delete :destroy, id: project.id
|
238
|
+
expect(Project.all).to_not include(project)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe UsersController do
|
4
|
+
let(:user) { create(:user) }
|
5
|
+
let(:admin) { create(:admin) }
|
6
|
+
|
7
|
+
describe "GET #index" do
|
8
|
+
before do
|
9
|
+
unless example.metadata[:skip_before]
|
10
|
+
@controller.stub(:current_user) { user }
|
11
|
+
get :index
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "responds successfully" do
|
16
|
+
expect(response).to be_success
|
17
|
+
expect(response.status).to eq(200)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "renders the index template" do
|
21
|
+
expect(response).to render_template("index")
|
22
|
+
end
|
23
|
+
|
24
|
+
it "loads all of the users into @projects if admin", skip_before: true do
|
25
|
+
@controller.stub(:current_user) { admin }
|
26
|
+
get :index
|
27
|
+
expect(assigns(:users)).to eq(User.all)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "loads only current user into @projects if not admin" do
|
31
|
+
expect(assigns(:users)).to eq([user])
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
describe "GET #show" do
|
38
|
+
before do
|
39
|
+
unless example.metadata[:skip_before]
|
40
|
+
@controller.stub(:current_user) { user }
|
41
|
+
get :show, id: user.id
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "responds unsuccessfully if user not signed in", skip_before: true do
|
46
|
+
@controller.stub(:current_user) { nil }
|
47
|
+
get :show, id: user.id
|
48
|
+
expect(response).to_not be_success
|
49
|
+
expect(response.status).to eq(302)
|
50
|
+
expect(response).to redirect_to(projects_url)
|
51
|
+
expect(flash.alert).to eq("You are not authorized to access this page.")
|
52
|
+
end
|
53
|
+
|
54
|
+
it "responds unsuccessfully if user signed in and not current user", skip_before: true do
|
55
|
+
@controller.stub(:current_user) { user }
|
56
|
+
get :show, id: admin.id
|
57
|
+
expect(response).to_not be_success
|
58
|
+
expect(response.status).to eq(302)
|
59
|
+
expect(response).to redirect_to(projects_url)
|
60
|
+
expect(flash.alert).to eq("You are not authorized to access this page.")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "responds successfully if user signed in and current user" do
|
64
|
+
expect(response).to be_success
|
65
|
+
expect(response.status).to eq(200)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "renders the show template" do
|
69
|
+
expect(response).to render_template("show")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "loads the user into @user" do
|
73
|
+
expect(assigns(:user)).to eq(user)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|