g5_authenticatable 0.4.2 → 0.5.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 +4 -4
- data/.travis.yml +12 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +2 -2
- data/README.md +186 -1
- data/app/controllers/concerns/g5_authenticatable/authorization.rb +21 -0
- data/app/models/g5_authenticatable/role.rb +8 -0
- data/app/models/g5_authenticatable/user.rb +41 -0
- data/app/policies/g5_authenticatable/base_policy.rb +73 -0
- data/config/initializers/rolify.rb +8 -0
- data/g5_authenticatable.gemspec +3 -0
- data/lib/g5_authenticatable/engine.rb +3 -0
- data/lib/g5_authenticatable/rspec.rb +1 -0
- data/lib/g5_authenticatable/test/factory.rb +51 -1
- data/lib/g5_authenticatable/test/feature_helpers.rb +15 -2
- data/lib/g5_authenticatable/version.rb +1 -1
- data/lib/generators/g5_authenticatable/install/USAGE +7 -1
- data/lib/generators/g5_authenticatable/install/install_generator.rb +33 -6
- data/lib/generators/g5_authenticatable/install/templates/403.html +26 -0
- data/lib/generators/g5_authenticatable/install/templates/application_policy.rb +4 -0
- data/lib/generators/g5_authenticatable/install/templates/{g5_authenticatable.rb → initializer.rb} +0 -0
- data/lib/generators/g5_authenticatable/install/templates/migrate/add_g5_authenticatable_users_contact_info.rb +11 -0
- data/lib/generators/g5_authenticatable/install/templates/migrate/create_g5_authenticatable_roles.rb +20 -0
- data/lib/generators/g5_authenticatable/install/templates/{create_g5_authenticatable_users.rb → migrate/create_g5_authenticatable_users.rb} +0 -0
- data/spec/controllers/application_controller_spec.rb +12 -0
- data/spec/controllers/concerns/g5_authenticatable/authorization.rb +50 -0
- data/spec/dummy/app/assets/javascripts/posts.js +2 -0
- data/spec/dummy/app/assets/stylesheets/posts.css +4 -0
- data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/spec/dummy/app/controllers/application_controller.rb +1 -0
- data/spec/dummy/app/controllers/posts_controller.rb +74 -0
- data/spec/dummy/app/helpers/posts_helper.rb +2 -0
- data/spec/dummy/app/models/post.rb +3 -0
- data/spec/dummy/app/policies/application_policy.rb +4 -0
- data/spec/dummy/app/policies/post_policy.rb +4 -0
- data/spec/dummy/app/views/home/index.html.erb +40 -0
- data/spec/dummy/app/views/posts/_form.html.erb +21 -0
- data/spec/dummy/app/views/posts/edit.html.erb +6 -0
- data/spec/dummy/app/views/posts/index.html.erb +30 -0
- data/spec/dummy/app/views/posts/new.html.erb +5 -0
- data/spec/dummy/app/views/posts/show.html.erb +17 -0
- data/spec/dummy/config/database.yml.ci +1 -2
- data/spec/dummy/config/initializers/g5_authenticatable.rb +8 -0
- data/spec/dummy/config/routes.rb +2 -0
- data/spec/dummy/db/migrate/20150428182339_add_g5_authenticatable_users_contact_info.rb +11 -0
- data/spec/dummy/db/migrate/20150429212919_create_g5_authenticatable_roles.rb +20 -0
- data/spec/dummy/db/migrate/20150509061150_create_posts.rb +9 -0
- data/spec/dummy/db/schema.rb +37 -4
- data/spec/dummy/public/403.html +26 -0
- data/spec/factories/post.rb +6 -0
- data/spec/features/default_role_authorization_spec.rb +254 -0
- data/spec/features/sign_in_spec.rb +144 -8
- data/spec/lib/generators/g5_authenticatable/install_generator_spec.rb +72 -1
- data/spec/models/g5_authenticatable/role_spec.rb +81 -0
- data/spec/models/g5_authenticatable/user_spec.rb +340 -3
- data/spec/models/post_spec.rb +12 -0
- data/spec/policies/application_policy_spec.rb +171 -0
- data/spec/policies/post_policy_spec.rb +35 -0
- data/spec/requests/default_role_authorization_spec.rb +169 -0
- data/spec/spec_helper.rb +0 -3
- data/spec/support/shared_examples/super_admin_authorizer.rb +33 -0
- metadata +109 -5
- data/circle.yml +0 -4
@@ -0,0 +1,254 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Default role-based authorization UI' do
|
4
|
+
describe 'Posts index' do
|
5
|
+
let(:visit_posts_index) { visit_path_and_login_with(posts_path, user) }
|
6
|
+
|
7
|
+
let!(:post) { FactoryGirl.create(:post, author: user) }
|
8
|
+
let!(:other_post) { FactoryGirl.create(:post) }
|
9
|
+
|
10
|
+
before { visit_posts_index }
|
11
|
+
|
12
|
+
context 'when authenticated user is a super admin' do
|
13
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
|
14
|
+
|
15
|
+
it 'renders the posts index page' do
|
16
|
+
expect(current_path).to eq(posts_path)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'shows the first post' do
|
20
|
+
expect(page).to have_content(post.content)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'shows the second post' do
|
24
|
+
expect(page).to have_content(other_post.content)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when authenticated user is not a super admin' do
|
29
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
|
30
|
+
|
31
|
+
it 'displays an error message' do
|
32
|
+
expect(page).to have_content(/forbidden/i)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'does not show the first post' do
|
36
|
+
expect(page).to_not have_content(post.content)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'does not show the second post' do
|
40
|
+
expect(page).to_not have_content(other_post.content)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'Show post' do
|
46
|
+
let(:show_post) { visit_path_and_login_with(post_path(post.id), user) }
|
47
|
+
|
48
|
+
let!(:post) { FactoryGirl.create(:post, author: user) }
|
49
|
+
|
50
|
+
before { show_post }
|
51
|
+
|
52
|
+
context 'when authenticated user is a super_admin' do
|
53
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
|
54
|
+
|
55
|
+
it 'renders the show post page' do
|
56
|
+
expect(current_path).to eq(post_path(post.id))
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'shows the post content' do
|
60
|
+
expect(page).to have_content(post.content)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'when authenticated user is not a super_admin' do
|
65
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
|
66
|
+
|
67
|
+
it 'displays an error message' do
|
68
|
+
expect(page).to have_content(/forbidden/i)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'does not show the post content' do
|
72
|
+
expect(page).to_not have_content(post.content)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'New post' do
|
78
|
+
let(:visit_new_post) { visit_path_and_login_with(new_post_path, user) }
|
79
|
+
|
80
|
+
before { visit_new_post }
|
81
|
+
|
82
|
+
context 'when authenticated user is a super admin' do
|
83
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
|
84
|
+
|
85
|
+
it 'renders the new post page' do
|
86
|
+
expect(current_path).to eq(new_post_path)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'renders a form that accepts post content' do
|
90
|
+
expect(page).to have_field('Content')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when authenticated user is not a super admin' do
|
95
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
|
96
|
+
|
97
|
+
it 'displays an error message' do
|
98
|
+
expect(page).to have_content(/forbidden/i)
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'does not render a form that accepts post content' do
|
102
|
+
expect(page).to_not have_field('Content')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe 'Create post' do
|
108
|
+
subject(:create_post) { click_button 'Create Post' }
|
109
|
+
|
110
|
+
before do
|
111
|
+
visit_path_and_login_with(new_post_path, user)
|
112
|
+
fill_in 'Content', with: post.content
|
113
|
+
end
|
114
|
+
|
115
|
+
let(:post) { FactoryGirl.build(:post, author: user) }
|
116
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
|
117
|
+
|
118
|
+
context 'when authenticated user is a super admin' do
|
119
|
+
it 'renders the flash message' do
|
120
|
+
create_post
|
121
|
+
expect(page).to have_content('Post was successfully created.')
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'renders the post content' do
|
125
|
+
create_post
|
126
|
+
expect(page).to have_content(post.content)
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'creates a post in the db' do
|
130
|
+
expect { create_post }.to change { Post.count }.by(1)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'when authenticated user is not a super admin on form submission' do
|
135
|
+
before do
|
136
|
+
user.roles.clear
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'displays an error message' do
|
140
|
+
create_post
|
141
|
+
expect(page).to have_content(/forbidden/i)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'does not create a post' do
|
145
|
+
expect { create_post }.to_not change { Post.count }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe 'Edit post' do
|
151
|
+
subject(:edit_post) { visit_path_and_login_with(edit_post_path(post.id), user) }
|
152
|
+
before { edit_post }
|
153
|
+
|
154
|
+
let(:post) { FactoryGirl.create(:post, author: user) }
|
155
|
+
|
156
|
+
context 'when authenticated user is a super admin' do
|
157
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
|
158
|
+
|
159
|
+
it 'renders the edit post page' do
|
160
|
+
expect(current_path).to eq(edit_post_path(post.id))
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'renders a form that accepts post content' do
|
164
|
+
expect(page).to have_field('Content', with: post.content)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context 'when authenticated user is not a super admin' do
|
169
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
|
170
|
+
|
171
|
+
it 'displays an error message' do
|
172
|
+
expect(page).to have_content(/forbidden/i)
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'does not render a form that accepts post content' do
|
176
|
+
expect(page).to_not have_field('Content')
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe 'Update post' do
|
182
|
+
subject(:update_post) { click_button 'Update Post' }
|
183
|
+
|
184
|
+
before do
|
185
|
+
visit_path_and_login_with(edit_post_path(post.id), user)
|
186
|
+
fill_in 'Content', with: new_content
|
187
|
+
end
|
188
|
+
|
189
|
+
let(:post) { FactoryGirl.create(:post, author: user) }
|
190
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
|
191
|
+
let(:new_content) { 'My updated post content' }
|
192
|
+
|
193
|
+
context 'when authenticated user is a super admin' do
|
194
|
+
it 'renders the flash message' do
|
195
|
+
update_post
|
196
|
+
expect(page).to have_content('Post was successfully updated.')
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'renders the post content' do
|
200
|
+
update_post
|
201
|
+
expect(page).to have_content(new_content)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context 'when authenticated user is not a super admin on form submission' do
|
206
|
+
before do
|
207
|
+
user.roles.clear
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'displays an error message' do
|
211
|
+
update_post
|
212
|
+
expect(page).to have_content(/forbidden/i)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'does not update post content' do
|
216
|
+
update_post
|
217
|
+
expect(page).to_not have_content(new_content)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe 'Delete post' do
|
223
|
+
subject(:delete_post) { click_link 'Destroy' }
|
224
|
+
|
225
|
+
let!(:post) { FactoryGirl.create(:post, author: user) }
|
226
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_super_admin) }
|
227
|
+
|
228
|
+
before { visit_path_and_login_with(posts_path, user) }
|
229
|
+
|
230
|
+
context 'when authenticated user is a super admin' do
|
231
|
+
it 'renders the flash message' do
|
232
|
+
delete_post
|
233
|
+
expect(page).to have_content('Post was successfully destroyed.')
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'deletes the post' do
|
237
|
+
expect { delete_post }.to change { Post.count }.by(-1)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
context 'when authenticated user is not a super admin' do
|
242
|
+
before { user.roles.clear }
|
243
|
+
|
244
|
+
it 'displays an error message' do
|
245
|
+
delete_post
|
246
|
+
expect(page).to have_content(/forbidden/i)
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'does not delete the post' do
|
250
|
+
expect { delete_post }.to_not change { Post.count }
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
@@ -10,31 +10,127 @@ describe 'Signing in' do
|
|
10
10
|
|
11
11
|
context 'when user exists locally' do
|
12
12
|
before do
|
13
|
-
|
14
|
-
|
13
|
+
OmniAuth.config.mock_auth[:g5] = OmniAuth::AuthHash.new({
|
14
|
+
uid: user.uid,
|
15
|
+
provider: user.provider,
|
16
|
+
info: {
|
17
|
+
email: user.email,
|
18
|
+
name: "#{updated_first_name} #{updated_last_name}",
|
19
|
+
first_name: updated_first_name,
|
20
|
+
last_name: updated_last_name,
|
21
|
+
phone: updated_phone_number
|
22
|
+
},
|
23
|
+
credentials: {
|
24
|
+
token: updated_access_token,
|
25
|
+
expires: true,
|
26
|
+
expires_at: Time.now + 1000
|
27
|
+
},
|
28
|
+
extra: {
|
29
|
+
title: updated_title,
|
30
|
+
organization_name: updated_organization_name,
|
31
|
+
roles: [{name: updated_role.name}],
|
32
|
+
raw_info: {}
|
33
|
+
}
|
34
|
+
})
|
15
35
|
end
|
16
36
|
|
37
|
+
let(:updated_first_name) { "Updated #{user.first_name}" }
|
38
|
+
let(:updated_last_name) { "Updated #{user.last_name}" }
|
39
|
+
let(:updated_phone_number) { "#{user.phone_number} x1234" }
|
40
|
+
let(:updated_title) { "Updated #{user.title}" }
|
41
|
+
let(:updated_organization_name) { "Updated #{user.organization_name}" }
|
42
|
+
let(:updated_access_token) { "updated-#{user.g5_access_token}-123" }
|
43
|
+
let(:updated_role) { FactoryGirl.create(:g5_authenticatable_super_admin_role) }
|
44
|
+
|
17
45
|
it 'should sign in the user successfully' do
|
46
|
+
login
|
18
47
|
expect(page).to have_content('Signed in successfully.')
|
19
48
|
end
|
20
49
|
|
21
50
|
it 'should redirect the user to the root path' do
|
51
|
+
login
|
22
52
|
expect(current_path).to eq(root_path)
|
23
53
|
end
|
54
|
+
|
55
|
+
it 'should not create a new user' do
|
56
|
+
expect { login }.to_not change { G5Authenticatable::User.count }
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should not update the user email' do
|
60
|
+
login
|
61
|
+
expect(page).to have_content(user.email)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should update the first name' do
|
65
|
+
login
|
66
|
+
expect(page).to have_content(updated_first_name)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should update the last name' do
|
70
|
+
login
|
71
|
+
expect(page).to have_content(updated_last_name)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should update the phone number' do
|
75
|
+
login
|
76
|
+
expect(page).to have_content(updated_phone_number)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should update the title' do
|
80
|
+
login
|
81
|
+
expect(page).to have_content(updated_title)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should update the organization name' do
|
85
|
+
login
|
86
|
+
expect(page).to have_content(updated_organization_name)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should update the access token' do
|
90
|
+
login
|
91
|
+
expect(page).to have_content(updated_access_token)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should assign the updated role' do
|
95
|
+
login
|
96
|
+
expect(page).to have_content(updated_role.name)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should unassign the previous role' do
|
100
|
+
old_role = user.roles.first
|
101
|
+
login
|
102
|
+
expect(page).to_not have_content(old_role.name)
|
103
|
+
end
|
24
104
|
end
|
25
105
|
|
26
106
|
context 'when user does not exist locally' do
|
27
107
|
before do
|
28
108
|
OmniAuth.config.mock_auth[:g5] = OmniAuth::AuthHash.new({
|
29
|
-
uid: uid,
|
30
|
-
provider:
|
31
|
-
info: {
|
32
|
-
|
109
|
+
uid: user_attributes[:uid],
|
110
|
+
provider: user_attributes[:provider],
|
111
|
+
info: {
|
112
|
+
email: user_attributes[:email],
|
113
|
+
name: "#{user_attributes[:first_name]} #{user_attributes[:last_name]}",
|
114
|
+
first_name: user_attributes[:first_name],
|
115
|
+
last_name: user_attributes[:last_name],
|
116
|
+
phone: user_attributes[:phone_number]
|
117
|
+
},
|
118
|
+
credentials: {
|
119
|
+
token: user_attributes[:g5_access_token],
|
120
|
+
expires: true,
|
121
|
+
expires_at: Time.now + 1000
|
122
|
+
},
|
123
|
+
extra: {
|
124
|
+
title: user_attributes[:title],
|
125
|
+
organization_name: user_attributes[:organization_name],
|
126
|
+
roles: [{name: role_attributes[:name]}],
|
127
|
+
raw_info: {}
|
128
|
+
}
|
33
129
|
})
|
34
130
|
end
|
35
131
|
|
36
|
-
let(:
|
37
|
-
let(:
|
132
|
+
let(:user_attributes) { FactoryGirl.attributes_for(:g5_authenticatable_user) }
|
133
|
+
let(:role_attributes) { FactoryGirl.attributes_for(:g5_authenticatable_editor_role) }
|
38
134
|
|
39
135
|
it 'should sign in the user successfully' do
|
40
136
|
login
|
@@ -49,6 +145,46 @@ describe 'Signing in' do
|
|
49
145
|
it 'should create the user locally' do
|
50
146
|
expect { login }.to change { G5Authenticatable::User.count }.by(1)
|
51
147
|
end
|
148
|
+
|
149
|
+
it 'should save the user email' do
|
150
|
+
login
|
151
|
+
expect(page).to have_content(user_attributes[:email])
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should save the user first_name' do
|
155
|
+
login
|
156
|
+
expect(page).to have_content(user_attributes[:first_name])
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should save the user last_name' do
|
160
|
+
login
|
161
|
+
expect(page).to have_content(user_attributes[:last_name])
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should save the user phone_number' do
|
165
|
+
login
|
166
|
+
expect(page).to have_content(user_attributes[:phone_number])
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should save the user token' do
|
170
|
+
login
|
171
|
+
expect(page).to have_content(user_attributes[:g5_access_token])
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should save the user title' do
|
175
|
+
login
|
176
|
+
expect(page).to have_content(user_attributes[:title])
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'should save the user organization_name' do
|
180
|
+
login
|
181
|
+
expect(page).to have_content(user_attributes[:organization_name])
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'should save the user role' do
|
185
|
+
login
|
186
|
+
expect(page).to have_content(role_attributes[:name])
|
187
|
+
end
|
52
188
|
end
|
53
189
|
end
|
54
190
|
|
@@ -12,10 +12,11 @@ describe G5Authenticatable::InstallGenerator, type: :generator do
|
|
12
12
|
before do
|
13
13
|
prepare_destination
|
14
14
|
setup_routes
|
15
|
+
setup_application_controller
|
15
16
|
run_generator
|
16
17
|
end
|
17
18
|
|
18
|
-
it 'should copy the migration' do
|
19
|
+
it 'should copy the create user migration' do
|
19
20
|
expect(destination_root).to have_structure {
|
20
21
|
directory 'db' do
|
21
22
|
directory 'migrate' do
|
@@ -27,6 +28,30 @@ describe G5Authenticatable::InstallGenerator, type: :generator do
|
|
27
28
|
}
|
28
29
|
end
|
29
30
|
|
31
|
+
it 'should copy the migration to add user contact info' do
|
32
|
+
expect(destination_root).to have_structure {
|
33
|
+
directory 'db' do
|
34
|
+
directory 'migrate' do
|
35
|
+
migration 'add_g5_authenticatable_users_contact_info' do
|
36
|
+
contains 'class AddG5AuthenticatableUsersContactInfo < ActiveRecord::Migration'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should copy the migration to add user roles' do
|
44
|
+
expect(destination_root).to have_structure {
|
45
|
+
directory 'db' do
|
46
|
+
directory 'migrate' do
|
47
|
+
migration 'create_g5_authenticatable_roles' do
|
48
|
+
contains 'class CreateG5AuthenticatableRoles < ActiveRecord::Migration'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
30
55
|
it 'should copy the initializer' do
|
31
56
|
expect(destination_root).to have_structure {
|
32
57
|
directory 'config' do
|
@@ -49,6 +74,40 @@ describe G5Authenticatable::InstallGenerator, type: :generator do
|
|
49
74
|
}
|
50
75
|
end
|
51
76
|
|
77
|
+
it 'should include authorization in the application controller' do
|
78
|
+
expect(destination_root).to have_structure {
|
79
|
+
directory 'app' do
|
80
|
+
directory 'controllers' do
|
81
|
+
file 'application_controller.rb' do
|
82
|
+
contains 'include G5Authenticatable::Authorization'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should create the default application policy' do
|
90
|
+
expect(destination_root).to have_structure {
|
91
|
+
directory 'app' do
|
92
|
+
directory 'policies' do
|
93
|
+
file 'application_policy.rb' do
|
94
|
+
contains 'class ApplicationPolicy < G5Authenticatable::BasePolicy'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should copy the static 403 error page' do
|
102
|
+
expect(destination_root).to have_structure {
|
103
|
+
directory 'public' do
|
104
|
+
file '403.html' do
|
105
|
+
contains 'Access forbidden'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
52
111
|
def setup_routes
|
53
112
|
routes = <<-END
|
54
113
|
Rails.application.routes.draw do
|
@@ -64,4 +123,16 @@ describe G5Authenticatable::InstallGenerator, type: :generator do
|
|
64
123
|
FileUtils.mkdir_p(config_dir)
|
65
124
|
File.write(File.join(config_dir, 'routes.rb'), routes)
|
66
125
|
end
|
126
|
+
|
127
|
+
def setup_application_controller
|
128
|
+
controller = <<-END
|
129
|
+
class ApplicationController < ActionController::Base
|
130
|
+
protect_from_forgery
|
131
|
+
end
|
132
|
+
END
|
133
|
+
controllers_dir = File.join(destination_root, 'app', 'controllers')
|
134
|
+
|
135
|
+
FileUtils.mkdir_p(controllers_dir)
|
136
|
+
File.write(File.join(controllers_dir, 'application_controller.rb'), controller)
|
137
|
+
end
|
67
138
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe G5Authenticatable::Role do
|
4
|
+
subject { role }
|
5
|
+
let(:role) { G5Authenticatable::Role.new(role_attributes) }
|
6
|
+
let(:role_attributes) { FactoryGirl.attributes_for(:g5_authenticatable_role) }
|
7
|
+
|
8
|
+
it { is_expected.to have_and_belong_to_many(:users) }
|
9
|
+
it { is_expected.to belong_to(:resource) }
|
10
|
+
|
11
|
+
it 'should expose the name attribute' do
|
12
|
+
expect(role.name).to eq(role_attributes[:name])
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '.global' do
|
16
|
+
subject(:global) { G5Authenticatable::Role.global }
|
17
|
+
let!(:global_role) { user.roles.first }
|
18
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
|
19
|
+
|
20
|
+
let!(:scoped_role) do
|
21
|
+
FactoryGirl.create(:g5_authenticatable_role,
|
22
|
+
resource: user)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should match one role' do
|
26
|
+
expect(global.count).to eq(1)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should only match the unscoped role' do
|
30
|
+
expect(global.first).to eq(global_role)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.class_scoped' do
|
35
|
+
subject(:class_scoped) { G5Authenticatable::Role.class_scoped(G5Authenticatable::User) }
|
36
|
+
let!(:global_role) { FactoryGirl.create(:g5_authenticatable_role) }
|
37
|
+
let!(:class_scoped_role) do
|
38
|
+
FactoryGirl.create(:g5_authenticatable_role,
|
39
|
+
resource_type: 'G5Authenticatable::User')
|
40
|
+
end
|
41
|
+
let!(:instance_scoped_role) do
|
42
|
+
FactoryGirl.create(:g5_authenticatable_role, resource: user)
|
43
|
+
end
|
44
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
|
45
|
+
|
46
|
+
it 'should match one role' do
|
47
|
+
expect(class_scoped.count).to eq(1)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should only match the class scoped role' do
|
51
|
+
expect(class_scoped.first).to eq(class_scoped_role)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '.instance_scoped' do
|
56
|
+
subject(:instance_scoped) { G5Authenticatable::Role.instance_scoped(user) }
|
57
|
+
let!(:global_role) { FactoryGirl.create(:g5_authenticatable_role) }
|
58
|
+
let!(:class_scoped_role) do
|
59
|
+
FactoryGirl.create(:g5_authenticatable_role,
|
60
|
+
resource_type: 'G5Authenticatable::User')
|
61
|
+
end
|
62
|
+
|
63
|
+
let!(:user_scoped_role) do
|
64
|
+
FactoryGirl.create(:g5_authenticatable_role, resource: user)
|
65
|
+
end
|
66
|
+
let(:user) { FactoryGirl.create(:g5_authenticatable_user) }
|
67
|
+
|
68
|
+
let!(:other_user_scoped_role) do
|
69
|
+
FactoryGirl.create(:g5_authenticatable_role, resource: other_user)
|
70
|
+
end
|
71
|
+
let(:other_user) { FactoryGirl.create(:g5_authenticatable_user) }
|
72
|
+
|
73
|
+
it 'should match one role' do
|
74
|
+
expect(instance_scoped.count).to eq(1)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should only match the role scoped to this user instance' do
|
78
|
+
expect(instance_scoped.first).to eq(user_scoped_role)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|