quo_vadis 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## 1.2.0 (18 July 2012)
5
+
6
+ * User activation.
7
+
8
+
4
9
  ## 1.1.2 (7 February 2012)
5
10
 
6
11
  * Replace ActiveSupport::SecureRandom with SecureRandom.
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
- ## Customisation
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
- 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.
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
- If you want to add other session management type features, go right ahead: create a `SessionsController` as normal and carry on.
116
-
117
- 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.
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
- Quo Vadis doesn't offer sign-up because that's user management, not authentication.
127
+ ## Sign up (with activation)
123
128
 
124
- However if you have implemented user sign-up yourself, you need to be able to sign in a newly created user. Do this by calling `sign_in(user)` in your controller. For example:
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.new params[:user]
134
+ @user = User.new_for_activation params[:user] # <-- NOTE: different constructor
130
135
  if @user.save
131
- sign_in @user # <-- NOTE: sign in your user here
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 `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.
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
- flash_if_present :alert, 'quo_vadis.flash.forgotten.invalid_token'
90
- redirect_to forgotten_sign_in_url
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.subject
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
@@ -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 which can be used in URLs, and
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 'sign-in/change-password/:token' => 'sessions#edit', :as => 'change_password'
10
- put 'sign-in/change-password/:token' => 'sessions#update', :as => 'change_password'
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.subject = 'Change your password'
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
  #
@@ -1,3 +1,3 @@
1
1
  module QuoVadis
2
- VERSION = '1.1.2'
2
+ VERSION = '1.2.0'
3
3
  end
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 :subject
106
- @@subject = 'Change your password.'
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,8 @@
1
+ Hello <%= @user.name %>,
2
+
3
+ You can activate your account by clicking this link (valid for 3 hours):
4
+ <%= @url %>
5
+
6
+ <% if instance_variable_defined? :@foo %><%= @foo %><% end %>
7
+
8
+ Thanks!
@@ -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.subject = 'Change your password'
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
  #
@@ -0,0 +1,16 @@
1
+ # TODO: remove once on Rack 1.3.0.
2
+ # https://github.com/jnicklas/capybara/issues/87#issuecomment-2106788
3
+ module Rack
4
+ module Utils
5
+
6
+ def escape(s)
7
+ CGI.escape s.to_s
8
+ end
9
+
10
+ def unescape(s)
11
+ CGI.unescape s
12
+ end
13
+
14
+ end
15
+ end
16
+
@@ -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.subject = 'You idiot!'
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
- # person_factory 'James', 'jim', 'secret'
18
- # sign_in_as 'jim', 'secret'
17
+ person_factory 'James', 'jim', 'secret'
18
+ sign_in_as 'jim', 'secret'
19
19
 
20
- # assert_equal root_path, current_path
21
- # within '.flash.notice' do
22
- # assert page.has_content?('You have successfully signed in.')
23
- # end
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.subject = 'Change your password'
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
@@ -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.1.2
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-02-07 00:00:00.000000000 Z
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: &2157988380 !ruby/object:Gem::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: *2157988380
24
+ version_requirements: *2156553540
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: bcrypt-ruby
27
- requirement: &2157987500 !ruby/object:Gem::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: *2157987500
35
+ version_requirements: *2156550300
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rails
38
- requirement: &2157986780 !ruby/object:Gem::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: *2157986780
46
+ version_requirements: *2156568880
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: sqlite3-ruby
49
- requirement: &2157986100 !ruby/object:Gem::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: *2157986100
57
+ version_requirements: *2156564820
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: capybara
60
- requirement: &2157967940 !ruby/object:Gem::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: *2157967940
68
+ version_requirements: *2152428460
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: launchy
71
- requirement: &2157967080 !ruby/object:Gem::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: *2157967080
79
+ version_requirements: *2152426880
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rake
82
- requirement: &2157965940 !ruby/object:Gem::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: *2157965940
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: 4176509777758211908
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: 4176509777758211908
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