quo_vadis 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +48 -7
- data/app/controllers/controller_mixin.rb +2 -2
- data/app/controllers/quo_vadis/sessions_controller.rb +65 -8
- data/app/mailers/quo_vadis/notifier.rb +11 -0
- data/app/models/model_mixin.rb +23 -3
- data/config/initializers/quo_vadis.rb +11 -0
- data/config/locales/quo_vadis.en.yml +12 -3
- data/config/routes.rb +10 -4
- data/lib/generators/quo_vadis/templates/migration.rb +9 -2
- data/lib/quo_vadis/version.rb +1 -1
- data/lib/quo_vadis.rb +13 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/views/quo_vadis/notifier/change_password.text.erb +9 -0
- data/test/dummy/app/views/sessions/edit.html.erb +11 -0
- data/test/dummy/app/views/sessions/forgotten.html.erb +13 -0
- data/test/dummy/config/environments/test.rb +2 -0
- data/test/dummy/config/initializers/quo_vadis.rb +58 -0
- data/test/dummy/config/locales/quo_vadis.en.yml +7 -0
- data/test/dummy/db/migrate/20110127094709_add_authentication_to_users.rb +18 -0
- data/test/dummy/db/schema.rb +33 -0
- data/test/integration/config_test.rb +14 -0
- data/test/integration/forgotten_test.rb +83 -0
- data/test/integration/locale_test.rb +107 -9
- data/test/test_helper.rb +11 -3
- data/test/unit/user_test.rb +31 -0
- metadata +25 -6
- data/test/dummy/db/migrate/20110124125216_add_authentication_to_users.rb +0 -11
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -8,11 +8,11 @@ Features:
|
|
8
8
|
* No surprises: it does what you expect.
|
9
9
|
* Easy to customise.
|
10
10
|
* Uses BCrypt to encrypt passwords.
|
11
|
-
* Sign in, sign out, authenticate actions.
|
11
|
+
* Sign in, sign out, forgotten password, authenticate actions.
|
12
12
|
|
13
13
|
Forthcoming features:
|
14
14
|
|
15
|
-
*
|
15
|
+
* Generate the views for you.
|
16
16
|
* Let you choose which model(s) to authenticate (currently `User`).
|
17
17
|
* Let you choose the identification field (currently `username`).
|
18
18
|
* Remember authenticated user across browser sessions.
|
@@ -35,9 +35,9 @@ What it doesn't and won't do:
|
|
35
35
|
|
36
36
|
If this takes you more than 5 minutes, you can have your money back ;)
|
37
37
|
|
38
|
-
Install and run the generator: add `gem 'quo_vadis'` to your Gemfile
|
38
|
+
Install and run the generator: add `gem 'quo_vadis'` to your Gemfile, run `bundle install`, then `rails generate quo_vadis:install`.
|
39
39
|
|
40
|
-
Edit and run the generated migration to add authentication columns: `rake db:migrate`. Note the migration (currently) assumes you already have a `User` model.
|
40
|
+
Edit and run the generated migration to add the authentication columns: `rake db:migrate`. Note the migration (currently) assumes you already have a `User` model.
|
41
41
|
|
42
42
|
In your `User` model, add `authenticates`:
|
43
43
|
|
@@ -45,7 +45,7 @@ In your `User` model, add `authenticates`:
|
|
45
45
|
authenticates
|
46
46
|
end
|
47
47
|
|
48
|
-
Note Quo Vadis validates the presence of the password, but it's up to you to add any other validations you want.
|
48
|
+
Note Quo Vadis validates the presence and uniqueness of the username, and the presence of the password, but it's up to you to add any other validations you want.
|
49
49
|
|
50
50
|
Use `:authenticate` in a `before_filter` to protect your controllers' actions. For example:
|
51
51
|
|
@@ -56,11 +56,52 @@ Use `:authenticate` in a `before_filter` to protect your controllers' actions.
|
|
56
56
|
Write the sign-in view. Your sign-in form must:
|
57
57
|
|
58
58
|
* be in `app/views/sessions/new.html.:format`
|
59
|
-
*
|
59
|
+
* POST the parameters `:username` and `:password` to `sign_in_url`
|
60
60
|
|
61
61
|
You have to write the view yourself because you'd inevitably want to change whatever markup I generated for you.
|
62
62
|
|
63
|
-
|
63
|
+
Remember to serve your sign in form over HTTPS -- to avoid [the credentials being stolen](http://blog.jgc.org/2011/01/code-injected-to-steal-passwords-in.html).
|
64
|
+
|
65
|
+
In your layout, use `current_user` to retrieve the signed-in user; and `sign_in_path`, `sign_out_path`, and `forgotten_sign_in_path` as appropriate.
|
66
|
+
|
67
|
+
|
68
|
+
## Forgotten Password
|
69
|
+
|
70
|
+
Here's the workflow:
|
71
|
+
|
72
|
+
1. [Sign in page] The user clicks the "I've forgotten my password" link.
|
73
|
+
2. [Forgotten password page] The user enters their username in the form and submits it.
|
74
|
+
3. Quo Vadis emails the user a message with a change-password link. The link is valid for 3 hours.
|
75
|
+
4. [The email] The user clicks the link.
|
76
|
+
5. [Change password page] The user types in a new password and saves it.
|
77
|
+
6. Quo Vadis changes the user's password and signs the user in.
|
78
|
+
|
79
|
+
It'll take you about 5 minutes to implement this.
|
80
|
+
|
81
|
+
On your sign-in page, link to the forgotten-password view at `forgotten_sign_in_url`.
|
82
|
+
|
83
|
+
Write the forgotten-password view. The form must:
|
84
|
+
|
85
|
+
* be in `app/views/sessions/forgotten.html.:format`
|
86
|
+
* POST the parameter `:username` to `forgotten_sign_in_url`
|
87
|
+
|
88
|
+
Now write the mailer view, i.e. the email which will be sent to your forgetful users. The view must:
|
89
|
+
|
90
|
+
* be at `app/views/quo_vadis/notifier/change_password.text.erb`
|
91
|
+
* render `@url` somewhere (this is the link the user clicks to go to the change-password page)
|
92
|
+
|
93
|
+
You can also refer to `@username` in the email view.
|
94
|
+
|
95
|
+
Configure the email's from address in `config/initializers/quo_vadis.rb`.
|
96
|
+
|
97
|
+
Configure the default host so ActionMailer can generate the URL. In `config/environments/<env>.rb`:
|
98
|
+
|
99
|
+
config.action_mailer.default_url_options = {:host => 'yourdomain.com'}
|
100
|
+
|
101
|
+
Finally, write the change-password page. The form must:
|
102
|
+
|
103
|
+
* be in `app/views/sessions/edit.html.:format`
|
104
|
+
* PUT the parameter `:password` to `change_password_url(params[:token])`
|
64
105
|
|
65
106
|
|
66
107
|
## Customisation
|
@@ -3,7 +3,7 @@ module ControllerMixin
|
|
3
3
|
base.helper_method :current_user
|
4
4
|
end
|
5
5
|
|
6
|
-
private
|
6
|
+
private
|
7
7
|
|
8
8
|
def current_user=(user)
|
9
9
|
session[:current_user_id] = user ? user.id : nil
|
@@ -16,7 +16,7 @@ module ControllerMixin
|
|
16
16
|
def authenticate
|
17
17
|
unless current_user
|
18
18
|
session[:quo_vadis_original_url] = request.fullpath
|
19
|
-
flash[:notice] = t('quo_vadis.flash.
|
19
|
+
flash[:notice] = t('quo_vadis.flash.sign_in.before') unless t('quo_vadis.flash.sign_in.before').blank?
|
20
20
|
redirect_to sign_in_url
|
21
21
|
end
|
22
22
|
end
|
@@ -1,26 +1,24 @@
|
|
1
1
|
class QuoVadis::SessionsController < ApplicationController
|
2
2
|
layout :quo_vadis_layout
|
3
3
|
|
4
|
-
#
|
4
|
+
# GET sign_in_path
|
5
5
|
def new
|
6
6
|
render 'sessions/new'
|
7
7
|
end
|
8
8
|
|
9
|
-
#
|
9
|
+
# POST sign_in_path
|
10
10
|
def create
|
11
11
|
if user = User.authenticate(params[:username], params[:password])
|
12
|
-
|
13
|
-
|
14
|
-
flash[:notice] = t('quo_vadis.flash.after_sign_in') unless t('quo_vadis.flash.after_sign_in').blank?
|
15
|
-
redirect_to QuoVadis.signed_in_url(user, original_url)
|
12
|
+
flash[:notice] = t('quo_vadis.flash.sign_in.after') unless t('quo_vadis.flash.sign_in.after').blank?
|
13
|
+
sign_in user
|
16
14
|
else
|
17
15
|
QuoVadis.failed_sign_in_hook self
|
18
|
-
flash.now[:alert] = t('quo_vadis.flash.
|
16
|
+
flash.now[:alert] = t('quo_vadis.flash.sign_in.failed') unless t('quo_vadis.flash.sign_in.failed').blank?
|
19
17
|
render 'sessions/new'
|
20
18
|
end
|
21
19
|
end
|
22
20
|
|
23
|
-
#
|
21
|
+
# GET sign_out_path
|
24
22
|
def destroy
|
25
23
|
QuoVadis.signed_out_hook current_user, self
|
26
24
|
self.current_user = nil
|
@@ -28,14 +26,73 @@ class QuoVadis::SessionsController < ApplicationController
|
|
28
26
|
redirect_to QuoVadis.signed_out_url
|
29
27
|
end
|
30
28
|
|
29
|
+
# GET forgotten_sign_in_path
|
30
|
+
# POST forgotten_sign_in_path
|
31
|
+
def forgotten
|
32
|
+
if request.get?
|
33
|
+
render 'sessions/forgotten'
|
34
|
+
elsif request.post?
|
35
|
+
if (user = User.where(:username => params[:username]).first)
|
36
|
+
if user.email.present?
|
37
|
+
user.generate_token
|
38
|
+
QuoVadis::Notifier.change_password(user).deliver
|
39
|
+
flash[:notice] = t('quo_vadis.flash.forgotten.sent_email') unless t('quo_vadis.flash.forgotten.sent_email').blank?
|
40
|
+
redirect_to :root
|
41
|
+
else
|
42
|
+
flash.now[:alert] = t('quo_vadis.flash.forgotten.no_email') unless t('quo_vadis.flash.forgotten.no_email').blank?
|
43
|
+
render 'sessions/forgotten'
|
44
|
+
end
|
45
|
+
else
|
46
|
+
flash.now[:alert] = t('quo_vadis.flash.forgotten.unknown') unless t('quo_vadis.flash.forgotten.unknown').blank?
|
47
|
+
render 'sessions/forgotten'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# GET change_password_path /sign-in/change-password/:token
|
53
|
+
def edit
|
54
|
+
if User.valid_token(params[:token]).first
|
55
|
+
render 'sessions/edit'
|
56
|
+
else
|
57
|
+
invalid_token
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# PUT change_password_path /sign-in/change-password/:token
|
62
|
+
def update
|
63
|
+
if (user = User.valid_token(params[:token]).first)
|
64
|
+
user.password = params[:password]
|
65
|
+
if user.save
|
66
|
+
user.clear_token
|
67
|
+
flash[:notice] = t('quo_vadis.flash.forgotten.password_changed') unless t('quo_vadis.flash.forgotten.password_changed').blank?
|
68
|
+
sign_in user
|
69
|
+
else
|
70
|
+
render 'sessions/edit'
|
71
|
+
end
|
72
|
+
else
|
73
|
+
invalid_token
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
31
77
|
private
|
32
78
|
|
79
|
+
def sign_in(user)
|
80
|
+
self.current_user = user
|
81
|
+
QuoVadis.signed_in_hook user, self
|
82
|
+
redirect_to QuoVadis.signed_in_url(user, original_url)
|
83
|
+
end
|
84
|
+
|
33
85
|
def original_url
|
34
86
|
url = session[:quo_vadis_original_url]
|
35
87
|
session[:quo_vadis_original_url] = nil
|
36
88
|
url
|
37
89
|
end
|
38
90
|
|
91
|
+
def invalid_token
|
92
|
+
flash[:alert] = t('quo_vadis.flash.forgotten.invalid_token') unless t('quo_vadis.flash.forgotten.invalid_token').blank?
|
93
|
+
redirect_to forgotten_sign_in_url
|
94
|
+
end
|
95
|
+
|
39
96
|
def quo_vadis_layout
|
40
97
|
QuoVadis.layout
|
41
98
|
end
|
data/app/models/model_mixin.rb
CHANGED
@@ -13,9 +13,11 @@ module ModelMixin
|
|
13
13
|
attr_reader :password
|
14
14
|
attr_protected :password_digest
|
15
15
|
|
16
|
-
validates
|
17
|
-
validates
|
18
|
-
validates
|
16
|
+
validates :username, :presence => true, :uniqueness => true
|
17
|
+
validates :password, :presence => true, :if => Proc.new { |u| u.changed.include?('password_digest') }
|
18
|
+
validates :password_digest, :presence => true
|
19
|
+
|
20
|
+
scope :valid_token, lambda { |token| where("token = ? AND token_created_at > ?", token, 3.hours.ago) }
|
19
21
|
|
20
22
|
instance_eval <<-END
|
21
23
|
def authenticate(username, plain_text_password)
|
@@ -36,9 +38,27 @@ module ModelMixin
|
|
36
38
|
self.password_digest = BCrypt::Password.create plain_text_password
|
37
39
|
end
|
38
40
|
|
41
|
+
def generate_token
|
42
|
+
begin
|
43
|
+
self.token = url_friendly_token
|
44
|
+
end while self.class.exists?(:token => token)
|
45
|
+
self.token_created_at = Time.now.utc
|
46
|
+
save
|
47
|
+
end
|
48
|
+
|
49
|
+
def clear_token
|
50
|
+
update_attributes :token => nil, :token_created_at => nil
|
51
|
+
end
|
52
|
+
|
39
53
|
def has_matching_password?(plain_text_password)
|
40
54
|
BCrypt::Password.new(password_digest) == plain_text_password
|
41
55
|
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def url_friendly_token
|
60
|
+
ActiveSupport::SecureRandom.base64(10).tr('+/=', 'xyz')
|
61
|
+
end
|
42
62
|
end
|
43
63
|
|
44
64
|
end
|
@@ -48,6 +48,17 @@ QuoVadis.configure do |config|
|
|
48
48
|
config.signed_out_hook = nil
|
49
49
|
|
50
50
|
|
51
|
+
#
|
52
|
+
# Forgotten-password Mailer
|
53
|
+
#
|
54
|
+
|
55
|
+
# From whom the forgotten-password email should be sent.
|
56
|
+
config.from = 'noreply@example.com'
|
57
|
+
|
58
|
+
# Subject of the forgotten-password email.
|
59
|
+
config.subject = 'Change your password'
|
60
|
+
|
61
|
+
|
51
62
|
#
|
52
63
|
# Miscellaneous
|
53
64
|
#
|
@@ -1,7 +1,16 @@
|
|
1
1
|
en:
|
2
2
|
quo_vadis:
|
3
3
|
flash:
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
sign_in:
|
5
|
+
before: 'Please sign in first.'
|
6
|
+
after: 'You have successfully signed in.'
|
7
|
+
failed: 'Sorry, we did not recognise you.'
|
8
|
+
|
7
9
|
sign_out: 'You have successfully signed out.'
|
10
|
+
|
11
|
+
forgotten:
|
12
|
+
unknown: "Sorry, we did not recognise you."
|
13
|
+
no_email: "Sorry, we don't have an email address for you."
|
14
|
+
sent_email: "We've emailed you a link where you can change your password."
|
15
|
+
invalid_token: "Sorry, this link isn't valid anymore."
|
16
|
+
password_changed: "You have successfully changed your password and you're now signed in."
|
data/config/routes.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
-
Rails.application.routes.draw do
|
1
|
+
Rails.application.routes.draw do
|
2
2
|
scope :module => 'quo_vadis' do
|
3
|
-
get 'sign-in'
|
4
|
-
post 'sign-in'
|
5
|
-
get 'sign-out'
|
3
|
+
get 'sign-in' => 'sessions#new', :as => 'sign_in'
|
4
|
+
post 'sign-in' => 'sessions#create', :as => 'sign_in'
|
5
|
+
get 'sign-out' => 'sessions#destroy', :as => 'sign_out'
|
6
|
+
get 'sign-in/forgotten' => 'sessions#forgotten', :as => 'forgotten_sign_in'
|
7
|
+
post 'sign-in/forgotten' => 'sessions#forgotten', :as => 'forgotten_sign_in'
|
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'
|
11
|
+
end
|
6
12
|
end
|
7
13
|
end
|
@@ -1,11 +1,18 @@
|
|
1
1
|
class AddAuthenticationToUsers < ActiveRecord::Migration
|
2
2
|
def self.up
|
3
|
-
add_column :users, :username,
|
4
|
-
add_column :users, :password_digest,
|
3
|
+
add_column :users, :username, :string # for user identification
|
4
|
+
add_column :users, :password_digest, :string
|
5
|
+
|
6
|
+
add_column :users, :email, :string # for forgotten-credentials
|
7
|
+
add_column :users, :token, :string # for forgotten-credentials
|
8
|
+
add_column :users, :token_created_at, :string # for forgotten-credentials
|
5
9
|
end
|
6
10
|
|
7
11
|
def self.down
|
8
12
|
remove_column :users, :username
|
9
13
|
remove_column :users, :password_digest
|
14
|
+
remove_column :users, :email
|
15
|
+
remove_column :users, :token
|
16
|
+
remove_column :users, :token_created_at
|
10
17
|
end
|
11
18
|
end
|
data/lib/quo_vadis/version.rb
CHANGED
data/lib/quo_vadis.rb
CHANGED
@@ -57,6 +57,19 @@ module QuoVadis
|
|
57
57
|
end
|
58
58
|
|
59
59
|
|
60
|
+
#
|
61
|
+
# Forgotten-password Mailer
|
62
|
+
#
|
63
|
+
|
64
|
+
# From whom the forgotten-password email should be sent.
|
65
|
+
mattr_accessor :from
|
66
|
+
@@from = 'noreply@example.com'
|
67
|
+
|
68
|
+
# Subject of the forgotten-password email.
|
69
|
+
mattr_accessor :subject
|
70
|
+
@@subject = 'Change your password.'
|
71
|
+
|
72
|
+
|
60
73
|
#
|
61
74
|
# Miscellaneous
|
62
75
|
#
|
data/test/dummy/Rakefile
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
3
|
+
|
4
|
+
require File.expand_path('../config/application', __FILE__)
|
5
|
+
require 'rake'
|
6
|
+
|
7
|
+
Dummy::Application.load_tasks
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Hello <%= @username %>,
|
2
|
+
|
3
|
+
We've received a request to change your password. If this wasn't you,
|
4
|
+
please ignore this email and your password will be left alone.
|
5
|
+
|
6
|
+
If you do want to change your password, just click this link (valid for 3 hours):
|
7
|
+
<%= @url %>
|
8
|
+
|
9
|
+
Thanks!
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<h1>Forgotten your password?</h1>
|
2
|
+
|
3
|
+
<p>Don't worry, it happens to the best of us. Just tell us who you are, and we'll send you an email explaining how to change your password.</p>
|
4
|
+
|
5
|
+
<%= form_tag forgotten_sign_in_path do %>
|
6
|
+
<p>
|
7
|
+
<%= label_tag :username %>
|
8
|
+
<%= text_field_tag :username %>
|
9
|
+
</p>
|
10
|
+
<p>
|
11
|
+
<%= submit_tag 'Send me that email' %>
|
12
|
+
</p>
|
13
|
+
<% end %>
|
@@ -25,6 +25,8 @@ Dummy::Application.configure do
|
|
25
25
|
# ActionMailer::Base.deliveries array.
|
26
26
|
config.action_mailer.delivery_method = :test
|
27
27
|
|
28
|
+
config.action_mailer.default_url_options = {:host => 'www.example.com'}
|
29
|
+
|
28
30
|
# Use SQL instead of Active Record's schema dumper when creating the test database.
|
29
31
|
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
30
32
|
# like if you have constraints or database-specific column types
|
@@ -0,0 +1,58 @@
|
|
1
|
+
QuoVadis.configure do |config|
|
2
|
+
|
3
|
+
#
|
4
|
+
# Redirection URLs
|
5
|
+
#
|
6
|
+
|
7
|
+
# The URL to redirect the user to after s/he signs in.
|
8
|
+
# Use a proc if the URL depends on the user. E.g.:
|
9
|
+
#
|
10
|
+
# config.signed_in_url = Proc.new do |user|
|
11
|
+
# user.admin? ? :admin : :root
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# See also `:override_original_url`.
|
15
|
+
config.signed_in_url = :root
|
16
|
+
|
17
|
+
# Whether the `:signed_in_url` should override the URL the user was trying
|
18
|
+
# to reach when they were made to authenticate.
|
19
|
+
config.override_original_url = false
|
20
|
+
|
21
|
+
# The URL to redirect the user to after s/he signs out.
|
22
|
+
config.signed_out_url = :root
|
23
|
+
|
24
|
+
|
25
|
+
#
|
26
|
+
# Hooks
|
27
|
+
#
|
28
|
+
|
29
|
+
# Code to run when the user has signed in. E.g.:
|
30
|
+
#
|
31
|
+
# config.signed_in_hook = Proc.new do |user, controller|
|
32
|
+
# user.increment! :sign_in_count # assuming this attribute exists
|
33
|
+
# end
|
34
|
+
config.signed_in_hook = nil
|
35
|
+
|
36
|
+
# Code to run when someone has tried but failed to sign in. E.g.:
|
37
|
+
#
|
38
|
+
# config.failed_sign_in_hook = Proc.new do |controller|
|
39
|
+
# logger.info "Failed sign in from #{controller.request.remote_ip}"
|
40
|
+
# end
|
41
|
+
config.failed_sign_in_hook = nil
|
42
|
+
|
43
|
+
# Code to run just before the user has signed out. E.g.:
|
44
|
+
#
|
45
|
+
# config.signed_out_hook = Proc.new do |user, controller|
|
46
|
+
# controller.session.reset
|
47
|
+
# end
|
48
|
+
config.signed_out_hook = nil
|
49
|
+
|
50
|
+
|
51
|
+
#
|
52
|
+
# Miscellaneous
|
53
|
+
#
|
54
|
+
|
55
|
+
# Layout for the sign-in view. Pass a string or a symbol.
|
56
|
+
config.layout = 'application'
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class AddAuthenticationToUsers < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :users, :username, :string # for user identification
|
4
|
+
add_column :users, :password_digest, :string
|
5
|
+
|
6
|
+
add_column :users, :email, :string # for forgotten-credentials
|
7
|
+
add_column :users, :token, :string # for forgotten-credentials
|
8
|
+
add_column :users, :token_created_at, :string # for forgotten-credentials
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.down
|
12
|
+
remove_column :users, :username
|
13
|
+
remove_column :users, :password_digest
|
14
|
+
remove_column :users, :email
|
15
|
+
remove_column :users, :token
|
16
|
+
remove_column :users, :token_created_at
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# This file is auto-generated from the current state of the database. Instead
|
2
|
+
# of editing this file, please use the migrations feature of Active Record to
|
3
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
4
|
+
#
|
5
|
+
# Note that this schema.rb definition is the authoritative source for your
|
6
|
+
# database schema. If you need to create the application database on another
|
7
|
+
# system, you should be using db:schema:load, not running all the migrations
|
8
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
9
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
10
|
+
#
|
11
|
+
# It's strongly recommended to check this file into your version control system.
|
12
|
+
|
13
|
+
ActiveRecord::Schema.define(:version => 20110127094709) do
|
14
|
+
|
15
|
+
create_table "articles", :force => true do |t|
|
16
|
+
t.string "title"
|
17
|
+
t.text "content"
|
18
|
+
t.datetime "created_at"
|
19
|
+
t.datetime "updated_at"
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table "users", :force => true do |t|
|
23
|
+
t.string "name"
|
24
|
+
t.datetime "created_at"
|
25
|
+
t.datetime "updated_at"
|
26
|
+
t.string "username"
|
27
|
+
t.string "password_digest"
|
28
|
+
t.string "email"
|
29
|
+
t.string "token"
|
30
|
+
t.string "token_created_at"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -99,4 +99,18 @@ class ConfigTest < ActiveSupport::IntegrationCase
|
|
99
99
|
assert page.has_content?('Sessions layout')
|
100
100
|
end
|
101
101
|
|
102
|
+
test 'mailer from config' do
|
103
|
+
QuoVadis.from = 'jim@example.com'
|
104
|
+
(user = User.last).generate_token
|
105
|
+
email = QuoVadis::Notifier.change_password(user)
|
106
|
+
assert_equal ['jim@example.com'], email.from
|
107
|
+
end
|
108
|
+
|
109
|
+
test 'mailer subject config' do
|
110
|
+
QuoVadis.subject = 'You idiot!'
|
111
|
+
(user = User.last).generate_token
|
112
|
+
email = QuoVadis::Notifier.change_password(user)
|
113
|
+
assert_equal 'You idiot!', email.subject
|
114
|
+
end
|
115
|
+
|
102
116
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ForgottenTest < ActiveSupport::IntegrationCase
|
4
|
+
|
5
|
+
teardown do
|
6
|
+
Capybara.reset_sessions!
|
7
|
+
end
|
8
|
+
|
9
|
+
test 'user fills in forgotten-password form with invalid username' do
|
10
|
+
submit_forgotten_details 'bob'
|
11
|
+
assert_equal forgotten_sign_in_path, current_path
|
12
|
+
within '.flash.alert' do
|
13
|
+
assert page.has_content?("Sorry, we did not recognise you.")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
test 'user without email requests password-change email' do
|
18
|
+
user_factory 'Bob', 'bob', 'secret'
|
19
|
+
submit_forgotten_details 'bob'
|
20
|
+
assert_equal forgotten_sign_in_path, current_path
|
21
|
+
within '.flash.alert' do
|
22
|
+
assert page.has_content?("Sorry, we don't have an email address for you.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
test 'user can request password-change email' do
|
27
|
+
user_factory 'Bob', 'bob', 'secret', 'bob@example.com'
|
28
|
+
submit_forgotten_details 'bob'
|
29
|
+
|
30
|
+
assert_equal root_path, current_path
|
31
|
+
within '.flash.notice' do
|
32
|
+
assert page.has_content?("We've emailed you a link where you can change your password.")
|
33
|
+
end
|
34
|
+
assert !ActionMailer::Base.deliveries.empty?
|
35
|
+
email = ActionMailer::Base.deliveries.last
|
36
|
+
assert_equal ['bob@example.com'], email.to
|
37
|
+
assert_equal ['noreply@example.com'], email.from
|
38
|
+
assert_equal 'Change your password', email.subject
|
39
|
+
# Why doesn't this use the default url option set up in test/test_helper.rb#9?
|
40
|
+
assert_match Regexp.new(Regexp.escape(change_password_url User.last.token, :host => 'www.example.com')), email.encoded
|
41
|
+
end
|
42
|
+
|
43
|
+
test 'user can follow emailed link while valid to change password' do
|
44
|
+
user_factory 'Bob', 'bob', 'secret', 'bob@example.com'
|
45
|
+
submit_forgotten_details 'bob'
|
46
|
+
|
47
|
+
link_in_email = ActionMailer::Base.deliveries.last.encoded[%r{http://.*}].strip
|
48
|
+
visit link_in_email
|
49
|
+
fill_in :password, :with => 'topsecret'
|
50
|
+
click_button 'Change my password'
|
51
|
+
assert_equal root_path, current_path
|
52
|
+
within '.flash.notice' do
|
53
|
+
assert page.has_content?("You have successfully changed your password and you're now signed in.")
|
54
|
+
end
|
55
|
+
assert_nil User.last.token
|
56
|
+
assert_nil User.last.token_created_at
|
57
|
+
end
|
58
|
+
|
59
|
+
test 'user cannot change password to an invalid one' do
|
60
|
+
user_factory 'Bob', 'bob', 'secret', 'bob@example.com'
|
61
|
+
submit_forgotten_details 'bob'
|
62
|
+
|
63
|
+
link_in_email = ActionMailer::Base.deliveries.last.encoded[%r{http://.*}].strip
|
64
|
+
visit link_in_email
|
65
|
+
fill_in :password, :with => ''
|
66
|
+
click_button 'Change my password'
|
67
|
+
assert_equal change_password_path(User.last.token), current_path
|
68
|
+
end
|
69
|
+
|
70
|
+
test 'user cannot change password once emailed link is invalid' do
|
71
|
+
user_factory 'Bob', 'bob', 'secret', 'bob@example.com'
|
72
|
+
submit_forgotten_details 'bob'
|
73
|
+
User.last.update_attributes :token_created_at => 1.day.ago
|
74
|
+
|
75
|
+
link_in_email = ActionMailer::Base.deliveries.last.encoded[%r{http://.*}].strip
|
76
|
+
visit link_in_email
|
77
|
+
assert_equal forgotten_sign_in_path, current_path
|
78
|
+
within '.flash.alert' do
|
79
|
+
assert page.has_content?("Sorry, this link isn't valid anymore.")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -6,14 +6,14 @@ class LocaleTest < ActiveSupport::IntegrationCase
|
|
6
6
|
Capybara.reset_sessions!
|
7
7
|
end
|
8
8
|
|
9
|
-
test '
|
9
|
+
test 'sign_in.before flash' do
|
10
10
|
visit new_article_path
|
11
11
|
within '.flash' do
|
12
12
|
assert page.has_content?('Please sign in first.')
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
test '
|
16
|
+
test 'sign_in.after flash' do
|
17
17
|
user_factory 'Bob', 'bob', 'secret'
|
18
18
|
sign_in_as 'bob', 'secret'
|
19
19
|
within '.flash' do
|
@@ -21,7 +21,7 @@ class LocaleTest < ActiveSupport::IntegrationCase
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
test '
|
24
|
+
test 'sign_in.failed flash' do
|
25
25
|
sign_in_as 'bob', 'secret'
|
26
26
|
within '.flash' do
|
27
27
|
assert page.has_content?('Sorry, we did not recognise you.')
|
@@ -35,9 +35,9 @@ class LocaleTest < ActiveSupport::IntegrationCase
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
test '
|
38
|
+
test 'sign_in.before flash is optional' do
|
39
39
|
begin
|
40
|
-
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:
|
40
|
+
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:sign_in => {:before => ''}}}}
|
41
41
|
visit new_article_path
|
42
42
|
assert page.has_no_css?('div.flash')
|
43
43
|
ensure
|
@@ -45,10 +45,10 @@ class LocaleTest < ActiveSupport::IntegrationCase
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
test '
|
48
|
+
test 'sign_in.after flash is optional' do
|
49
49
|
user_factory 'Bob', 'bob', 'secret'
|
50
50
|
begin
|
51
|
-
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:
|
51
|
+
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:sign_in => {:after => ''}}}}
|
52
52
|
sign_in_as 'bob', 'secret'
|
53
53
|
assert page.has_no_css?('div.flash')
|
54
54
|
ensure
|
@@ -56,9 +56,9 @@ class LocaleTest < ActiveSupport::IntegrationCase
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
test '
|
59
|
+
test 'sign_in.failed flash is optional' do
|
60
60
|
begin
|
61
|
-
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:
|
61
|
+
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:sign_in => {:failed => ''}}}}
|
62
62
|
sign_in_as 'bob', 'secret'
|
63
63
|
assert page.has_no_css?('div.flash')
|
64
64
|
ensure
|
@@ -75,4 +75,102 @@ class LocaleTest < ActiveSupport::IntegrationCase
|
|
75
75
|
I18n.reload!
|
76
76
|
end
|
77
77
|
end
|
78
|
+
|
79
|
+
test 'forgotten.unknown flash' do
|
80
|
+
submit_forgotten_details 'bob'
|
81
|
+
within '.flash.alert' do
|
82
|
+
assert page.has_content?('Sorry, we did not recognise you.')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
test 'forgotten.unknown flash is optional' do
|
87
|
+
begin
|
88
|
+
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:forgotten => {:unknown => ''}}}}
|
89
|
+
submit_forgotten_details 'bob'
|
90
|
+
assert page.has_no_css?('div.flash')
|
91
|
+
ensure
|
92
|
+
I18n.reload!
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
test 'forgotten.no_email flash' do
|
97
|
+
user_factory 'Bob', 'bob', 'secret'
|
98
|
+
submit_forgotten_details 'bob'
|
99
|
+
within '.flash.alert' do
|
100
|
+
assert page.has_content?("Sorry, we don't have an email address for you.")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
test 'forgotten.no_email flash is optional' do
|
105
|
+
begin
|
106
|
+
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:forgotten => {:no_email => ''}}}}
|
107
|
+
user_factory 'Bob', 'bob', 'secret'
|
108
|
+
submit_forgotten_details 'bob'
|
109
|
+
assert page.has_no_css?('div.flash')
|
110
|
+
ensure
|
111
|
+
I18n.reload!
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
test 'forgotten.sent_email flash' do
|
116
|
+
user_factory 'Bob', 'bob', 'secret', 'bob@example.com'
|
117
|
+
submit_forgotten_details 'bob'
|
118
|
+
within '.flash.notice' do
|
119
|
+
assert page.has_content?("We've emailed you a link where you can change your password.")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
test 'forgotten.sent_email flash is optional' do
|
124
|
+
begin
|
125
|
+
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:forgotten => {:sent_email => ''}}}}
|
126
|
+
user_factory 'Bob', 'bob', 'secret', 'bob@example.com'
|
127
|
+
submit_forgotten_details 'bob'
|
128
|
+
assert page.has_no_css?('div.flash')
|
129
|
+
ensure
|
130
|
+
I18n.reload!
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
test 'forgotten.invalid_token flash' do
|
135
|
+
visit change_password_path('123')
|
136
|
+
within '.flash.alert' do
|
137
|
+
assert page.has_content?("Sorry, this link isn't valid anymore.")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
test 'forgotten.invalid_token flash is optional' do
|
142
|
+
begin
|
143
|
+
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:forgotten => {:invalid_token => ''}}}}
|
144
|
+
visit change_password_path('123')
|
145
|
+
assert page.has_no_css?('div.flash')
|
146
|
+
ensure
|
147
|
+
I18n.reload!
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
test 'forgotten.password_changed flash' do
|
152
|
+
user_factory 'Bob', 'bob', 'secret', 'bob@example.com'
|
153
|
+
User.last.generate_token
|
154
|
+
visit change_password_path(User.last.token)
|
155
|
+
fill_in :password, :with => 'topsecret'
|
156
|
+
click_button 'Change my password'
|
157
|
+
within '.flash.notice' do
|
158
|
+
assert page.has_content?("You have successfully changed your password and you're now signed in.")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
test 'forgotten.password_changed flash is optional' do
|
163
|
+
begin
|
164
|
+
I18n.backend.store_translations :en, {:quo_vadis => {:flash => {:forgotten => {:password_changed => ''}}}}
|
165
|
+
user_factory 'Bob', 'bob', 'secret', 'bob@example.com'
|
166
|
+
User.last.generate_token
|
167
|
+
visit change_password_path(User.last.token)
|
168
|
+
fill_in :password, :with => 'topsecret'
|
169
|
+
click_button 'Change my password'
|
170
|
+
assert page.has_no_css?('div.flash')
|
171
|
+
ensure
|
172
|
+
I18n.reload!
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
78
176
|
end
|
data/test/test_helper.rb
CHANGED
@@ -6,7 +6,7 @@ require "rails/test_help"
|
|
6
6
|
|
7
7
|
ActionMailer::Base.delivery_method = :test
|
8
8
|
ActionMailer::Base.perform_deliveries = true
|
9
|
-
ActionMailer::Base.default_url_options[:host] = "
|
9
|
+
ActionMailer::Base.default_url_options[:host] = "www.example.com"
|
10
10
|
|
11
11
|
Rails.backtrace_cleaner.remove_silencers!
|
12
12
|
|
@@ -32,8 +32,14 @@ def sign_in_as(username, password)
|
|
32
32
|
click_button 'Sign in'
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
36
|
-
|
35
|
+
def submit_forgotten_details(username)
|
36
|
+
visit forgotten_sign_in_path
|
37
|
+
fill_in 'username', :with => username
|
38
|
+
click_button 'Send me that email'
|
39
|
+
end
|
40
|
+
|
41
|
+
def user_factory(name, username, password, email = nil)
|
42
|
+
User.create! :name => name, :username => username, :password => password, :email => email
|
37
43
|
end
|
38
44
|
|
39
45
|
def reset_quo_vadis_configuration
|
@@ -44,4 +50,6 @@ def reset_quo_vadis_configuration
|
|
44
50
|
QuoVadis.failed_sign_in_hook = nil
|
45
51
|
QuoVadis.signed_out_hook = nil
|
46
52
|
QuoVadis.layout = 'application'
|
53
|
+
QuoVadis.from = 'noreply@example.com'
|
54
|
+
QuoVadis.subject = 'Change your password'
|
47
55
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class UserTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
test 'user must have a valid password on create' do
|
6
|
+
assert !User.create(:username => 'bob', :password => nil).valid?
|
7
|
+
assert !User.create(:username => 'bob', :password => '').valid?
|
8
|
+
assert User.create(:username => 'bob', :password => 'secret').valid?
|
9
|
+
end
|
10
|
+
|
11
|
+
test 'user need not supply password when updating other attributes' do
|
12
|
+
User.create :username => 'bob', :password => 'secret'
|
13
|
+
user = User.last # reload from database so password is nil
|
14
|
+
assert_nil user.password
|
15
|
+
assert user.update_attributes(:username => 'Robert')
|
16
|
+
end
|
17
|
+
|
18
|
+
test 'user must have a valid password when updating password' do
|
19
|
+
user = User.create :username => 'bob', :password => 'secret'
|
20
|
+
assert !user.update_attributes(:password => '')
|
21
|
+
assert !user.update_attributes(:password => nil)
|
22
|
+
assert user.update_attributes(:password => 'topsecret')
|
23
|
+
end
|
24
|
+
|
25
|
+
test 'has_matching_password?' do
|
26
|
+
User.create :username => 'bob', :password => 'secret'
|
27
|
+
user = User.last
|
28
|
+
assert user.has_matching_password?('secret')
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quo_vadis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 1.0.
|
9
|
+
- 2
|
10
|
+
version: 1.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andy Stewart
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-01-
|
18
|
+
date: 2011-01-27 00:00:00 +00:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -110,6 +110,7 @@ files:
|
|
110
110
|
- Rakefile
|
111
111
|
- app/controllers/controller_mixin.rb
|
112
112
|
- app/controllers/quo_vadis/sessions_controller.rb
|
113
|
+
- app/mailers/quo_vadis/notifier.rb
|
113
114
|
- app/models/model_mixin.rb
|
114
115
|
- config/initializers/quo_vadis.rb
|
115
116
|
- config/locales/quo_vadis.en.yml
|
@@ -121,6 +122,7 @@ files:
|
|
121
122
|
- lib/quo_vadis/version.rb
|
122
123
|
- quo_vadis.gemspec
|
123
124
|
- test/dummy/.gitignore
|
125
|
+
- test/dummy/Rakefile
|
124
126
|
- test/dummy/app/controllers/application_controller.rb
|
125
127
|
- test/dummy/app/controllers/articles_controller.rb
|
126
128
|
- test/dummy/app/helpers/application_helper.rb
|
@@ -131,6 +133,9 @@ files:
|
|
131
133
|
- test/dummy/app/views/articles/new.html.erb
|
132
134
|
- test/dummy/app/views/layouts/application.html.erb
|
133
135
|
- test/dummy/app/views/layouts/sessions.html.erb
|
136
|
+
- test/dummy/app/views/quo_vadis/notifier/change_password.text.erb
|
137
|
+
- test/dummy/app/views/sessions/edit.html.erb
|
138
|
+
- test/dummy/app/views/sessions/forgotten.html.erb
|
134
139
|
- test/dummy/app/views/sessions/new.html.erb
|
135
140
|
- test/dummy/config.ru
|
136
141
|
- test/dummy/config/application.rb
|
@@ -143,13 +148,16 @@ files:
|
|
143
148
|
- test/dummy/config/initializers/backtrace_silencers.rb
|
144
149
|
- test/dummy/config/initializers/inflections.rb
|
145
150
|
- test/dummy/config/initializers/mime_types.rb
|
151
|
+
- test/dummy/config/initializers/quo_vadis.rb
|
146
152
|
- test/dummy/config/initializers/secret_token.rb
|
147
153
|
- test/dummy/config/initializers/session_store.rb
|
148
154
|
- test/dummy/config/locales/en.yml
|
155
|
+
- test/dummy/config/locales/quo_vadis.en.yml
|
149
156
|
- test/dummy/config/routes.rb
|
150
157
|
- test/dummy/db/migrate/20110124125037_create_users.rb
|
151
|
-
- test/dummy/db/migrate/20110124125216_add_authentication_to_users.rb
|
152
158
|
- test/dummy/db/migrate/20110124131535_create_articles.rb
|
159
|
+
- test/dummy/db/migrate/20110127094709_add_authentication_to_users.rb
|
160
|
+
- test/dummy/db/schema.rb
|
153
161
|
- test/dummy/public/404.html
|
154
162
|
- test/dummy/public/422.html
|
155
163
|
- test/dummy/public/500.html
|
@@ -169,6 +177,7 @@ files:
|
|
169
177
|
- test/dummy/tmp/capybara/capybara-20110124135435.html
|
170
178
|
- test/integration/authenticate_test.rb
|
171
179
|
- test/integration/config_test.rb
|
180
|
+
- test/integration/forgotten_test.rb
|
172
181
|
- test/integration/helper_test.rb
|
173
182
|
- test/integration/locale_test.rb
|
174
183
|
- test/integration/navigation_test.rb
|
@@ -177,6 +186,7 @@ files:
|
|
177
186
|
- test/quo_vadis_test.rb
|
178
187
|
- test/support/integration_case.rb
|
179
188
|
- test/test_helper.rb
|
189
|
+
- test/unit/user_test.rb
|
180
190
|
has_rdoc: true
|
181
191
|
homepage: https://github.com/airblade/quo_vadis
|
182
192
|
licenses: []
|
@@ -213,6 +223,7 @@ specification_version: 3
|
|
213
223
|
summary: Simple username/password authentication for Rails 3.
|
214
224
|
test_files:
|
215
225
|
- test/dummy/.gitignore
|
226
|
+
- test/dummy/Rakefile
|
216
227
|
- test/dummy/app/controllers/application_controller.rb
|
217
228
|
- test/dummy/app/controllers/articles_controller.rb
|
218
229
|
- test/dummy/app/helpers/application_helper.rb
|
@@ -223,6 +234,9 @@ test_files:
|
|
223
234
|
- test/dummy/app/views/articles/new.html.erb
|
224
235
|
- test/dummy/app/views/layouts/application.html.erb
|
225
236
|
- test/dummy/app/views/layouts/sessions.html.erb
|
237
|
+
- test/dummy/app/views/quo_vadis/notifier/change_password.text.erb
|
238
|
+
- test/dummy/app/views/sessions/edit.html.erb
|
239
|
+
- test/dummy/app/views/sessions/forgotten.html.erb
|
226
240
|
- test/dummy/app/views/sessions/new.html.erb
|
227
241
|
- test/dummy/config.ru
|
228
242
|
- test/dummy/config/application.rb
|
@@ -235,13 +249,16 @@ test_files:
|
|
235
249
|
- test/dummy/config/initializers/backtrace_silencers.rb
|
236
250
|
- test/dummy/config/initializers/inflections.rb
|
237
251
|
- test/dummy/config/initializers/mime_types.rb
|
252
|
+
- test/dummy/config/initializers/quo_vadis.rb
|
238
253
|
- test/dummy/config/initializers/secret_token.rb
|
239
254
|
- test/dummy/config/initializers/session_store.rb
|
240
255
|
- test/dummy/config/locales/en.yml
|
256
|
+
- test/dummy/config/locales/quo_vadis.en.yml
|
241
257
|
- test/dummy/config/routes.rb
|
242
258
|
- test/dummy/db/migrate/20110124125037_create_users.rb
|
243
|
-
- test/dummy/db/migrate/20110124125216_add_authentication_to_users.rb
|
244
259
|
- test/dummy/db/migrate/20110124131535_create_articles.rb
|
260
|
+
- test/dummy/db/migrate/20110127094709_add_authentication_to_users.rb
|
261
|
+
- test/dummy/db/schema.rb
|
245
262
|
- test/dummy/public/404.html
|
246
263
|
- test/dummy/public/422.html
|
247
264
|
- test/dummy/public/500.html
|
@@ -261,6 +278,7 @@ test_files:
|
|
261
278
|
- test/dummy/tmp/capybara/capybara-20110124135435.html
|
262
279
|
- test/integration/authenticate_test.rb
|
263
280
|
- test/integration/config_test.rb
|
281
|
+
- test/integration/forgotten_test.rb
|
264
282
|
- test/integration/helper_test.rb
|
265
283
|
- test/integration/locale_test.rb
|
266
284
|
- test/integration/navigation_test.rb
|
@@ -269,3 +287,4 @@ test_files:
|
|
269
287
|
- test/quo_vadis_test.rb
|
270
288
|
- test/support/integration_case.rb
|
271
289
|
- test/test_helper.rb
|
290
|
+
- test/unit/user_test.rb
|
@@ -1,11 +0,0 @@
|
|
1
|
-
class AddAuthenticationToUsers < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
add_column :users, :username, :string # for user identification
|
4
|
-
add_column :users, :password_digest, :string
|
5
|
-
end
|
6
|
-
|
7
|
-
def self.down
|
8
|
-
remove_column :users, :username
|
9
|
-
remove_column :users, :password_digest
|
10
|
-
end
|
11
|
-
end
|