quo_vadis 1.1.2 → 1.2.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.
- data/CHANGELOG.md +5 -0
- data/README.md +65 -15
- data/app/controllers/quo_vadis/sessions_controller.rb +49 -6
- data/app/mailers/quo_vadis/notifier.rb +13 -1
- data/app/models/model_mixin.rb +18 -2
- data/config/locales/quo_vadis.en.yml +4 -0
- data/config/routes.rb +4 -2
- data/lib/generators/quo_vadis/templates/migration.rb.erb +3 -3
- data/lib/generators/quo_vadis/templates/quo_vadis.rb.erb +5 -2
- data/lib/quo_vadis/version.rb +1 -1
- data/lib/quo_vadis.rb +6 -3
- data/test/dummy/app/views/quo_vadis/notifier/invite.text.erb +8 -0
- data/test/dummy/app/views/sessions/invite.html.erb +15 -0
- data/test/dummy/config/initializers/quo_vadis.rb +4 -1
- data/test/dummy/config/initializers/rack_patch.rb +16 -0
- data/test/dummy/config/locales/quo_vadis.en.yml +4 -0
- data/test/integration/activation_test.rb +98 -0
- data/test/integration/config_test.rb +10 -3
- data/test/integration/locale_test.rb +2 -2
- data/test/integration/sign_in_person_test.rb +6 -6
- data/test/test_helper.rb +2 -1
- data/test/unit/user_test.rb +10 -0
- metadata +26 -18
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -10,7 +10,7 @@ Features:
|
|
10
10
|
* No surprises: it does what you expect.
|
11
11
|
* Easy to customise.
|
12
12
|
* Uses BCrypt to encrypt passwords.
|
13
|
-
* Sign in, sign out, forgotten password, authenticate actions, remember user between browser sessions.
|
13
|
+
* Sign in, sign out, forgotten password, authenticate actions, remember user between browser sessions, user activation.
|
14
14
|
* Block accounts.
|
15
15
|
* Let you choose which model(s) to authenticate (defaults to `User`).
|
16
16
|
|
@@ -25,7 +25,6 @@ Forthcoming features:
|
|
25
25
|
What it doesn't and won't do:
|
26
26
|
|
27
27
|
* Authorisation.
|
28
|
-
* Sign up; that's user management, not authentication.
|
29
28
|
* Work outside Rails 3.
|
30
29
|
* OpenID, OAuth, LDAP, CAS, etc.
|
31
30
|
* Separate identity from authentication services (cf OmniAuth).
|
@@ -106,36 +105,87 @@ Finally, write the change-password page ([example](https://github.com/airblade/q
|
|
106
105
|
* PUT the parameter `:password` to `change_password_url(params[:token])`
|
107
106
|
|
108
107
|
|
109
|
-
##
|
110
|
-
|
111
|
-
You can customise the flash messages and mailer from/subject in `config/locales/quo_vadis.en.yml`.
|
108
|
+
## Sign up (directly, without activation)
|
112
109
|
|
113
|
-
|
110
|
+
When you create a user, you need to sign them in. Do this by calling `sign_in(user)` in your controller. For example:
|
114
111
|
|
115
|
-
|
116
|
-
|
117
|
-
|
112
|
+
# In your app
|
113
|
+
class UsersController < ApplicationController
|
114
|
+
def create
|
115
|
+
@user = User.new params[:user]
|
116
|
+
if @user.save
|
117
|
+
sign_in @user # <-- NOTE: sign in your user here
|
118
|
+
else
|
119
|
+
render 'new'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
118
123
|
|
124
|
+
The `sign_in(user)` method will redirect the user appropriately (you can configure this in `config/initializers/quo_vadis.rb`), as well as running any sign-in hook you may have defined in the initializer.
|
119
125
|
|
120
|
-
## Sign up / user registration
|
121
126
|
|
122
|
-
|
127
|
+
## Sign up (with activation)
|
123
128
|
|
124
|
-
|
129
|
+
To create a user who must activate their account (via email) before they can sign in, do this:
|
125
130
|
|
126
131
|
# In your app
|
127
132
|
class UsersController < ApplicationController
|
128
133
|
def create
|
129
|
-
@user = User.
|
134
|
+
@user = User.new_for_activation params[:user] # <-- NOTE: different constructor
|
130
135
|
if @user.save
|
131
|
-
|
136
|
+
QuoVadis::SessionsController.new.invite_to_activate @user # <-- NOTE: email user here
|
137
|
+
redirect_to root_path, notice: "Emailed sign-in instructions to #{@user.name}" # or whatever
|
132
138
|
else
|
133
139
|
render 'new'
|
134
140
|
end
|
135
141
|
end
|
136
142
|
end
|
137
143
|
|
138
|
-
The
|
144
|
+
The user will receive an email with a link which takes them to a page (which you must write) where they can choose a username and password for themselves. When they submit the form their new credentials are stored and they are signed in.
|
145
|
+
|
146
|
+
Here's the workflow:
|
147
|
+
|
148
|
+
1. [New user page, without username/password fields] You or user fills in and submits form.
|
149
|
+
2. [Users controller] Create user and invite to activate. See code snippet above.
|
150
|
+
3. Quo Vadis emails the user a message with an invitation link. The link is valid for 3 hours.
|
151
|
+
4. [The email] The user clicks the link.
|
152
|
+
5. [Invitation page] The user fills in their new username and password.
|
153
|
+
6. Quo Vadis sets the user's username and password and signs the user in.
|
154
|
+
|
155
|
+
It'll take you about 3 minutes to implement this.
|
156
|
+
|
157
|
+
Update your user controller's `create` action as above.
|
158
|
+
|
159
|
+
Write the mailer view, i.e. the email which will be sent to your new users ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/notifier/invite.text.erb)). The view must:
|
160
|
+
|
161
|
+
* be at `app/views/quo_vadis/notifier/invite.text.erb`
|
162
|
+
* render `@url` somewhere (this is the link the user clicks to go to the invitation page)
|
163
|
+
|
164
|
+
You can also refer to `@user` in the email view, as well as any other data you pass to `invite_to_activate`.
|
165
|
+
|
166
|
+
Configure the email's from address in `config/initializers/quo_vadis.rb`.
|
167
|
+
|
168
|
+
Configure the default host so ActionMailer can generate the URL. In `config/environments/<env>.rb`:
|
169
|
+
|
170
|
+
config.action_mailer.default_url_options = {:host => 'yourdomain.com'}
|
171
|
+
|
172
|
+
Finally, write the invitation page ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/sessions/invite.html.erb)). The form must:
|
173
|
+
|
174
|
+
* be in `app/views/sessions/invite.html.:format`
|
175
|
+
* POST the parameters `:username` and `:password` to `activation_url(params[:token])`
|
176
|
+
|
177
|
+
If the token expires and you need to generate a new one, re-invite the user with: `invite_to_activate @user`.
|
178
|
+
|
179
|
+
|
180
|
+
## Customisation
|
181
|
+
|
182
|
+
You can customise the flash messages and mailer from/subject in `config/locales/quo_vadis.en.yml`.
|
183
|
+
|
184
|
+
You can customise the sign-in and sign-out redirects in `config/initializers/quo_vadis.rb`; they both default to the root route. You can also hook into the sign-in and sign-out process if you need to run any other code.
|
185
|
+
|
186
|
+
If you want to add other session management type features, go right ahead: create a `SessionsController` as normal and carry on.
|
187
|
+
|
188
|
+
You can skip the validation of authentication attributes (password etc) by overriding `should_authenticate?` in your model. Perhaps only some of the users should be able to sign in, so you don't want to force them to have a password.
|
139
189
|
|
140
190
|
|
141
191
|
## See also
|
@@ -39,7 +39,7 @@ class QuoVadis::SessionsController < ApplicationController
|
|
39
39
|
if params[:username].present? &&
|
40
40
|
(user = QuoVadis.model_class.where(:username => params[:username]).first)
|
41
41
|
if user.email.present?
|
42
|
-
user.generate_token
|
42
|
+
user.generate_token!
|
43
43
|
QuoVadis::Notifier.change_password(user).deliver
|
44
44
|
flash_if_present :notice, 'quo_vadis.flash.forgotten.sent_email'
|
45
45
|
redirect_to :root
|
@@ -59,7 +59,7 @@ class QuoVadis::SessionsController < ApplicationController
|
|
59
59
|
if QuoVadis.model_class.valid_token(params[:token]).first
|
60
60
|
render 'sessions/edit'
|
61
61
|
else
|
62
|
-
invalid_token
|
62
|
+
invalid_token :forgotten
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -79,15 +79,58 @@ class QuoVadis::SessionsController < ApplicationController
|
|
79
79
|
render 'sessions/edit'
|
80
80
|
end
|
81
81
|
else
|
82
|
-
invalid_token
|
82
|
+
invalid_token :forgotten
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
+
# GET invitation_path /sign-in/invite/:token
|
87
|
+
def invite
|
88
|
+
if (user = QuoVadis.model_class.valid_token(params[:token]).first)
|
89
|
+
render 'sessions/invite'
|
90
|
+
else
|
91
|
+
invalid_token :activation
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# POST activation_path /sign-in/accept/:token
|
96
|
+
def accept
|
97
|
+
if (user = QuoVadis.model_class.valid_token(params[:token]).first)
|
98
|
+
user.username, user.password = params[:username], params[:password]
|
99
|
+
# When we create a user who must activate their account, we give them
|
100
|
+
# a random username and password. However we want to treat them as if
|
101
|
+
# they weren't set at all.
|
102
|
+
user.password_digest = nil if params[:password].blank?
|
103
|
+
if user.save
|
104
|
+
user.clear_token
|
105
|
+
flash_if_present :notice, 'quo_vadis.flash.activation.accepted'
|
106
|
+
sign_in user
|
107
|
+
else
|
108
|
+
render 'sessions/invite'
|
109
|
+
end
|
110
|
+
else
|
111
|
+
invalid_token :activation
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Invites a user to set up their sign-in credentials.
|
116
|
+
def invite_to_activate(user, data = {})
|
117
|
+
return false if user.email.blank?
|
118
|
+
user.generate_token!
|
119
|
+
QuoVadis::Notifier.invite(user, data).deliver
|
120
|
+
true
|
121
|
+
end
|
122
|
+
hide_action :send_invitation
|
123
|
+
|
86
124
|
private
|
87
125
|
|
88
|
-
def invalid_token # :nodoc:
|
89
|
-
|
90
|
-
|
126
|
+
def invalid_token(workflow) # :nodoc:
|
127
|
+
if workflow == :activation
|
128
|
+
flash_if_present :alert, 'quo_vadis.flash.activation.invalid_token'
|
129
|
+
redirect_to root_path
|
130
|
+
else
|
131
|
+
flash_if_present :alert, 'quo_vadis.flash.forgotten.invalid_token'
|
132
|
+
redirect_to forgotten_sign_in_url
|
133
|
+
end
|
91
134
|
end
|
92
135
|
|
93
136
|
def quo_vadis_layout # :nodoc:
|
@@ -6,7 +6,19 @@ module QuoVadis
|
|
6
6
|
def change_password(user)
|
7
7
|
@username = user.username
|
8
8
|
@url = change_password_url user.token
|
9
|
-
mail :to => user.email, :from => QuoVadis.from, :subject => QuoVadis.
|
9
|
+
mail :to => user.email, :from => QuoVadis.from, :subject => QuoVadis.subject_change_password
|
10
|
+
end
|
11
|
+
|
12
|
+
# Sends an email to <tt>user</tt> with a link to a page where they
|
13
|
+
# can choose their username and password.
|
14
|
+
#
|
15
|
+
# `data` - hash of data to pass to view via instance variables. A key of `:foo`
|
16
|
+
# will be available via `@foo`.
|
17
|
+
def invite(user, data = {})
|
18
|
+
@user = user
|
19
|
+
@url = invitation_url user.token
|
20
|
+
data.each { |k,v| instance_variable_set :"@#{k}", v }
|
21
|
+
mail :to => user.email, :from => QuoVadis.from, :subject => QuoVadis.subject_invitation
|
10
22
|
end
|
11
23
|
|
12
24
|
end
|
data/app/models/model_mixin.rb
CHANGED
@@ -44,6 +44,17 @@ module ModelMixin
|
|
44
44
|
nil
|
45
45
|
end
|
46
46
|
end
|
47
|
+
|
48
|
+
# Instantiates a user suitable for user-activation.
|
49
|
+
def new_for_activation(attributes = nil)
|
50
|
+
user = new attributes
|
51
|
+
# Satisfy username and password validations by setting to random values.
|
52
|
+
begin
|
53
|
+
user.username = SecureRandom.base64(10)
|
54
|
+
end while exists?(:username => user.username)
|
55
|
+
user.password = SecureRandom.base64(10)
|
56
|
+
user
|
57
|
+
end
|
47
58
|
END
|
48
59
|
end
|
49
60
|
end
|
@@ -61,13 +72,18 @@ module ModelMixin
|
|
61
72
|
end
|
62
73
|
end
|
63
74
|
|
64
|
-
# Generates a unique, timestamped token
|
65
|
-
# saves the record. This is part of the forgotten-password workflow.
|
75
|
+
# Generates a unique, timestamped token.
|
66
76
|
def generate_token # :nodoc:
|
67
77
|
begin
|
68
78
|
self.token = url_friendly_token
|
69
79
|
end while self.class.exists?(:token => token)
|
70
80
|
self.token_created_at = Time.now.utc
|
81
|
+
end
|
82
|
+
|
83
|
+
# Generates a unique, timestamped token which can be used in URLs, and
|
84
|
+
# saves the record. This is part of the forgotten-password workflow.
|
85
|
+
def generate_token! # :nodoc:
|
86
|
+
generate_token
|
71
87
|
save
|
72
88
|
end
|
73
89
|
|
@@ -15,3 +15,7 @@ en:
|
|
15
15
|
sent_email: "We've emailed you a link where you can change your password."
|
16
16
|
invalid_token: "Sorry, this link isn't valid anymore."
|
17
17
|
password_changed: "You have successfully changed your password and you're now signed in."
|
18
|
+
|
19
|
+
activation:
|
20
|
+
accepted: "Your account is active and you're now signed in."
|
21
|
+
invalid_token: "Sorry, this link isn't valid anymore."
|
data/config/routes.rb
CHANGED
@@ -6,8 +6,10 @@ Rails.application.routes.draw do
|
|
6
6
|
get 'sign-in/forgotten' => 'sessions#forgotten', :as => 'forgotten_sign_in'
|
7
7
|
post 'sign-in/forgotten' => 'sessions#forgotten', :as => 'forgotten_sign_in'
|
8
8
|
constraints :token => /.+/ do
|
9
|
-
get
|
10
|
-
put
|
9
|
+
get 'sign-in/change-password/:token' => 'sessions#edit', :as => 'change_password'
|
10
|
+
put 'sign-in/change-password/:token' => 'sessions#update', :as => 'change_password'
|
11
|
+
get 'sign-in/invite/:token' => 'sessions#invite', :as => 'invitation'
|
12
|
+
post 'sign-in/accept/:token' => 'sessions#accept', :as => 'activation'
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
@@ -3,9 +3,9 @@ class AddAuthenticationTo<%= model_name.pluralize.camelize %> < ActiveRecord::Mi
|
|
3
3
|
add_column :<%= model_name.tableize %>, :username, :string # for user identification
|
4
4
|
add_column :<%= model_name.tableize %>, :password_digest, :string
|
5
5
|
|
6
|
-
add_column :<%= model_name.tableize %>, :email, :string # for forgotten-credentials
|
7
|
-
add_column :<%= model_name.tableize %>, :token, :string # for forgotten-credentials
|
8
|
-
add_column :<%= model_name.tableize %>, :token_created_at, :string # for forgotten-credentials
|
6
|
+
add_column :<%= model_name.tableize %>, :email, :string # for forgotten-credentials / activation
|
7
|
+
add_column :<%= model_name.tableize %>, :token, :string # for forgotten-credentials / activation
|
8
|
+
add_column :<%= model_name.tableize %>, :token_created_at, :string # for forgotten-credentials / activation
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.down
|
@@ -73,14 +73,17 @@ QuoVadis.configure do |config|
|
|
73
73
|
|
74
74
|
|
75
75
|
#
|
76
|
-
# Forgotten-password Mailer
|
76
|
+
# Forgotten-password and activation Mailer
|
77
77
|
#
|
78
78
|
|
79
79
|
# From whom the forgotten-password email should be sent.
|
80
80
|
config.from = 'noreply@example.com'
|
81
81
|
|
82
82
|
# Subject of the forgotten-password email.
|
83
|
-
config.
|
83
|
+
config.subject_change_password = 'Change your password'
|
84
|
+
|
85
|
+
# Subject of the invitation email.
|
86
|
+
config.subject_invitation = 'Activate your account'
|
84
87
|
|
85
88
|
|
86
89
|
#
|
data/lib/quo_vadis/version.rb
CHANGED
data/lib/quo_vadis.rb
CHANGED
@@ -94,7 +94,7 @@ module QuoVadis
|
|
94
94
|
|
95
95
|
|
96
96
|
#
|
97
|
-
# Forgotten-password Mailer
|
97
|
+
# Forgotten-password and activation Mailer
|
98
98
|
#
|
99
99
|
|
100
100
|
# From whom the forgotten-password email should be sent.
|
@@ -102,9 +102,12 @@ module QuoVadis
|
|
102
102
|
@@from = 'noreply@example.com'
|
103
103
|
|
104
104
|
# Subject of the forgotten-password email.
|
105
|
-
mattr_accessor :
|
106
|
-
@@
|
105
|
+
mattr_accessor :subject_change_password
|
106
|
+
@@subject_change_password = 'Change your password.'
|
107
107
|
|
108
|
+
# Subject of the invitation email.
|
109
|
+
mattr_accessor :subject_invitation
|
110
|
+
@@subject_invitation = 'Activate your account'
|
108
111
|
|
109
112
|
|
110
113
|
#
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<h1>Choose your username and password</h1>
|
2
|
+
|
3
|
+
<%= form_tag activation_path(params[:token]) do %>
|
4
|
+
<p>
|
5
|
+
<%= label_tag :username %>
|
6
|
+
<%= text_field_tag :username %>
|
7
|
+
</p>
|
8
|
+
<p>
|
9
|
+
<%= label_tag :password %>
|
10
|
+
<%= password_field_tag :password %>
|
11
|
+
</p>
|
12
|
+
<p>
|
13
|
+
<%= submit_tag 'Save my details' %>
|
14
|
+
</p>
|
15
|
+
<% end %>
|
@@ -68,7 +68,10 @@ QuoVadis.configure do |config|
|
|
68
68
|
config.from = 'noreply@example.com'
|
69
69
|
|
70
70
|
# Subject of the forgotten-password email.
|
71
|
-
config.
|
71
|
+
config.subject_change_password = 'Change your password'
|
72
|
+
|
73
|
+
# Subject of the invitation email.
|
74
|
+
config.subject_invitation = 'Activate your account'
|
72
75
|
|
73
76
|
|
74
77
|
#
|
@@ -15,3 +15,7 @@ en:
|
|
15
15
|
sent_email: "We've emailed you a link where you can change your password."
|
16
16
|
invalid_token: "Sorry, this link isn't valid anymore."
|
17
17
|
password_changed: "You have successfully changed your password and you're now signed in."
|
18
|
+
|
19
|
+
activation:
|
20
|
+
accepted: "Your account is active and you're now signed in."
|
21
|
+
invalid_token: "Sorry, this link isn't valid anymore."
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActivationTest < ActiveSupport::IntegrationCase
|
4
|
+
|
5
|
+
teardown do
|
6
|
+
Capybara.reset_sessions!
|
7
|
+
end
|
8
|
+
|
9
|
+
test 'a user can be invited' do
|
10
|
+
user = User.new_for_activation :name => 'Bob', :email => 'bob@example.com'
|
11
|
+
assert user.save
|
12
|
+
assert QuoVadis::SessionsController.new.invite_to_activate user
|
13
|
+
|
14
|
+
assert ActionMailer::Base.deliveries.last
|
15
|
+
assert !ActionMailer::Base.deliveries.empty?
|
16
|
+
email = ActionMailer::Base.deliveries.last
|
17
|
+
|
18
|
+
assert_equal ['bob@example.com'], email.to
|
19
|
+
assert_equal ['noreply@example.com'], email.from
|
20
|
+
assert_equal 'Activate your account', email.subject
|
21
|
+
# Why doesn't this use the default url option set up in test/test_helper.rb#9?
|
22
|
+
assert_match Regexp.new(Regexp.escape(invitation_url user.token, :host => 'www.example.com')), email.encoded
|
23
|
+
end
|
24
|
+
|
25
|
+
test 'a user without email cannot be invited' do
|
26
|
+
user = User.new_for_activation :name => 'Bob'
|
27
|
+
assert user.save
|
28
|
+
assert ! QuoVadis::SessionsController.new.invite_to_activate(user)
|
29
|
+
end
|
30
|
+
|
31
|
+
test 'user can accept a valid invitation and set valid credentials' do
|
32
|
+
user = User.new_for_activation :name => 'Bob', :email => 'bob@example.com'
|
33
|
+
user.generate_token
|
34
|
+
assert user.save
|
35
|
+
|
36
|
+
visit invitation_url(user.token, :host => 'www.example.com')
|
37
|
+
fill_in 'Username', :with => 'bob'
|
38
|
+
fill_in 'Password', :with => 'secret'
|
39
|
+
click_button 'Save my details'
|
40
|
+
assert_equal root_path, current_path
|
41
|
+
within '.flash.notice' do
|
42
|
+
assert page.has_content?("Your account is active and you're now signed in.")
|
43
|
+
end
|
44
|
+
assert_nil user.reload.token
|
45
|
+
assert_nil user.token_created_at
|
46
|
+
end
|
47
|
+
|
48
|
+
test 'user can accept a valid invitation but not set invalid credentials' do
|
49
|
+
user = User.new_for_activation :name => 'Bob', :email => 'bob@example.com'
|
50
|
+
user.generate_token
|
51
|
+
assert user.save
|
52
|
+
|
53
|
+
visit invitation_url(user.token, :host => 'www.example.com')
|
54
|
+
fill_in 'Username', :with => 'bob'
|
55
|
+
fill_in 'Password', :with => ''
|
56
|
+
click_button 'Save my details'
|
57
|
+
assert_equal activation_path(user.token), current_path
|
58
|
+
assert user.reload.token
|
59
|
+
assert user.token_created_at
|
60
|
+
end
|
61
|
+
|
62
|
+
test 'user cannot view an expired invitation' do
|
63
|
+
user = User.new_for_activation :name => 'Bob', :email => 'bob@example.com'
|
64
|
+
user.generate_token
|
65
|
+
assert user.save
|
66
|
+
user.update_attributes :token_created_at => 1.day.ago
|
67
|
+
|
68
|
+
visit invitation_url(user.token, :host => 'www.example.com')
|
69
|
+
assert_equal root_path, current_path
|
70
|
+
within '.flash.alert' do
|
71
|
+
assert page.has_content?("Sorry, this link isn't valid anymore.")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
test 'user cannot accept an expired invitation' do
|
76
|
+
user = User.new_for_activation :name => 'Bob', :email => 'bob@example.com'
|
77
|
+
user.generate_token
|
78
|
+
assert user.save
|
79
|
+
|
80
|
+
visit invitation_url(user.token, :host => 'www.example.com')
|
81
|
+
user.update_attributes :token_created_at => 1.day.ago
|
82
|
+
fill_in 'Username', :with => 'bob'
|
83
|
+
fill_in 'Password', :with => 'secret'
|
84
|
+
click_button 'Save my details'
|
85
|
+
assert_equal root_path, current_path
|
86
|
+
within '.flash.alert' do
|
87
|
+
assert page.has_content?("Sorry, this link isn't valid anymore.")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
test 'data can be passed to invitation email' do
|
92
|
+
user = User.new_for_activation :name => 'Bob', :email => 'bob@example.com'
|
93
|
+
assert user.save
|
94
|
+
assert QuoVadis::SessionsController.new.invite_to_activate user, :foo => 'Barbaz'
|
95
|
+
email = ActionMailer::Base.deliveries.last
|
96
|
+
assert_match Regexp.new('Barbaz'), email.encoded
|
97
|
+
end
|
98
|
+
end
|
@@ -108,18 +108,25 @@ class ConfigTest < ActiveSupport::IntegrationCase
|
|
108
108
|
assert page.has_content?('Sessions layout')
|
109
109
|
end
|
110
110
|
|
111
|
-
test 'mailer from config' do
|
111
|
+
test 'change-password mailer from config' do
|
112
112
|
QuoVadis.from = 'jim@example.com'
|
113
113
|
(user = User.last).generate_token
|
114
114
|
email = QuoVadis::Notifier.change_password(user)
|
115
115
|
assert_equal ['jim@example.com'], email.from
|
116
116
|
end
|
117
117
|
|
118
|
-
test 'mailer subject config' do
|
119
|
-
QuoVadis.
|
118
|
+
test 'change-password mailer subject config' do
|
119
|
+
QuoVadis.subject_change_password = 'You idiot!'
|
120
120
|
(user = User.last).generate_token
|
121
121
|
email = QuoVadis::Notifier.change_password(user)
|
122
122
|
assert_equal 'You idiot!', email.subject
|
123
123
|
end
|
124
124
|
|
125
|
+
test 'invitation mailer subject config' do
|
126
|
+
QuoVadis.subject_invitation = 'Wooha'
|
127
|
+
(user = User.last).generate_token
|
128
|
+
email = QuoVadis::Notifier.invite(user)
|
129
|
+
assert_equal 'Wooha', email.subject
|
130
|
+
end
|
131
|
+
|
125
132
|
end
|
@@ -171,7 +171,7 @@ class LocaleTest < ActiveSupport::IntegrationCase
|
|
171
171
|
|
172
172
|
test 'forgotten.password_changed flash' do
|
173
173
|
user_factory 'Bob', 'bob', 'secret', 'bob@example.com'
|
174
|
-
User.last.generate_token
|
174
|
+
User.last.generate_token!
|
175
175
|
visit change_password_path(User.last.token)
|
176
176
|
fill_in :password, :with => 'topsecret'
|
177
177
|
click_button 'Change my password'
|
@@ -184,7 +184,7 @@ class LocaleTest < ActiveSupport::IntegrationCase
|
|
184
184
|
begin
|
185
185
|
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:forgotten => {:password_changed => ''}}}}
|
186
186
|
user_factory 'Bob', 'bob', 'secret', 'bob@example.com'
|
187
|
-
User.last.generate_token
|
187
|
+
User.last.generate_token!
|
188
188
|
visit change_password_path(User.last.token)
|
189
189
|
fill_in :password, :with => 'topsecret'
|
190
190
|
click_button 'Change my password'
|
@@ -14,13 +14,13 @@ class SignInPersonTest < ActiveSupport::IntegrationCase
|
|
14
14
|
|
15
15
|
END
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
person_factory 'James', 'jim', 'secret'
|
18
|
+
sign_in_as 'jim', 'secret'
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
assert_equal root_path, current_path
|
21
|
+
within '.flash.notice' do
|
22
|
+
assert page.has_content?('You have successfully signed in.')
|
23
|
+
end
|
24
24
|
end
|
25
25
|
|
26
26
|
end
|
data/test/test_helper.rb
CHANGED
@@ -56,7 +56,8 @@ def reset_quo_vadis_configuration
|
|
56
56
|
QuoVadis.signed_out_hook = nil
|
57
57
|
QuoVadis.layout = 'application'
|
58
58
|
QuoVadis.from = 'noreply@example.com'
|
59
|
-
QuoVadis.
|
59
|
+
QuoVadis.subject_change_password = 'Change your password'
|
60
|
+
QuoVadis.subject_invitation = 'Activate your account'
|
60
61
|
QuoVadis.remember_for = 2.weeks
|
61
62
|
QuoVadis.blocked = false
|
62
63
|
end
|
data/test/unit/user_test.rb
CHANGED
@@ -51,4 +51,14 @@ class UserTest < ActiveSupport::TestCase
|
|
51
51
|
assert user.valid?
|
52
52
|
end
|
53
53
|
|
54
|
+
test 'create for activation' do
|
55
|
+
user = User.new_for_activation :name => 'Bob'
|
56
|
+
assert user.valid?
|
57
|
+
|
58
|
+
user = User.new_for_activation :name => 'John', :username => 'john', :password => 'secret'
|
59
|
+
assert user.valid?
|
60
|
+
assert_not_equal 'john', user.username
|
61
|
+
assert_not_equal 'secret', user.password
|
62
|
+
end
|
63
|
+
|
54
64
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quo_vadis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement: &
|
16
|
+
requirement: &2156553540 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2156553540
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: bcrypt-ruby
|
27
|
-
requirement: &
|
27
|
+
requirement: &2156550300 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 3.0.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2156550300
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rails
|
38
|
-
requirement: &
|
38
|
+
requirement: &2156568880 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 3.0.4
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2156568880
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: sqlite3-ruby
|
49
|
-
requirement: &
|
49
|
+
requirement: &2156564820 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2156564820
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: capybara
|
60
|
-
requirement: &
|
60
|
+
requirement: &2152428460 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '1.1'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *2152428460
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: launchy
|
71
|
-
requirement: &
|
71
|
+
requirement: &2152426880 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *2152426880
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rake
|
82
|
-
requirement: &
|
82
|
+
requirement: &2152425340 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,7 +87,7 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *2152425340
|
91
91
|
description: Simple username/password authentication for Rails 3.
|
92
92
|
email:
|
93
93
|
- boss@airbladesoftware.com
|
@@ -128,8 +128,10 @@ files:
|
|
128
128
|
- test/dummy/app/views/layouts/application.html.erb
|
129
129
|
- test/dummy/app/views/layouts/sessions.html.erb
|
130
130
|
- test/dummy/app/views/quo_vadis/notifier/change_password.text.erb
|
131
|
+
- test/dummy/app/views/quo_vadis/notifier/invite.text.erb
|
131
132
|
- test/dummy/app/views/sessions/edit.html.erb
|
132
133
|
- test/dummy/app/views/sessions/forgotten.html.erb
|
134
|
+
- test/dummy/app/views/sessions/invite.html.erb
|
133
135
|
- test/dummy/app/views/sessions/new.html.erb
|
134
136
|
- test/dummy/app/views/users/new.html.erb
|
135
137
|
- test/dummy/config.ru
|
@@ -144,6 +146,7 @@ files:
|
|
144
146
|
- test/dummy/config/initializers/inflections.rb
|
145
147
|
- test/dummy/config/initializers/mime_types.rb
|
146
148
|
- test/dummy/config/initializers/quo_vadis.rb
|
149
|
+
- test/dummy/config/initializers/rack_patch.rb
|
147
150
|
- test/dummy/config/initializers/secret_token.rb
|
148
151
|
- test/dummy/config/initializers/session_store.rb
|
149
152
|
- test/dummy/config/locales/en.yml
|
@@ -167,6 +170,7 @@ files:
|
|
167
170
|
- test/dummy/public/javascripts/rails.js
|
168
171
|
- test/dummy/public/stylesheets/.gitkeep
|
169
172
|
- test/dummy/script/rails
|
173
|
+
- test/integration/activation_test.rb
|
170
174
|
- test/integration/authenticate_test.rb
|
171
175
|
- test/integration/blocked_test.rb
|
172
176
|
- test/integration/config_test.rb
|
@@ -198,7 +202,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
198
202
|
version: '0'
|
199
203
|
segments:
|
200
204
|
- 0
|
201
|
-
hash:
|
205
|
+
hash: -4183127178798820750
|
202
206
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
203
207
|
none: false
|
204
208
|
requirements:
|
@@ -207,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
211
|
version: '0'
|
208
212
|
segments:
|
209
213
|
- 0
|
210
|
-
hash:
|
214
|
+
hash: -4183127178798820750
|
211
215
|
requirements: []
|
212
216
|
rubyforge_project: quo_vadis
|
213
217
|
rubygems_version: 1.8.11
|
@@ -230,8 +234,10 @@ test_files:
|
|
230
234
|
- test/dummy/app/views/layouts/application.html.erb
|
231
235
|
- test/dummy/app/views/layouts/sessions.html.erb
|
232
236
|
- test/dummy/app/views/quo_vadis/notifier/change_password.text.erb
|
237
|
+
- test/dummy/app/views/quo_vadis/notifier/invite.text.erb
|
233
238
|
- test/dummy/app/views/sessions/edit.html.erb
|
234
239
|
- test/dummy/app/views/sessions/forgotten.html.erb
|
240
|
+
- test/dummy/app/views/sessions/invite.html.erb
|
235
241
|
- test/dummy/app/views/sessions/new.html.erb
|
236
242
|
- test/dummy/app/views/users/new.html.erb
|
237
243
|
- test/dummy/config.ru
|
@@ -246,6 +252,7 @@ test_files:
|
|
246
252
|
- test/dummy/config/initializers/inflections.rb
|
247
253
|
- test/dummy/config/initializers/mime_types.rb
|
248
254
|
- test/dummy/config/initializers/quo_vadis.rb
|
255
|
+
- test/dummy/config/initializers/rack_patch.rb
|
249
256
|
- test/dummy/config/initializers/secret_token.rb
|
250
257
|
- test/dummy/config/initializers/session_store.rb
|
251
258
|
- test/dummy/config/locales/en.yml
|
@@ -269,6 +276,7 @@ test_files:
|
|
269
276
|
- test/dummy/public/javascripts/rails.js
|
270
277
|
- test/dummy/public/stylesheets/.gitkeep
|
271
278
|
- test/dummy/script/rails
|
279
|
+
- test/integration/activation_test.rb
|
272
280
|
- test/integration/authenticate_test.rb
|
273
281
|
- test/integration/blocked_test.rb
|
274
282
|
- test/integration/config_test.rb
|