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