double_auth_engine 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.
- data/.gitignore +7 -0
- data/.rvmrc +1 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +136 -0
- data/MIT-LICENSE +20 -0
- data/README.md +59 -0
- data/Rakefile +25 -0
- data/app/controllers/password_resets_controller.rb +3 -0
- data/app/controllers/user_sessions_controller.rb +3 -0
- data/app/controllers/users_controller.rb +3 -0
- data/app/mailers/notifier.rb +8 -0
- data/app/models/assignment.rb +3 -0
- data/app/models/role.rb +3 -0
- data/app/models/user.rb +3 -0
- data/app/models/user_session.rb +3 -0
- data/app/views/notifier/password_reset_instructions.text.erb +8 -0
- data/app/views/password_resets/edit.html.erb +5 -0
- data/app/views/password_resets/new.html.erb +5 -0
- data/app/views/user_sessions/new.html.erb +17 -0
- data/app/views/users/edit.html.erb +0 -0
- data/app/views/users/index.html.erb +0 -0
- data/app/views/users/new.html.erb +20 -0
- data/app/views/users/show.html.erb +2 -0
- data/config/routes.rb +11 -0
- data/double_auth_engine.gemspec +26 -0
- data/lib/double_auth_engine/controllers/application_controller_mixin.rb +42 -0
- data/lib/double_auth_engine/controllers/password_resets_controller_mixin.rb +49 -0
- data/lib/double_auth_engine/controllers/user_sessions_controller_mixin.rb +34 -0
- data/lib/double_auth_engine/controllers/users_controller_mixin.rb +63 -0
- data/lib/double_auth_engine/generators/double_auth_engine/install_generator.rb +48 -0
- data/lib/double_auth_engine/generators/double_auth_engine/templates/assignment_migration.rb +13 -0
- data/lib/double_auth_engine/generators/double_auth_engine/templates/authorization_rules.rb +19 -0
- data/lib/double_auth_engine/generators/double_auth_engine/templates/role_migration.rb +12 -0
- data/lib/double_auth_engine/generators/double_auth_engine/templates/setup_mail_initializer.rb +7 -0
- data/lib/double_auth_engine/generators/double_auth_engine/templates/user_migration.rb +28 -0
- data/lib/double_auth_engine/models/assignment_mixin.rb +10 -0
- data/lib/double_auth_engine/models/role_mixin.rb +10 -0
- data/lib/double_auth_engine/models/user_mixin.rb +38 -0
- data/lib/double_auth_engine/models/user_session_mixin.rb +15 -0
- data/lib/double_auth_engine/tasks/migrate_seed.rake +9 -0
- data/lib/double_auth_engine/version.rb +3 -0
- data/lib/double_auth_engine.rb +15 -0
- data/lib/engine.rb +23 -0
- data/spec/double_auth_engine_spec.rb +7 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +4 -0
- data/spec/dummy/app/controllers/dashboard_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/dashboard/index.html.erb +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config/application.rb +48 -0
- data/spec/dummy/config/authorization_rules.rb +20 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +22 -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 +52 -0
- data/spec/dummy/config/environments/test.rb +35 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/setup_mail.rb +9 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20110408030355_create_users.rb +28 -0
- data/spec/dummy/db/migrate/20110408030356_create_roles.rb +12 -0
- data/spec/dummy/db/migrate/20110408030357_create_assignments.rb +13 -0
- data/spec/dummy/db/schema.rb +51 -0
- data/spec/dummy/db/seeds.rb +3 -0
- data/spec/dummy/lib/development_mail_interceptor.rb +6 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/javascripts/application.js +2 -0
- data/spec/dummy/public/javascripts/controls.js +965 -0
- data/spec/dummy/public/javascripts/dragdrop.js +974 -0
- data/spec/dummy/public/javascripts/effects.js +1123 -0
- data/spec/dummy/public/javascripts/prototype.js +6001 -0
- data/spec/dummy/public/javascripts/rails.js +175 -0
- data/spec/dummy/public/stylesheets/.gitkeep +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/spec/authorizations/user_spec.rb +104 -0
- data/spec/dummy/spec/controllers/user_sessions_controller_spec.rb +48 -0
- data/spec/dummy/spec/controllers/users_controller_spec.rb +125 -0
- data/spec/dummy/spec/models/user_spec.rb +65 -0
- data/spec/integration/navigation_spec.rb +9 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/support/user_authentication.rb +14 -0
- data/spec/support/user_authorization.rb +17 -0
- metadata +218 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
// Technique from Juriy Zaytsev
|
|
3
|
+
// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
|
|
4
|
+
function isEventSupported(eventName) {
|
|
5
|
+
var el = document.createElement('div');
|
|
6
|
+
eventName = 'on' + eventName;
|
|
7
|
+
var isSupported = (eventName in el);
|
|
8
|
+
if (!isSupported) {
|
|
9
|
+
el.setAttribute(eventName, 'return;');
|
|
10
|
+
isSupported = typeof el[eventName] == 'function';
|
|
11
|
+
}
|
|
12
|
+
el = null;
|
|
13
|
+
return isSupported;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isForm(element) {
|
|
17
|
+
return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isInput(element) {
|
|
21
|
+
if (Object.isElement(element)) {
|
|
22
|
+
var name = element.nodeName.toUpperCase()
|
|
23
|
+
return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
|
|
24
|
+
}
|
|
25
|
+
else return false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var submitBubbles = isEventSupported('submit'),
|
|
29
|
+
changeBubbles = isEventSupported('change')
|
|
30
|
+
|
|
31
|
+
if (!submitBubbles || !changeBubbles) {
|
|
32
|
+
// augment the Event.Handler class to observe custom events when needed
|
|
33
|
+
Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
|
|
34
|
+
function(init, element, eventName, selector, callback) {
|
|
35
|
+
init(element, eventName, selector, callback)
|
|
36
|
+
// is the handler being attached to an element that doesn't support this event?
|
|
37
|
+
if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
|
|
38
|
+
(!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
|
|
39
|
+
// "submit" => "emulated:submit"
|
|
40
|
+
this.eventName = 'emulated:' + this.eventName
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!submitBubbles) {
|
|
47
|
+
// discover forms on the page by observing focus events which always bubble
|
|
48
|
+
document.on('focusin', 'form', function(focusEvent, form) {
|
|
49
|
+
// special handler for the real "submit" event (one-time operation)
|
|
50
|
+
if (!form.retrieve('emulated:submit')) {
|
|
51
|
+
form.on('submit', function(submitEvent) {
|
|
52
|
+
var emulated = form.fire('emulated:submit', submitEvent, true)
|
|
53
|
+
// if custom event received preventDefault, cancel the real one too
|
|
54
|
+
if (emulated.returnValue === false) submitEvent.preventDefault()
|
|
55
|
+
})
|
|
56
|
+
form.store('emulated:submit', true)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!changeBubbles) {
|
|
62
|
+
// discover form inputs on the page
|
|
63
|
+
document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
|
|
64
|
+
// special handler for real "change" events
|
|
65
|
+
if (!input.retrieve('emulated:change')) {
|
|
66
|
+
input.on('change', function(changeEvent) {
|
|
67
|
+
input.fire('emulated:change', changeEvent, true)
|
|
68
|
+
})
|
|
69
|
+
input.store('emulated:change', true)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function handleRemote(element) {
|
|
75
|
+
var method, url, params;
|
|
76
|
+
|
|
77
|
+
var event = element.fire("ajax:before");
|
|
78
|
+
if (event.stopped) return false;
|
|
79
|
+
|
|
80
|
+
if (element.tagName.toLowerCase() === 'form') {
|
|
81
|
+
method = element.readAttribute('method') || 'post';
|
|
82
|
+
url = element.readAttribute('action');
|
|
83
|
+
params = element.serialize();
|
|
84
|
+
} else {
|
|
85
|
+
method = element.readAttribute('data-method') || 'get';
|
|
86
|
+
url = element.readAttribute('href');
|
|
87
|
+
params = {};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
new Ajax.Request(url, {
|
|
91
|
+
method: method,
|
|
92
|
+
parameters: params,
|
|
93
|
+
evalScripts: true,
|
|
94
|
+
|
|
95
|
+
onComplete: function(request) { element.fire("ajax:complete", request); },
|
|
96
|
+
onSuccess: function(request) { element.fire("ajax:success", request); },
|
|
97
|
+
onFailure: function(request) { element.fire("ajax:failure", request); }
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
element.fire("ajax:after");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function handleMethod(element) {
|
|
104
|
+
var method = element.readAttribute('data-method'),
|
|
105
|
+
url = element.readAttribute('href'),
|
|
106
|
+
csrf_param = $$('meta[name=csrf-param]')[0],
|
|
107
|
+
csrf_token = $$('meta[name=csrf-token]')[0];
|
|
108
|
+
|
|
109
|
+
var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
|
|
110
|
+
element.parentNode.insert(form);
|
|
111
|
+
|
|
112
|
+
if (method !== 'post') {
|
|
113
|
+
var field = new Element('input', { type: 'hidden', name: '_method', value: method });
|
|
114
|
+
form.insert(field);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (csrf_param) {
|
|
118
|
+
var param = csrf_param.readAttribute('content'),
|
|
119
|
+
token = csrf_token.readAttribute('content'),
|
|
120
|
+
field = new Element('input', { type: 'hidden', name: param, value: token });
|
|
121
|
+
form.insert(field);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
form.submit();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
document.on("click", "*[data-confirm]", function(event, element) {
|
|
129
|
+
var message = element.readAttribute('data-confirm');
|
|
130
|
+
if (!confirm(message)) event.stop();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
document.on("click", "a[data-remote]", function(event, element) {
|
|
134
|
+
if (event.stopped) return;
|
|
135
|
+
handleRemote(element);
|
|
136
|
+
event.stop();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
document.on("click", "a[data-method]", function(event, element) {
|
|
140
|
+
if (event.stopped) return;
|
|
141
|
+
handleMethod(element);
|
|
142
|
+
event.stop();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
document.on("submit", function(event) {
|
|
146
|
+
var element = event.findElement(),
|
|
147
|
+
message = element.readAttribute('data-confirm');
|
|
148
|
+
if (message && !confirm(message)) {
|
|
149
|
+
event.stop();
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
var inputs = element.select("input[type=submit][data-disable-with]");
|
|
154
|
+
inputs.each(function(input) {
|
|
155
|
+
input.disabled = true;
|
|
156
|
+
input.writeAttribute('data-original-value', input.value);
|
|
157
|
+
input.value = input.readAttribute('data-disable-with');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
var element = event.findElement("form[data-remote]");
|
|
161
|
+
if (element) {
|
|
162
|
+
handleRemote(element);
|
|
163
|
+
event.stop();
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
document.on("ajax:after", "form", function(event, element) {
|
|
168
|
+
var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
|
|
169
|
+
inputs.each(function(input) {
|
|
170
|
+
input.value = input.readAttribute('data-original-value');
|
|
171
|
+
input.removeAttribute('data-original-value');
|
|
172
|
+
input.disabled = false;
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
})();
|
|
File without changes
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
|
3
|
+
|
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
|
6
|
+
require 'rails/commands'
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "User Authorizations" do
|
|
4
|
+
describe "a 'guest' role" do
|
|
5
|
+
before do
|
|
6
|
+
@user = User.create(:name => Faker::Name.name,
|
|
7
|
+
:password => 'testing',
|
|
8
|
+
:password_confirmation => "testing",
|
|
9
|
+
:email => Faker::Internet.email)
|
|
10
|
+
Authorization.current_user = @user
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "should be allowed" do
|
|
14
|
+
it "to access the 'index' action" do
|
|
15
|
+
should_be_allowed_to(:index, :users)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "to access the 'show' action" do
|
|
19
|
+
should_be_allowed_to(:show, :users)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "to access the 'new' action" do
|
|
23
|
+
should_be_allowed_to(:new, :users)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "to access the 'create' action" do
|
|
27
|
+
should_be_allowed_to(:create, :users)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "to access the 'edit' action" do
|
|
31
|
+
should_be_allowed_to(:edit, @user)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "to access the 'update' action" do
|
|
35
|
+
should_be_allowed_to(:update, @user)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "to access the 'destroy' action" do
|
|
39
|
+
should_be_allowed_to(:destroy, @user)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe "should not be allowed" do
|
|
44
|
+
before do
|
|
45
|
+
@alt_user = User.create(:name => Faker::Name.name,
|
|
46
|
+
:password => 'testing',
|
|
47
|
+
:password_confirmation => "testing",
|
|
48
|
+
:email => Faker::Internet.email)
|
|
49
|
+
end
|
|
50
|
+
it "to access the 'edit' action for another user" do
|
|
51
|
+
should_not_be_allowed_to(:edit, @alt_user)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "to access the 'update' action for another user" do
|
|
55
|
+
should_not_be_allowed_to(:update, @alt_user)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "to access the 'destroy' action for another user" do
|
|
59
|
+
should_not_be_allowed_to(:update, @alt_user)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "an 'admin' role" do
|
|
65
|
+
before do
|
|
66
|
+
@user = User.create(:name => Faker::Name.name,
|
|
67
|
+
:password => 'testing',
|
|
68
|
+
:password_confirmation => "testing",
|
|
69
|
+
:email => Faker::Internet.email)
|
|
70
|
+
@user.roles << Role.create(:name => 'admin')
|
|
71
|
+
Authorization.current_user = @user
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe "should be allowed" do
|
|
75
|
+
it "to access the 'index' action" do
|
|
76
|
+
should_be_allowed_to(:index, :users)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "to access the 'show' action" do
|
|
80
|
+
should_be_allowed_to(:show, :users)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "to access the 'new' action" do
|
|
84
|
+
should_be_allowed_to(:new, :users)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "to access the 'create' action" do
|
|
88
|
+
should_be_allowed_to(:create, :users)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "to access the 'edit' action" do
|
|
92
|
+
should_be_allowed_to(:edit, :users)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "to access the 'update' action" do
|
|
96
|
+
should_be_allowed_to(:update, :users)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "to access the 'destroy' action" do
|
|
100
|
+
should_be_allowed_to(:destroy, :users)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe UserSessionsController do
|
|
4
|
+
def mock_user_session(stubs={})
|
|
5
|
+
@mock_user_session ||= mock(UserSession, stubs.update(:login_field => 'email')).as_null_object
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe "GET new" do
|
|
9
|
+
it "assigns a new user_session as @user_session" do
|
|
10
|
+
UserSession.stub(:new) { mock_user_session }
|
|
11
|
+
get :new
|
|
12
|
+
assigns(:user_session).should be(mock_user_session)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe "POST create" do
|
|
17
|
+
describe "with valid params" do
|
|
18
|
+
it "redirects to the dashboard page" do
|
|
19
|
+
UserSession.stub(:new) { mock_user_session(:save => true) }
|
|
20
|
+
post :create, :user_session => {}
|
|
21
|
+
response.should redirect_to(root_url)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe "with invalid params" do
|
|
26
|
+
it "re-renders the 'new' template" do
|
|
27
|
+
UserSession.stub(:new) { mock_user_session(:save => false) }
|
|
28
|
+
post :create, :user_session => {}
|
|
29
|
+
response.should render_template "user_sessions/new"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
#Special case for session control to use GET /logout and not DELETE /logout
|
|
35
|
+
describe "GET destroy" do
|
|
36
|
+
it "destroys the requested user_session" do
|
|
37
|
+
UserSession.stub(:find) { mock_user_session }
|
|
38
|
+
mock_user_session.should_receive(:destroy)
|
|
39
|
+
get :destroy
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "redirects to the user_sessions list" do
|
|
43
|
+
UserSession.stub(:find) { mock_user_session }
|
|
44
|
+
get :destroy, :id => "1"
|
|
45
|
+
response.should redirect_to(root_url)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe UsersController do
|
|
4
|
+
before do
|
|
5
|
+
login
|
|
6
|
+
controller.stub!(:filter_access_to).and_return(true)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe "GET 'show'" do
|
|
10
|
+
before do
|
|
11
|
+
User.stub(:find).and_return(@user = stub_model(User))
|
|
12
|
+
get :show, :id => @user.id
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should render the 'show' template" do
|
|
16
|
+
response.should render_template("show")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "exposes the requested User as @user" do
|
|
20
|
+
assigns[:user].should == @user
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it '@user object should not be a new record' do
|
|
24
|
+
assigns[:user].should_not be_new_record
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "GET 'new'" do
|
|
29
|
+
it "should render the 'new' template" do
|
|
30
|
+
get :new
|
|
31
|
+
response.should render_template("new")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe "POST 'create'" do
|
|
36
|
+
before :each do
|
|
37
|
+
@user = stub_model(User)
|
|
38
|
+
User.should_receive(:new).and_return(@user)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'should set a @user instance' do
|
|
42
|
+
@user.should_receive(:save).and_return(true)
|
|
43
|
+
post :create, :user => { }
|
|
44
|
+
assigns(:user).should_not be_nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'should set flash on successful create' do
|
|
48
|
+
@user.should_receive(:save).and_return(true)
|
|
49
|
+
post :create, :user => { }
|
|
50
|
+
flash[:notice].should eq("User successfully created")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "should render 'show' template on successful create" do
|
|
54
|
+
@user.should_receive(:save).and_return(true)
|
|
55
|
+
post :create, :user => { }
|
|
56
|
+
response.should redirect_to(user_url(@user))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should render 'new' action on unsuccessful update" do
|
|
60
|
+
@user.should_receive(:save).and_return(false)
|
|
61
|
+
post :create, :user => { }
|
|
62
|
+
response.should render_template("new")
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "GET edit" do
|
|
67
|
+
before do
|
|
68
|
+
User.stub(:find).and_return(@user = stub_model(User))
|
|
69
|
+
get :edit, :id => @user.id
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "exposes the requested User as @user" do
|
|
73
|
+
assigns[:user].should == @user
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "renders the 'edit' template" do
|
|
77
|
+
response.should render_template("edit")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it '@user object should not be a new record' do
|
|
81
|
+
assigns[:user].should_not be_new_record
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe "POST update" do
|
|
86
|
+
before do
|
|
87
|
+
User.stub(:find).and_return(@user = stub_model(User))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "should render 'show'" do
|
|
91
|
+
@user.stub!(:update_attributes).and_return(true)
|
|
92
|
+
put :update, :id => @user.id, :user => { }
|
|
93
|
+
response.should redirect_to(user_path(@user))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "re-renders the 'edit' template" do
|
|
97
|
+
@user.stub!(:update_attributes).and_return(false)
|
|
98
|
+
put :update, :id => @user.id, :user => { }
|
|
99
|
+
response.should render_template("edit")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "should set flash message on successful update" do
|
|
103
|
+
@user.stub!(:update_attributes).and_return(true)
|
|
104
|
+
put :update, :id => @user.id, :user => { }
|
|
105
|
+
flash[:notice].should eq("User successfully updated")
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
describe "GET 'index'" do
|
|
110
|
+
it "should render 'index' template" do
|
|
111
|
+
get :index
|
|
112
|
+
response.should render_template("index")
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "should return with a 200 status code" do
|
|
116
|
+
get :index
|
|
117
|
+
response.status.should == 200
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'should assign @users' do
|
|
121
|
+
get :index
|
|
122
|
+
assigns[:users].should_not be_nil
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe User do
|
|
4
|
+
before do
|
|
5
|
+
@valid_attributes = { :name => Faker::Name.name,
|
|
6
|
+
:password => 'testing',
|
|
7
|
+
:password_confirmation => "testing",
|
|
8
|
+
:email => Faker::Internet.email }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
context "validations" do
|
|
12
|
+
it "should not create a new object with without an email" do
|
|
13
|
+
user = User.new(@valid_attributes.update(:email => ""))
|
|
14
|
+
user.valid?.should be_false
|
|
15
|
+
user.errors[:email].include?("can't be blank").should be_true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should not create a new object with an email less than 6 characters" do
|
|
19
|
+
user = User.new(@valid_attributes.update(:email => "t@m.m"))
|
|
20
|
+
user.valid?.should be_false
|
|
21
|
+
user.errors[:email].include?("is too short (minimum is 6 characters)").should be_true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should not create a new object with an email that does not look like an email" do
|
|
25
|
+
user = User.new(@valid_attributes.update(:email => "testing"))
|
|
26
|
+
user.valid?.should be_false
|
|
27
|
+
user.errors[:email].include?("should look like an email address.").should be_true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should not create a new object without name" do
|
|
31
|
+
user = User.new(@valid_attributes.update(:name => ""))
|
|
32
|
+
user.valid?.should be_false
|
|
33
|
+
user.errors[:name].include?("can't be blank").should be_true
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# it "should not create a new object without role" do
|
|
37
|
+
# user = User.new(@valid_attributes.update(:role => nil))
|
|
38
|
+
# user.valid?.should be_false
|
|
39
|
+
# user.errors[:role_id].include?("can't be blank").should be_true
|
|
40
|
+
# end
|
|
41
|
+
|
|
42
|
+
it "should not create a new object with a non-unique email address" do
|
|
43
|
+
User.create(@valid_attributes)
|
|
44
|
+
user = User.new(@valid_attributes)
|
|
45
|
+
user.valid?.should be_false
|
|
46
|
+
user.errors[:email].include?("has already been taken").should be_true
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context "methods" do
|
|
51
|
+
describe "email=(value)" do
|
|
52
|
+
it "should downcase the email attribute" do
|
|
53
|
+
user = User.create(@valid_attributes.update(:email => "AdMiN@EXAMPLE.com"))
|
|
54
|
+
user.email.should == "admin@example.com"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# describe "role_symbols" do
|
|
59
|
+
# it "should return administrator for an administrator" do
|
|
60
|
+
# user = User.make(:administrator)
|
|
61
|
+
# user.role_symbols.should == [:administrator]
|
|
62
|
+
# end
|
|
63
|
+
# end
|
|
64
|
+
end
|
|
65
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Configure Rails Environment
|
|
2
|
+
ENV["RAILS_ENV"] = "test"
|
|
3
|
+
|
|
4
|
+
# Declarative Authorization
|
|
5
|
+
AUTH_DSL_FILES = File.expand_path("../dummy/config/authorization_rules.rb", __FILE__)
|
|
6
|
+
|
|
7
|
+
require File.expand_path("../dummy/config/environment.rb", __FILE__)
|
|
8
|
+
require "rails/test_help"
|
|
9
|
+
require "rspec/rails"
|
|
10
|
+
require 'ffaker'
|
|
11
|
+
|
|
12
|
+
# Authlogic
|
|
13
|
+
require 'authlogic/test_case'
|
|
14
|
+
include Authlogic::TestCase
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
ActionMailer::Base.delivery_method = :test
|
|
18
|
+
ActionMailer::Base.perform_deliveries = true
|
|
19
|
+
ActionMailer::Base.default_url_options[:host] = "test.com"
|
|
20
|
+
|
|
21
|
+
Rails.backtrace_cleaner.remove_silencers!
|
|
22
|
+
|
|
23
|
+
# Configure capybara for integration testing
|
|
24
|
+
require "capybara/rails"
|
|
25
|
+
Capybara.default_driver = :rack_test
|
|
26
|
+
Capybara.default_selector = :css
|
|
27
|
+
|
|
28
|
+
# Run any available migration
|
|
29
|
+
ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
|
|
30
|
+
|
|
31
|
+
# Load support files
|
|
32
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
|
33
|
+
|
|
34
|
+
RSpec.configure do |config|
|
|
35
|
+
# Remove this line if you don't want RSpec's should and should_not
|
|
36
|
+
# methods or matchers
|
|
37
|
+
require 'rspec/expectations'
|
|
38
|
+
config.include RSpec::Matchers
|
|
39
|
+
|
|
40
|
+
# == Mock Framework
|
|
41
|
+
config.mock_with :rspec
|
|
42
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
def login
|
|
2
|
+
activate_authlogic
|
|
3
|
+
@current_user = User.create({ :name => Faker::Name.name,
|
|
4
|
+
:email => Faker::Internet.email,
|
|
5
|
+
:password => 'testing',
|
|
6
|
+
:password_confirmation => "testing" })
|
|
7
|
+
@current_user
|
|
8
|
+
@current_user.roles << Role.create(:name => 'admin')
|
|
9
|
+
|
|
10
|
+
UserSession.create!(@current_user)
|
|
11
|
+
controller.stub!(:current_user).and_return(@current_user)
|
|
12
|
+
ApplicationController.send(:public, :current_user)
|
|
13
|
+
view.stub!(:current_user).and_return(@current_user) if respond_to?(:view)
|
|
14
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
def should_be_allowed_to(privilege, object_or_context, object=nil)
|
|
2
|
+
options = {}
|
|
3
|
+
options[object_or_context.is_a?(Symbol) ? :context : :object] = object_or_context
|
|
4
|
+
options[:object] = object unless object.blank?
|
|
5
|
+
lambda {
|
|
6
|
+
Authorization::Engine.instance.permit! privilege, options
|
|
7
|
+
}.should_not raise_error
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def should_not_be_allowed_to(privilege, object_or_context, object=nil)
|
|
11
|
+
options = {}
|
|
12
|
+
options[object_or_context.is_a?(Symbol) ? :context : :object] = object_or_context
|
|
13
|
+
options[:object] = object unless object.blank?
|
|
14
|
+
lambda { Authorization::Engine.instance.permit! privilege, options }.should raise_error() do |e|
|
|
15
|
+
Authorization::NotAuthorized.ancestors.include?(e)
|
|
16
|
+
end
|
|
17
|
+
end
|