Commit a3d9f0bbfdae40889c49c78c33044e2001012559

Authored by AntonioTerceiro
1 parent 4f51c61b

ActionItem9: adding user accounts model and controller, just generated acts_as_authenticated code



git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@94 3f533792-8f58-4932-b0fe-aaf55b0a4547
app/controllers/account_controller.rb 0 → 100644
... ... @@ -0,0 +1,43 @@
  1 +class AccountController < ApplicationController
  2 + # Be sure to include AuthenticationSystem in Application Controller instead
  3 + include AuthenticatedSystem
  4 + # If you want "remember me" functionality, add this before_filter to Application Controller
  5 + before_filter :login_from_cookie
  6 +
  7 + # say something nice, you goof! something sweet.
  8 + def index
  9 + redirect_to(:action => 'signup') unless logged_in? || User.count > 0
  10 + end
  11 +
  12 + def login
  13 + return unless request.post?
  14 + self.current_user = User.authenticate(params[:login], params[:password])
  15 + if logged_in?
  16 + if params[:remember_me] == "1"
  17 + self.current_user.remember_me
  18 + cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
  19 + end
  20 + redirect_back_or_default(:controller => '/account', :action => 'index')
  21 + flash[:notice] = "Logged in successfully"
  22 + end
  23 + end
  24 +
  25 + def signup
  26 + @user = User.new(params[:user])
  27 + return unless request.post?
  28 + @user.save!
  29 + self.current_user = @user
  30 + redirect_back_or_default(:controller => '/account', :action => 'index')
  31 + flash[:notice] = "Thanks for signing up!"
  32 + rescue ActiveRecord::RecordInvalid
  33 + render :action => 'signup'
  34 + end
  35 +
  36 + def logout
  37 + self.current_user.forget_me if logged_in?
  38 + cookies.delete :auth_token
  39 + reset_session
  40 + flash[:notice] = "You have been logged out."
  41 + redirect_back_or_default(:controller => '/account', :action => 'index')
  42 + end
  43 +end
... ...
app/helpers/account_helper.rb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +module AccountHelper
  2 +end
0 3 \ No newline at end of file
... ...
app/models/user.rb 0 → 100644
... ... @@ -0,0 +1,64 @@
  1 +require 'digest/sha1'
  2 +class User < ActiveRecord::Base
  3 + # Virtual attribute for the unencrypted password
  4 + attr_accessor :password
  5 +
  6 + validates_presence_of :login, :email
  7 + validates_presence_of :password, :if => :password_required?
  8 + validates_presence_of :password_confirmation, :if => :password_required?
  9 + validates_length_of :password, :within => 4..40, :if => :password_required?
  10 + validates_confirmation_of :password, :if => :password_required?
  11 + validates_length_of :login, :within => 3..40
  12 + validates_length_of :email, :within => 3..100
  13 + validates_uniqueness_of :login, :email, :case_sensitive => false
  14 + before_save :encrypt_password
  15 +
  16 + # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
  17 + def self.authenticate(login, password)
  18 + u = find_by_login(login) # need to get the salt
  19 + u && u.authenticated?(password) ? u : nil
  20 + end
  21 +
  22 + # Encrypts some data with the salt.
  23 + def self.encrypt(password, salt)
  24 + Digest::SHA1.hexdigest("--#{salt}--#{password}--")
  25 + end
  26 +
  27 + # Encrypts the password with the user salt
  28 + def encrypt(password)
  29 + self.class.encrypt(password, salt)
  30 + end
  31 +
  32 + def authenticated?(password)
  33 + crypted_password == encrypt(password)
  34 + end
  35 +
  36 + def remember_token?
  37 + remember_token_expires_at && Time.now.utc < remember_token_expires_at
  38 + end
  39 +
  40 + # These create and unset the fields required for remembering users between browser closes
  41 + def remember_me
  42 + self.remember_token_expires_at = 2.weeks.from_now.utc
  43 + self.remember_token = encrypt("#{email}--#{remember_token_expires_at}")
  44 + save(false)
  45 + end
  46 +
  47 + def forget_me
  48 + self.remember_token_expires_at = nil
  49 + self.remember_token = nil
  50 + save(false)
  51 + end
  52 +
  53 + protected
  54 + # before filter
  55 + def encrypt_password
  56 + return if password.blank?
  57 + self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
  58 + self.crypted_password = encrypt(password)
  59 + end
  60 +
  61 + def password_required?
  62 + crypted_password.blank? || !password.blank?
  63 + end
  64 +end
... ...
app/views/account/index.rhtml 0 → 100644
... ... @@ -0,0 +1,56 @@
  1 +<h1>In the Caboose.</h1>
  2 +
  3 +<% content_for 'poem' do -%>
  4 +"Train delayed? and what's to say?"
  5 +"Blocked by last night's snow they say."
  6 +Seven hours or so to wait;
  7 +Well, that's pleasant! but there's the freight.
  8 +Depot loafing no one fancies,
  9 +We'll try the caboose and take our chances.
  10 +
  11 +Cool this morning in Watertown,
  12 +Somewhat frosty___mercury down;
  13 +Enter caboose___roaring fire,
  14 +With never an air-hole; heat so dire
  15 +That we shrivel and pant; we are roasted through-
  16 +Outside, thermometer thirty-two.
  17 +
  18 +We start with a jerk and suddenly stop.
  19 +"What's broke?" says one; another "What's up?",
  20 +"Oh, nothing," they answer, "That's our way:
  21 +You must stand the jerking, sorry to say."
  22 +We "stand it" with oft this painful thought:
  23 +Are our heads on yet, or are they not?
  24 +
  25 +Comrades in misery___let me see;
  26 +Girl like a statue opposite me;
  27 +Back and forth the others jostle___
  28 +She never winks, nor moves a muscle;
  29 +See her, as she sits there now;
  30 +She's "well balanced," anyhow.
  31 +
  32 +Woman in trouble, tearful eyes,
  33 +Sits by the window, softly cries,
  34 +Pity___for griefs we may not know,
  35 +For breasts that ache, for tears that flow,
  36 +Though we know not why. Her eyelids red
  37 +Tell a sorrowful tale___some hope is dead.
  38 +
  39 +Man who follows the Golden Rule,
  40 +And lends his papers___a pocket full,
  41 +Has a blank book___once in a minute
  42 +Has an idea, and writes it in it.
  43 +Guess him? Yes, of course I can,
  44 +He's a___well___a newspaper man.
  45 +
  46 +Blue-eyed fairy, wrapped in fur;
  47 +Sweet young mother tending her.
  48 +Fairy thinks it's "awful far,"
  49 +Wants to get off this "naughty car."
  50 +So do we, young golden-hair;
  51 +All this crowd are with you there!
  52 +<% end -%>
  53 +
  54 +<%= simple_format @content_for_poem %>
  55 +
  56 +<p><a href="http://skyways.lib.ks.us/poetry/walls/caboose.html">-- Ellen P. Allerton.</a></p>
0 57 \ No newline at end of file
... ...
app/views/account/login.rhtml 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +<% form_tag do -%>
  2 +<p><label for="login">Login</label><br/>
  3 +<%= text_field_tag 'login' %></p>
  4 +
  5 +<p><label for="password">Password</label><br/>
  6 +<%= password_field_tag 'password' %></p>
  7 +
  8 +<!-- Uncomment this if you want this functionality
  9 +<p><label for="remember_me">Remember me:</label>
  10 +<%= check_box_tag 'remember_me' %></p>
  11 +-->
  12 +
  13 +<p><%= submit_tag 'Log in' %></p>
  14 +<% end -%>
... ...
app/views/account/signup.rhtml 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<%= error_messages_for :user %>
  2 +<% form_for :user do |f| -%>
  3 +<p><label for="login">Login</label><br/>
  4 +<%= f.text_field :login %></p>
  5 +
  6 +<p><label for="email">Email</label><br/>
  7 +<%= f.text_field :email %></p>
  8 +
  9 +<p><label for="password">Password</label><br/>
  10 +<%= f.password_field :password %></p>
  11 +
  12 +<p><label for="password_confirmation">Confirm Password</label><br/>
  13 +<%= f.password_field :password_confirmation %></p>
  14 +
  15 +<p><%= submit_tag 'Sign up' %></p>
  16 +<% end -%>
... ...
app/views/layouts/account.rhtml 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<html>
  2 + <head>
  3 + <%= javascript_include_tag :defaults %>
  4 + <%= javascript_include_tag_template @chosen_template %>
  5 + <%= stylesheet_link_tag_template @chosen_template %>
  6 +
  7 + </head>
  8 + <body>
  9 +
  10 + <div id='main'>
  11 + <%= yield %>
  12 + </div>
  13 +
  14 + </body>
  15 +
  16 +</html>
... ...
config/routes.rb
... ... @@ -13,6 +13,9 @@ ActionController::Routing::Routes.draw do |map|
13 13 # -- just remember to delete public/index.html.
14 14 map.connect '', :controller => "home"
15 15  
  16 + # user account controller
  17 + map.connect 'account/:action', :controller => 'account'
  18 +
16 19 # administrative tasks for a virtual community
17 20 map.connect 'admin/:controller/:action/:id'
18 21  
... ...
db/migrate/006_create_users.rb 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +class CreateUsers < ActiveRecord::Migration
  2 + def self.up
  3 + create_table "users", :force => true do |t|
  4 + t.column :login, :string
  5 + t.column :email, :string
  6 + t.column :crypted_password, :string, :limit => 40
  7 + t.column :salt, :string, :limit => 40
  8 + t.column :created_at, :datetime
  9 + t.column :updated_at, :datetime
  10 + t.column :remember_token, :string
  11 + t.column :remember_token_expires_at, :datetime
  12 + end
  13 + end
  14 +
  15 + def self.down
  16 + drop_table "users"
  17 + end
  18 +end
... ...
lib/authenticated_system.rb 0 → 100644
... ... @@ -0,0 +1,120 @@
  1 +module AuthenticatedSystem
  2 + protected
  3 + # Returns true or false if the user is logged in.
  4 + # Preloads @current_user with the user model if they're logged in.
  5 + def logged_in?
  6 + current_user != :false
  7 + end
  8 +
  9 + # Accesses the current user from the session.
  10 + def current_user
  11 + @current_user ||= (session[:user] && User.find_by_id(session[:user])) || :false
  12 + end
  13 +
  14 + # Store the given user in the session.
  15 + def current_user=(new_user)
  16 + session[:user] = (new_user.nil? || new_user.is_a?(Symbol)) ? nil : new_user.id
  17 + @current_user = new_user
  18 + end
  19 +
  20 + # Check if the user is authorized.
  21 + #
  22 + # Override this method in your controllers if you want to restrict access
  23 + # to only a few actions or if you want to check if the user
  24 + # has the correct rights.
  25 + #
  26 + # Example:
  27 + #
  28 + # # only allow nonbobs
  29 + # def authorize?
  30 + # current_user.login != "bob"
  31 + # end
  32 + def authorized?
  33 + true
  34 + end
  35 +
  36 + # Filter method to enforce a login requirement.
  37 + #
  38 + # To require logins for all actions, use this in your controllers:
  39 + #
  40 + # before_filter :login_required
  41 + #
  42 + # To require logins for specific actions, use this in your controllers:
  43 + #
  44 + # before_filter :login_required, :only => [ :edit, :update ]
  45 + #
  46 + # To skip this in a subclassed controller:
  47 + #
  48 + # skip_before_filter :login_required
  49 + #
  50 + def login_required
  51 + username, passwd = get_auth_data
  52 + self.current_user ||= User.authenticate(username, passwd) || :false if username && passwd
  53 + logged_in? && authorized? ? true : access_denied
  54 + end
  55 +
  56 + # Redirect as appropriate when an access request fails.
  57 + #
  58 + # The default action is to redirect to the login screen.
  59 + #
  60 + # Override this method in your controllers if you want to have special
  61 + # behavior in case the user is not authorized
  62 + # to access the requested action. For example, a popup window might
  63 + # simply close itself.
  64 + def access_denied
  65 + respond_to do |accepts|
  66 + accepts.html do
  67 + store_location
  68 + redirect_to :controller => '/account', :action => 'login'
  69 + end
  70 + accepts.xml do
  71 + headers["Status"] = "Unauthorized"
  72 + headers["WWW-Authenticate"] = %(Basic realm="Web Password")
  73 + render :text => "Could't authenticate you", :status => '401 Unauthorized'
  74 + end
  75 + end
  76 + false
  77 + end
  78 +
  79 + # Store the URI of the current request in the session.
  80 + #
  81 + # We can return to this location by calling #redirect_back_or_default.
  82 + def store_location
  83 + session[:return_to] = request.request_uri
  84 + end
  85 +
  86 + # Redirect to the URI stored by the most recent store_location call or
  87 + # to the passed default.
  88 + def redirect_back_or_default(default)
  89 + session[:return_to] ? redirect_to_url(session[:return_to]) : redirect_to(default)
  90 + session[:return_to] = nil
  91 + end
  92 +
  93 + # Inclusion hook to make #current_user and #logged_in?
  94 + # available as ActionView helper methods.
  95 + def self.included(base)
  96 + base.send :helper_method, :current_user, :logged_in?
  97 + end
  98 +
  99 + # When called with before_filter :login_from_cookie will check for an :auth_token
  100 + # cookie and log the user back in if apropriate
  101 + def login_from_cookie
  102 + return unless cookies[:auth_token] && !logged_in?
  103 + user = User.find_by_remember_token(cookies[:auth_token])
  104 + if user && user.remember_token?
  105 + user.remember_me
  106 + self.current_user = user
  107 + cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
  108 + flash[:notice] = "Logged in successfully"
  109 + end
  110 + end
  111 +
  112 + private
  113 + @@http_auth_headers = %w(X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION Authorization)
  114 + # gets BASIC auth info
  115 + def get_auth_data
  116 + auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
  117 + auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
  118 + return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
  119 + end
  120 +end
... ...
lib/authenticated_test_helper.rb 0 → 100644
... ... @@ -0,0 +1,113 @@
  1 +module AuthenticatedTestHelper
  2 + # Sets the current user in the session from the user fixtures.
  3 + def login_as(user)
  4 + @request.session[:user] = user ? users(user).id : nil
  5 + end
  6 +
  7 + def content_type(type)
  8 + @request.env['Content-Type'] = type
  9 + end
  10 +
  11 + def accept(accept)
  12 + @request.env["HTTP_ACCEPT"] = accept
  13 + end
  14 +
  15 + def authorize_as(user)
  16 + if user
  17 + @request.env["HTTP_AUTHORIZATION"] = "Basic #{Base64.encode64("#{users(user).login}:test")}"
  18 + accept 'application/xml'
  19 + content_type 'application/xml'
  20 + else
  21 + @request.env["HTTP_AUTHORIZATION"] = nil
  22 + accept nil
  23 + content_type nil
  24 + end
  25 + end
  26 +
  27 + # http://project.ioni.st/post/217#post-217
  28 + #
  29 + # def test_new_publication
  30 + # assert_difference(Publication, :count) do
  31 + # post :create, :publication => {...}
  32 + # # ...
  33 + # end
  34 + # end
  35 + #
  36 + def assert_difference(object, method = nil, difference = 1)
  37 + initial_value = object.send(method)
  38 + yield
  39 + assert_equal initial_value + difference, object.send(method), "#{object}##{method}"
  40 + end
  41 +
  42 + def assert_no_difference(object, method, &block)
  43 + assert_difference object, method, 0, &block
  44 + end
  45 +
  46 + # Assert the block redirects to the login
  47 + #
  48 + # assert_requires_login(:bob) { |c| c.get :edit, :id => 1 }
  49 + #
  50 + def assert_requires_login(login = nil)
  51 + yield HttpLoginProxy.new(self, login)
  52 + end
  53 +
  54 + def assert_http_authentication_required(login = nil)
  55 + yield XmlLoginProxy.new(self, login)
  56 + end
  57 +
  58 + def reset!(*instance_vars)
  59 + instance_vars = [:controller, :request, :response] unless instance_vars.any?
  60 + instance_vars.collect! { |v| "@#{v}".to_sym }
  61 + instance_vars.each do |var|
  62 + instance_variable_set(var, instance_variable_get(var).class.new)
  63 + end
  64 + end
  65 +end
  66 +
  67 +class BaseLoginProxy
  68 + attr_reader :controller
  69 + attr_reader :options
  70 + def initialize(controller, login)
  71 + @controller = controller
  72 + @login = login
  73 + end
  74 +
  75 + private
  76 + def authenticated
  77 + raise NotImplementedError
  78 + end
  79 +
  80 + def check
  81 + raise NotImplementedError
  82 + end
  83 +
  84 + def method_missing(method, *args)
  85 + @controller.reset!
  86 + authenticate
  87 + @controller.send(method, *args)
  88 + check
  89 + end
  90 +end
  91 +
  92 +class HttpLoginProxy < BaseLoginProxy
  93 + protected
  94 + def authenticate
  95 + @controller.login_as @login if @login
  96 + end
  97 +
  98 + def check
  99 + @controller.assert_redirected_to :controller => 'account', :action => 'login'
  100 + end
  101 +end
  102 +
  103 +class XmlLoginProxy < BaseLoginProxy
  104 + protected
  105 + def authenticate
  106 + @controller.accept 'application/xml'
  107 + @controller.authorize_as @login if @login
  108 + end
  109 +
  110 + def check
  111 + @controller.assert_response 401
  112 + end
  113 +end
0 114 \ No newline at end of file
... ...
test/fixtures/users.yml 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +quentin:
  2 + id: 1
  3 + login: quentin
  4 + email: quentin@example.com
  5 + salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
  6 + crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
  7 + #crypted_password: "ce2/iFrNtQ8=\n" # quentin, use only if you're using 2-way encryption
  8 + created_at: <%= 5.days.ago.to_s :db %>
  9 + # activated_at: <%= 5.days.ago.to_s :db %> # only if you're activating new signups
  10 +aaron:
  11 + id: 2
  12 + login: aaron
  13 + email: aaron@example.com
  14 + salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
  15 + crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
  16 + # activation_code: aaronscode # only if you're activating new signups
  17 + created_at: <%= 1.days.ago.to_s :db %>
0 18 \ No newline at end of file
... ...
test/functional/account_controller_test.rb 0 → 100644
... ... @@ -0,0 +1,129 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +require 'account_controller'
  3 +
  4 +# Re-raise errors caught by the controller.
  5 +class AccountController; def rescue_action(e) raise e end; end
  6 +
  7 +class AccountControllerTest < Test::Unit::TestCase
  8 + # Be sure to include AuthenticatedTestHelper in test/test_helper.rb instead
  9 + # Then, you can remove it from this and the units test.
  10 + include AuthenticatedTestHelper
  11 +
  12 + fixtures :users
  13 +
  14 + def setup
  15 + @controller = AccountController.new
  16 + @request = ActionController::TestRequest.new
  17 + @response = ActionController::TestResponse.new
  18 + end
  19 +
  20 + def test_should_login_and_redirect
  21 + post :login, :login => 'quentin', :password => 'test'
  22 + assert session[:user]
  23 + assert_response :redirect
  24 + end
  25 +
  26 + def test_should_fail_login_and_not_redirect
  27 + post :login, :login => 'quentin', :password => 'bad password'
  28 + assert_nil session[:user]
  29 + assert_response :success
  30 + end
  31 +
  32 + def test_should_allow_signup
  33 + assert_difference User, :count do
  34 + create_user
  35 + assert_response :redirect
  36 + end
  37 + end
  38 +
  39 + def test_should_require_login_on_signup
  40 + assert_no_difference User, :count do
  41 + create_user(:login => nil)
  42 + assert assigns(:user).errors.on(:login)
  43 + assert_response :success
  44 + end
  45 + end
  46 +
  47 + def test_should_require_password_on_signup
  48 + assert_no_difference User, :count do
  49 + create_user(:password => nil)
  50 + assert assigns(:user).errors.on(:password)
  51 + assert_response :success
  52 + end
  53 + end
  54 +
  55 + def test_should_require_password_confirmation_on_signup
  56 + assert_no_difference User, :count do
  57 + create_user(:password_confirmation => nil)
  58 + assert assigns(:user).errors.on(:password_confirmation)
  59 + assert_response :success
  60 + end
  61 + end
  62 +
  63 + def test_should_require_email_on_signup
  64 + assert_no_difference User, :count do
  65 + create_user(:email => nil)
  66 + assert assigns(:user).errors.on(:email)
  67 + assert_response :success
  68 + end
  69 + end
  70 +
  71 + def test_should_logout
  72 + login_as :quentin
  73 + get :logout
  74 + assert_nil session[:user]
  75 + assert_response :redirect
  76 + end
  77 +
  78 + def test_should_remember_me
  79 + post :login, :login => 'quentin', :password => 'test', :remember_me => "1"
  80 + assert_not_nil @response.cookies["auth_token"]
  81 + end
  82 +
  83 + def test_should_not_remember_me
  84 + post :login, :login => 'quentin', :password => 'test', :remember_me => "0"
  85 + assert_nil @response.cookies["auth_token"]
  86 + end
  87 +
  88 + def test_should_delete_token_on_logout
  89 + login_as :quentin
  90 + get :logout
  91 + assert_equal @response.cookies["auth_token"], []
  92 + end
  93 +
  94 + def test_should_login_with_cookie
  95 + users(:quentin).remember_me
  96 + @request.cookies["auth_token"] = cookie_for(:quentin)
  97 + get :index
  98 + assert @controller.send(:logged_in?)
  99 + end
  100 +
  101 + def test_should_fail_expired_cookie_login
  102 + users(:quentin).remember_me
  103 + users(:quentin).update_attribute :remember_token_expires_at, 5.minutes.ago
  104 + @request.cookies["auth_token"] = cookie_for(:quentin)
  105 + get :index
  106 + assert !@controller.send(:logged_in?)
  107 + end
  108 +
  109 + def test_should_fail_cookie_login
  110 + users(:quentin).remember_me
  111 + @request.cookies["auth_token"] = auth_token('invalid_auth_token')
  112 + get :index
  113 + assert !@controller.send(:logged_in?)
  114 + end
  115 +
  116 + protected
  117 + def create_user(options = {})
  118 + post :signup, :user => { :login => 'quire', :email => 'quire@example.com',
  119 + :password => 'quire', :password_confirmation => 'quire' }.merge(options)
  120 + end
  121 +
  122 + def auth_token(token)
  123 + CGI::Cookie.new('name' => 'auth_token', 'value' => token)
  124 + end
  125 +
  126 + def cookie_for(user)
  127 + auth_token users(user).remember_token
  128 + end
  129 +end
... ...
test/integration/routing_test.rb
... ... @@ -6,4 +6,8 @@ class RoutingTest &lt; ActionController::IntegrationTest
6 6 assert_routing('admin/features', :controller => 'features', :action => 'index')
7 7 end
8 8  
  9 + def test_account_controller
  10 + assert_routing('account', :controller => 'account', :action => 'index')
  11 + end
  12 +
9 13 end
... ...
test/unit/user_test.rb 0 → 100644
... ... @@ -0,0 +1,75 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class UserTest < Test::Unit::TestCase
  4 + # Be sure to include AuthenticatedTestHelper in test/test_helper.rb instead.
  5 + # Then, you can remove it from this and the functional test.
  6 + include AuthenticatedTestHelper
  7 + fixtures :users
  8 +
  9 + def test_should_create_user
  10 + assert_difference User, :count do
  11 + user = create_user
  12 + assert !user.new_record?, "#{user.errors.full_messages.to_sentence}"
  13 + end
  14 + end
  15 +
  16 + def test_should_require_login
  17 + assert_no_difference User, :count do
  18 + u = create_user(:login => nil)
  19 + assert u.errors.on(:login)
  20 + end
  21 + end
  22 +
  23 + def test_should_require_password
  24 + assert_no_difference User, :count do
  25 + u = create_user(:password => nil)
  26 + assert u.errors.on(:password)
  27 + end
  28 + end
  29 +
  30 + def test_should_require_password_confirmation
  31 + assert_no_difference User, :count do
  32 + u = create_user(:password_confirmation => nil)
  33 + assert u.errors.on(:password_confirmation)
  34 + end
  35 + end
  36 +
  37 + def test_should_require_email
  38 + assert_no_difference User, :count do
  39 + u = create_user(:email => nil)
  40 + assert u.errors.on(:email)
  41 + end
  42 + end
  43 +
  44 + def test_should_reset_password
  45 + users(:quentin).update_attributes(:password => 'new password', :password_confirmation => 'new password')
  46 + assert_equal users(:quentin), User.authenticate('quentin', 'new password')
  47 + end
  48 +
  49 + def test_should_not_rehash_password
  50 + users(:quentin).update_attributes(:login => 'quentin2')
  51 + assert_equal users(:quentin), User.authenticate('quentin2', 'test')
  52 + end
  53 +
  54 + def test_should_authenticate_user
  55 + assert_equal users(:quentin), User.authenticate('quentin', 'test')
  56 + end
  57 +
  58 + def test_should_set_remember_token
  59 + users(:quentin).remember_me
  60 + assert_not_nil users(:quentin).remember_token
  61 + assert_not_nil users(:quentin).remember_token_expires_at
  62 + end
  63 +
  64 + def test_should_unset_remember_token
  65 + users(:quentin).remember_me
  66 + assert_not_nil users(:quentin).remember_token
  67 + users(:quentin).forget_me
  68 + assert_nil users(:quentin).remember_token
  69 + end
  70 +
  71 + protected
  72 + def create_user(options = {})
  73 + User.create({ :login => 'quire', :email => 'quire@example.com', :password => 'quire', :password_confirmation => 'quire' }.merge(options))
  74 + end
  75 +end
... ...