permitter 0.0.1
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.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
|