jeffrafter-clearance 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/CHANGELOG.textile +75 -0
  2. data/LICENSE +21 -0
  3. data/README.textile +76 -0
  4. data/Rakefile +73 -0
  5. data/generators/clearance/USAGE +1 -0
  6. data/generators/clearance/clearance_generator.rb +96 -0
  7. data/generators/clearance/lib/insert_commands.rb +103 -0
  8. data/generators/clearance/lib/rake_commands.rb +22 -0
  9. data/generators/clearance/templates/README +45 -0
  10. data/generators/clearance/templates/app/controllers/application.rb +5 -0
  11. data/generators/clearance/templates/app/controllers/confirmations_controller.rb +3 -0
  12. data/generators/clearance/templates/app/controllers/passwords_controller.rb +3 -0
  13. data/generators/clearance/templates/app/controllers/sessions_controller.rb +3 -0
  14. data/generators/clearance/templates/app/controllers/users_controller.rb +3 -0
  15. data/generators/clearance/templates/app/models/clearance_mailer.rb +5 -0
  16. data/generators/clearance/templates/app/models/user.rb +3 -0
  17. data/generators/clearance/templates/app/views/clearance_mailer/change_password.html.erb +7 -0
  18. data/generators/clearance/templates/app/views/clearance_mailer/confirmation.html.erb +2 -0
  19. data/generators/clearance/templates/app/views/passwords/edit.html.erb +23 -0
  20. data/generators/clearance/templates/app/views/passwords/new.html.erb +15 -0
  21. data/generators/clearance/templates/app/views/sessions/new.html.erb +28 -0
  22. data/generators/clearance/templates/app/views/users/_form.html.erb +13 -0
  23. data/generators/clearance/templates/app/views/users/edit.html.erb +6 -0
  24. data/generators/clearance/templates/app/views/users/new.html.erb +6 -0
  25. data/generators/clearance/templates/db/migrate/create_users_with_clearance_columns.rb +20 -0
  26. data/generators/clearance/templates/db/migrate/update_users_with_clearance_columns.rb +41 -0
  27. data/generators/clearance/templates/test/factories/clearance.rb +16 -0
  28. data/generators/clearance/templates/test/functional/confirmations_controller_test.rb +5 -0
  29. data/generators/clearance/templates/test/functional/passwords_controller_test.rb +5 -0
  30. data/generators/clearance/templates/test/functional/sessions_controller_test.rb +5 -0
  31. data/generators/clearance/templates/test/functional/users_controller_test.rb +5 -0
  32. data/generators/clearance/templates/test/unit/clearance_mailer_test.rb +6 -0
  33. data/generators/clearance/templates/test/unit/user_test.rb +5 -0
  34. data/generators/clearance_features/USAGE +1 -0
  35. data/generators/clearance_features/clearance_features_generator.rb +20 -0
  36. data/generators/clearance_features/templates/features/password_reset.feature +31 -0
  37. data/generators/clearance_features/templates/features/sign_in.feature +41 -0
  38. data/generators/clearance_features/templates/features/sign_out.feature +22 -0
  39. data/generators/clearance_features/templates/features/sign_up.feature +30 -0
  40. data/generators/clearance_features/templates/features/step_definitions/clearance_steps.rb +110 -0
  41. data/generators/clearance_features/templates/features/step_definitions/factory_girl_steps.rb +5 -0
  42. data/generators/clearance_features/templates/features/support/paths.rb +25 -0
  43. data/lib/clearance.rb +15 -0
  44. data/lib/clearance/app/controllers/application_controller.rb +84 -0
  45. data/lib/clearance/app/controllers/confirmations_controller.rb +63 -0
  46. data/lib/clearance/app/controllers/passwords_controller.rb +79 -0
  47. data/lib/clearance/app/controllers/sessions_controller.rb +74 -0
  48. data/lib/clearance/app/controllers/users_controller.rb +45 -0
  49. data/lib/clearance/app/models/clearance_mailer.rb +23 -0
  50. data/lib/clearance/app/models/user.rb +118 -0
  51. data/lib/clearance/lib/extensions/errors.rb +4 -0
  52. data/lib/clearance/lib/extensions/rescue.rb +1 -0
  53. data/lib/clearance/test/functional/confirmations_controller_test.rb +72 -0
  54. data/lib/clearance/test/functional/passwords_controller_test.rb +180 -0
  55. data/lib/clearance/test/functional/sessions_controller_test.rb +188 -0
  56. data/lib/clearance/test/functional/users_controller_test.rb +60 -0
  57. data/lib/clearance/test/unit/clearance_mailer_test.rb +65 -0
  58. data/lib/clearance/test/unit/user_test.rb +236 -0
  59. data/rails/init.rb +1 -0
  60. data/shoulda_macros/clearance.rb +246 -0
  61. metadata +157 -0
@@ -0,0 +1,22 @@
1
+ Rails::Generator::Commands::Create.class_eval do
2
+ def rake_db_migrate
3
+ logger.rake "db:migrate"
4
+ unless system("rake db:migrate")
5
+ logger.rake "db:migrate failed. Rolling back"
6
+ command(:destroy).invoke!
7
+ end
8
+ end
9
+ end
10
+
11
+ Rails::Generator::Commands::Destroy.class_eval do
12
+ def rake_db_migrate
13
+ logger.rake "db:rollback"
14
+ system "rake db:rollback"
15
+ end
16
+ end
17
+
18
+ Rails::Generator::Commands::List.class_eval do
19
+ def rake_db_migrate
20
+ logger.rake "db:migrate"
21
+ end
22
+ end
@@ -0,0 +1,45 @@
1
+
2
+ *******************************************************************************
3
+
4
+ Ok, enough fancy automatic stuff. Time for some old school monkey copy-pasting.
5
+
6
+ 1. For any other file(s) that you already had and didn't want to overwrite, add
7
+ the corresponding Clearance module. They are namespaced exactly like the
8
+ directory structure of a Rails app.
9
+
10
+ Application controller example:
11
+
12
+ class ApplicationController < ActionController::Base
13
+ include Clearance::App::Controllers::ApplicationController
14
+ end
15
+
16
+ User model example:
17
+
18
+ class User < ActiveRecord::Base
19
+ include Clearance::App::Models::User
20
+ end
21
+
22
+ User test example:
23
+
24
+ class UserTest < ActiveSupport::TestCase
25
+ include Clearance::Test::Unit::UserTest
26
+ end
27
+
28
+ 2. You need to define HOST constant in your environments files.
29
+ In config/environments/test.rb and config/environments/development.rb it can be:
30
+
31
+ HOST = "localhost"
32
+
33
+ In production.rb it must be the actual host your application is deployed to.
34
+ The constant is used by mailers to generate URLs in emails.
35
+
36
+ In config/environment.rb:
37
+
38
+ DO_NOT_REPLY = "donotreply@example.com"
39
+
40
+ 3. Clearance depends on root_url, so please make sure that it is defined to
41
+ *something* in your config/routes.rb:
42
+
43
+ map.root :controller => 'home'
44
+
45
+ *******************************************************************************
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ helper :all
3
+ protect_from_forgery
4
+ include Clearance::App::Controllers::ApplicationController
5
+ end
@@ -0,0 +1,3 @@
1
+ class ConfirmationsController < ApplicationController
2
+ include Clearance::App::Controllers::ConfirmationsController
3
+ end
@@ -0,0 +1,3 @@
1
+ class PasswordsController < ApplicationController
2
+ include Clearance::App::Controllers::PasswordsController
3
+ end
@@ -0,0 +1,3 @@
1
+ class SessionsController < ApplicationController
2
+ include Clearance::App::Controllers::SessionsController
3
+ end
@@ -0,0 +1,3 @@
1
+ class UsersController < ApplicationController
2
+ include Clearance::App::Controllers::UsersController
3
+ end
@@ -0,0 +1,5 @@
1
+ class ClearanceMailer < ActionMailer::Base
2
+ default_url_options[:host] = HOST
3
+
4
+ include Clearance::App::Models::ClearanceMailer
5
+ end
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ include Clearance::App::Models::User
3
+ end
@@ -0,0 +1,7 @@
1
+ Someone, hopefully you, has requested that we send you a link to change your password.
2
+
3
+ Here's the link:
4
+
5
+ <%= edit_user_password_url(@user, :token => @user.token, :escape => false) %>
6
+
7
+ If you didn't request this, ignore this email. Don't worry. Your password hasn't been changed.
@@ -0,0 +1,2 @@
1
+
2
+ <%= new_user_confirmation_url :user_id => @user, :token => @user.token, :encode => false %>
@@ -0,0 +1,23 @@
1
+ <h2>Change your password</h2>
2
+
3
+ <p>
4
+ Your password has been reset. Choose a new password below.
5
+ </p>
6
+
7
+ <%= error_messages_for :user %>
8
+
9
+ <% form_for(:user,
10
+ :url => user_password_path(@user, :token => @user.token),
11
+ :html => { :method => :put }) do |form| %>
12
+ <div class="password_field">
13
+ <%= form.label :password, "Choose password" %>
14
+ <%= form.password_field :password %>
15
+ </div>
16
+ <div class="password_field">
17
+ <%= form.label :password_confirmation, "Confirm password" %>
18
+ <%= form.password_field :password_confirmation %>
19
+ </div>
20
+ <div class="submit_field">
21
+ <%= form.submit "Save this password", :disable_with => "Please wait..." %>
22
+ </div>
23
+ <% end %>
@@ -0,0 +1,15 @@
1
+ <h2>Change your password</h2>
2
+
3
+ <p>
4
+ We will email you a link to change your password.
5
+ </p>
6
+
7
+ <% form_for :password, :url => passwords_path do |form| %>
8
+ <div class="text_field">
9
+ <%= form.label :email, "Email address" %>
10
+ <%= form.text_field :email %>
11
+ </div>
12
+ <div class="submit_field">
13
+ <%= form.submit "Reset password", :disable_with => "Please wait..." %>
14
+ </div>
15
+ <% end %>
@@ -0,0 +1,28 @@
1
+ <h2>Sign in</h2>
2
+
3
+ <% form_for :session, :url => session_path do |form| %>
4
+ <div class="text_field">
5
+ <%= form.label :email %>
6
+ <%= form.text_field :email %>
7
+ </div>
8
+ <div class="text_field">
9
+ <%= form.label :password %>
10
+ <%= form.password_field :password %>
11
+ </div>
12
+ <div class="text_field">
13
+ <%= form.check_box :remember_me %>
14
+ <%= form.label :remember_me %>
15
+ </div>
16
+ <div class="submit_field">
17
+ <%= form.submit "Sign in", :disable_with => "Please wait..." %>
18
+ </div>
19
+ <% end %>
20
+
21
+ <ul>
22
+ <li>
23
+ <%= link_to "Sign up", new_user_path %>
24
+ </li>
25
+ <li>
26
+ <%= link_to "Forgot password?", new_password_path %>
27
+ </li>
28
+ </ul>
@@ -0,0 +1,13 @@
1
+ <%= form.error_messages %>
2
+ <div class="text_field">
3
+ <%= form.label :email %>
4
+ <%= form.text_field :email %>
5
+ </div>
6
+ <div class="password_field">
7
+ <%= form.label :password %>
8
+ <%= form.password_field :password %>
9
+ </div>
10
+ <div class="password_field">
11
+ <%= form.label :password_confirmation, "Confirm password" %>
12
+ <%= form.password_field :password_confirmation %>
13
+ </div>
@@ -0,0 +1,6 @@
1
+ <h2>Edit user information</h2>
2
+
3
+ <% form_for @user do |form| %>
4
+ <%= render :partial => '/users/form', :object => form %>
5
+ <%= form.submit 'Update', :disable_with => 'Please wait...' %>
6
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <h2>Sign up</h2>
2
+
3
+ <% form_for @user do |form| %>
4
+ <%= render :partial => '/users/form', :object => form %>
5
+ <%= form.submit 'Sign up', :disable_with => 'Please wait...' %>
6
+ <% end %>
@@ -0,0 +1,20 @@
1
+ class CreateOrUpdateUsersWithClearanceColumns < ActiveRecord::Migration
2
+ def self.up
3
+ create_table(:users) do |t|
4
+ t.string :email
5
+ t.string :encrypted_password, :limit => 128
6
+ t.string :salt, :limit => 128
7
+ t.string :token, :limit => 128
8
+ t.datetime :token_expires_at
9
+ t.boolean :email_confirmed, :default => false, :null => false
10
+ end
11
+
12
+ add_index :users, [:id, :token]
13
+ add_index :users, :email
14
+ add_index :users, :token
15
+ end
16
+
17
+ def self.down
18
+ drop_table :users
19
+ end
20
+ end
@@ -0,0 +1,41 @@
1
+ class CreateOrUpdateUsersWithClearanceColumns < ActiveRecord::Migration
2
+ def self.up
3
+ <%
4
+ existing_columns = ActiveRecord::Base.connection.columns(:users).collect { |each| each.name }
5
+ columns = [
6
+ [:email, 't.string :email'],
7
+ [:encrypted_password, 't.string :encrypted_password, :limit => 128'],
8
+ [:salt, 't.string :salt, :limit => 128'],
9
+ [:token, 't.string :token, :limit => 128'],
10
+ [:token_expires_at, 't.datetime :token_expires_at'],
11
+ [:email_confirmed, 't.boolean :email_confirmed, :default => false, :null => false']
12
+ ].delete_if {|c| existing_columns.include?(c.first.to_s)}
13
+ -%>
14
+ change_table(:users) do |t|
15
+ <% columns.each do |c| -%>
16
+ <%= c.last %>
17
+ <% end -%>
18
+ end
19
+
20
+ <%
21
+ existing_indexes = ActiveRecord::Base.connection.indexes(:users)
22
+ index_names = existing_indexes.collect { |each| each.name }
23
+ new_indexes = [
24
+ [:index_users_on_id_and_token, 'add_index :users, [:id, :token]'],
25
+ [:index_users_on_email, 'add_index :users, :email'],
26
+ [:index_users_on_token, 'add_index :users, :token']
27
+ ].delete_if { |each| index_names.include?(each.first.to_s) }
28
+ -%>
29
+ <% new_indexes.each do |each| -%>
30
+ <%= each.last %>
31
+ <% end -%>
32
+ end
33
+
34
+ def self.down
35
+ change_table(:users) do |t|
36
+ <% unless columns.empty? -%>
37
+ t.remove <%= columns.collect { |each| ":#{each.first}" }.join(',') %>
38
+ <% end -%>
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,16 @@
1
+ Factory.sequence :email do |n|
2
+ "user#{n}@example.com"
3
+ end
4
+
5
+ Factory.define :user do |user|
6
+ user.email { Factory.next :email }
7
+ user.password { "password" }
8
+ user.password_confirmation { "password" }
9
+ end
10
+
11
+ Factory.define :email_confirmed_user, :class => 'user' do |user|
12
+ user.email { Factory.next :email }
13
+ user.password { "password" }
14
+ user.password_confirmation { "password" }
15
+ user.email_confirmed { true }
16
+ end
@@ -0,0 +1,5 @@
1
+ require 'test_helper'
2
+
3
+ class ConfirmationsControllerTest < ActionController::TestCase
4
+ include Clearance::Test::Functional::ConfirmationsControllerTest
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'test_helper'
2
+
3
+ class PasswordsControllerTest < ActionController::TestCase
4
+ include Clearance::Test::Functional::PasswordsControllerTest
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'test_helper'
2
+
3
+ class SessionsControllerTest < ActionController::TestCase
4
+ include Clearance::Test::Functional::SessionsControllerTest
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'test_helper'
2
+
3
+ class UsersControllerTest < ActionController::TestCase
4
+ include Clearance::Test::Functional::UsersControllerTest
5
+ end
@@ -0,0 +1,6 @@
1
+ require 'test_helper'
2
+
3
+ class ClearanceMailerTest < ActionMailer::TestCase
4
+ tests ClearanceMailer
5
+ include Clearance::Test::Unit::ClearanceMailerTest
6
+ end
@@ -0,0 +1,5 @@
1
+ require 'test_helper'
2
+
3
+ class UserTest < ActiveSupport::TestCase
4
+ include Clearance::Test::Unit::UserTest
5
+ end
@@ -0,0 +1 @@
1
+ script/generate clearance_features
@@ -0,0 +1,20 @@
1
+ class ClearanceFeaturesGenerator < Rails::Generator::Base
2
+
3
+ def manifest
4
+ record do |m|
5
+ m.directory File.join("features", "step_definitions")
6
+ m.directory File.join("features", "support")
7
+
8
+ ["features/step_definitions/clearance_steps.rb",
9
+ "features/step_definitions/factory_girl_steps.rb",
10
+ "features/support/paths.rb",
11
+ "features/sign_in.feature",
12
+ "features/sign_out.feature",
13
+ "features/sign_up.feature",
14
+ "features/password_reset.feature"].each do |file|
15
+ m.file file, file
16
+ end
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,31 @@
1
+ Feature: Password reset
2
+ In order to sign in even if user forgot their password
3
+ A user
4
+ Should be able to reset it
5
+
6
+ Scenario: User is not signed up
7
+ Given no user exists with an email of "email@person.com"
8
+ When I request password reset link to be sent to "email@person.com"
9
+ Then I should see "Unknown email"
10
+
11
+ Scenario: User is signed up and requests password reset
12
+ Given I signed up with "email@person.com/password"
13
+ When I request password reset link to be sent to "email@person.com"
14
+ Then I should see "instructions for changing your password"
15
+ And a password reset message should be sent to "email@person.com"
16
+
17
+ Scenario: User is signed up updated his password and types wrong confirmation
18
+ Given I signed up with "email@person.com/password"
19
+ When I follow the password reset link sent to "email@person.com"
20
+ And I update my password with "newpassword/wrongconfirmation"
21
+ Then I should see error messages
22
+ And I should not be signed in
23
+
24
+ Scenario: User is signed up and updates his password
25
+ Given I signed up with "email@person.com/password"
26
+ When I follow the password reset link sent to "email@person.com"
27
+ And I update my password with "newpassword/newpassword"
28
+ Then I should be signed in
29
+ When I sign out
30
+ And I sign in as "email@person.com/newpassword"
31
+ Then I should be signed in
@@ -0,0 +1,41 @@
1
+ Feature: Sign in
2
+ In order to get access to protected sections of the site
3
+ A user
4
+ Should be able to sign in
5
+
6
+ Scenario: User is not signed up
7
+ Given no user exists with an email of "email@person.com"
8
+ When I go to the sign in page
9
+ And I sign in as "email@person.com/password"
10
+ Then I should see "Bad email or password"
11
+ And I should not be signed in
12
+
13
+ Scenario: User is not confirmed
14
+ Given I signed up with "email@person.com/password"
15
+ When I go to the sign in page
16
+ And I sign in as "email@person.com/password"
17
+ Then I should see "User has not confirmed email"
18
+ And I should not be signed in
19
+
20
+ Scenario: User enters wrong password
21
+ Given I am signed up and confirmed as "email@person.com/password"
22
+ When I go to the sign in page
23
+ And I sign in as "email@person.com/wrongpassword"
24
+ Then I should see "Bad email or password"
25
+ And I should not be signed in
26
+
27
+ Scenario: User signs in successfully
28
+ Given I am signed up and confirmed as "email@person.com/password"
29
+ When I go to the sign in page
30
+ And I sign in as "email@person.com/password"
31
+ Then I should see "Signed in successfully"
32
+ And I should be signed in
33
+
34
+ Scenario: User signs in and checks "remember me"
35
+ Given I am signed up and confirmed as "email@person.com/password"
36
+ When I go to the sign in page
37
+ And I sign in with "remember me" as "email@person.com/password"
38
+ Then I should see "Signed in successfully"
39
+ And I should be signed in
40
+ When I return next time
41
+ Then I should be signed in