quo_vadis 1.0.1 → 1.0.2
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/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
|