auth-slice 0.1.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/LICENSE +20 -0
- data/README +65 -0
- data/Rakefile +47 -0
- data/app/controllers/application.rb +4 -0
- data/app/controllers/controller_mixin.rb +150 -0
- data/app/controllers/users.rb +41 -0
- data/app/helpers/application_helper.rb +64 -0
- data/app/models/adapter/activerecord.rb +55 -0
- data/app/models/adapter/datamapper.rb +80 -0
- data/app/models/base_model.rb +76 -0
- data/app/views/layout/auth_slice.html.erb +47 -0
- data/app/views/users/login.html.erb +31 -0
- data/app/views/users/signup.html.erb +29 -0
- data/lib/auth-slice.rb +63 -0
- data/lib/auth-slice/merbtasks.rb +110 -0
- data/lib/auth-slice/model.rb +6 -0
- data/public/stylesheets/master.css +157 -0
- data/spec/auth-slice_spec.rb +52 -0
- data/spec/controllers/router_spec.rb +29 -0
- data/spec/controllers/session_spec.rb +87 -0
- data/spec/controllers/users_spec.rb +37 -0
- data/spec/controllers/view_helper_spec.rb +27 -0
- data/spec/models/ar_user_spec.rb +21 -0
- data/spec/models/dm_user_spec.rb +20 -0
- data/spec/models/shared_user_spec.rb +251 -0
- data/spec/spec_helper.rb +42 -0
- metadata +101 -0
@@ -0,0 +1,157 @@
|
|
1
|
+
body {
|
2
|
+
font-family: Arial, Verdana, sans-serif;
|
3
|
+
font-size: 14px;
|
4
|
+
background-color: #fff;
|
5
|
+
color: #000;
|
6
|
+
background-color: #fff;
|
7
|
+
}
|
8
|
+
|
9
|
+
html {
|
10
|
+
height: 100%;
|
11
|
+
}
|
12
|
+
|
13
|
+
hr {
|
14
|
+
border: 0px;
|
15
|
+
color: #ccc;
|
16
|
+
background-color: #cdcdcd;
|
17
|
+
height: 1px;
|
18
|
+
width: 100%;
|
19
|
+
text-align: left;
|
20
|
+
}
|
21
|
+
|
22
|
+
h1, h2, h3 {
|
23
|
+
color: #003399;
|
24
|
+
color: #09579A;
|
25
|
+
background-color: #fff;
|
26
|
+
font-family: Arial, Verdana, sans-serif;
|
27
|
+
font-weight: 300;
|
28
|
+
}
|
29
|
+
|
30
|
+
h1 {
|
31
|
+
font-size: 20px;
|
32
|
+
}
|
33
|
+
h2 {
|
34
|
+
font-size: 15px;
|
35
|
+
}
|
36
|
+
h3 {
|
37
|
+
font-size: 15px;
|
38
|
+
}
|
39
|
+
|
40
|
+
p {
|
41
|
+
line-height: 20px;
|
42
|
+
padding: 5px;
|
43
|
+
}
|
44
|
+
|
45
|
+
a, a:hover {
|
46
|
+
color: #0033CC;
|
47
|
+
background-color: #fff;
|
48
|
+
text-decoration: underline;
|
49
|
+
}
|
50
|
+
|
51
|
+
#container {
|
52
|
+
width: 95%;
|
53
|
+
text-align: left;
|
54
|
+
background-color: #fff;
|
55
|
+
margin-right: auto;
|
56
|
+
margin-left: auto;
|
57
|
+
}
|
58
|
+
|
59
|
+
#header-container {
|
60
|
+
width: 100%;
|
61
|
+
padding-top: 15px;
|
62
|
+
}
|
63
|
+
|
64
|
+
#header-container h1, #header-container h2 {
|
65
|
+
margin-left: 6px;
|
66
|
+
margin-bottom: 6px;
|
67
|
+
}
|
68
|
+
|
69
|
+
#main-container {
|
70
|
+
padding: 15px;
|
71
|
+
min-height: 400px;
|
72
|
+
}
|
73
|
+
|
74
|
+
#footer-container {
|
75
|
+
clear: both;
|
76
|
+
font-size: 12px;
|
77
|
+
font-family: Verdana, Arial, sans-serif;
|
78
|
+
}
|
79
|
+
|
80
|
+
#main-container ul {
|
81
|
+
margin-left: 3.0em;
|
82
|
+
}
|
83
|
+
|
84
|
+
.right {
|
85
|
+
float: right;
|
86
|
+
font-size: 100%;
|
87
|
+
margin-top: 5px;
|
88
|
+
color: #999;
|
89
|
+
background-color: #fff;
|
90
|
+
}
|
91
|
+
.left {
|
92
|
+
float: left;
|
93
|
+
font-size: 100%;
|
94
|
+
margin-top: 5px;
|
95
|
+
color: #999;
|
96
|
+
background-color: #fff;
|
97
|
+
}
|
98
|
+
|
99
|
+
a#google_signup {
|
100
|
+
background:transparent url(/images/btn-google-signup.png) no-repeat scroll 0% 0%;
|
101
|
+
color:#FFFFFF;
|
102
|
+
display:block;
|
103
|
+
font-size:14px;
|
104
|
+
height:67px;
|
105
|
+
line-height:22px;
|
106
|
+
margin:0pt;
|
107
|
+
padding:0px;
|
108
|
+
text-align:center;
|
109
|
+
text-decoration:none;
|
110
|
+
width:151px;
|
111
|
+
}
|
112
|
+
|
113
|
+
a#google_signup div {
|
114
|
+
padding-top:8px;
|
115
|
+
}
|
116
|
+
|
117
|
+
#openid_url, .openid_link {
|
118
|
+
background:#FFFFFF url(/images/openid-login.gif) no-repeat scroll 2px 50%;
|
119
|
+
padding-left:25px;
|
120
|
+
width:14.25em;
|
121
|
+
}
|
122
|
+
|
123
|
+
/** Form inputs **/
|
124
|
+
label {
|
125
|
+
font-weight: bold;
|
126
|
+
display: block;
|
127
|
+
}
|
128
|
+
|
129
|
+
#remember_me {
|
130
|
+
margin: 2px 5px 0px 0px;
|
131
|
+
float: left;
|
132
|
+
}
|
133
|
+
|
134
|
+
div.error {
|
135
|
+
background-color:#FCECEC;
|
136
|
+
}
|
137
|
+
|
138
|
+
div.error ul {
|
139
|
+
padding-bottom:20px;
|
140
|
+
}
|
141
|
+
|
142
|
+
.error {
|
143
|
+
background-color:#FCECEC;
|
144
|
+
}
|
145
|
+
|
146
|
+
.error h2 {
|
147
|
+
background: #CC0000 no-repeat scroll left center;
|
148
|
+
border-color: #CC9999;
|
149
|
+
color:#FFFFFF;
|
150
|
+
border:1px solid #CCCCCC;
|
151
|
+
font-size:14px;
|
152
|
+
padding:5px 5px 5px 10px;
|
153
|
+
}
|
154
|
+
|
155
|
+
.error li {
|
156
|
+
color: #CC0000;
|
157
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe "AuthSlice (module)" do
|
4
|
+
|
5
|
+
it "should be registered in Merb::Slices.slices" do
|
6
|
+
Merb::Slices.slices.should include(AuthSlice)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have an :identifier property" do
|
10
|
+
AuthSlice.identifier.should == "auth-slice"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have a :root property" do
|
14
|
+
AuthSlice.root.should == current_slice_root
|
15
|
+
AuthSlice.root_path('app').should == current_slice_root / 'app'
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should have a dir_for method" do
|
19
|
+
app_path = AuthSlice.dir_for(:application)
|
20
|
+
app_path.should == current_slice_root / 'app'
|
21
|
+
[:view, :model, :controller, :helper, :mailer, :part].each do |type|
|
22
|
+
AuthSlice.dir_for(type).should == app_path / "#{type}s"
|
23
|
+
end
|
24
|
+
public_path = AuthSlice.dir_for(:public)
|
25
|
+
public_path.should == current_slice_root / 'public'
|
26
|
+
[:stylesheet, :javascript, :image].each do |type|
|
27
|
+
AuthSlice.dir_for(type).should == public_path / "#{type}s"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should have a app_dir_for method" do
|
32
|
+
app_path = AuthSlice.app_dir_for(:application)
|
33
|
+
app_path.should == Merb.root / 'slices' / 'auth-slice' / 'app'
|
34
|
+
[:view, :model, :controller, :helper, :mailer, :part].each do |type|
|
35
|
+
AuthSlice.app_dir_for(type).should == app_path / "#{type}s"
|
36
|
+
end
|
37
|
+
public_path = AuthSlice.app_dir_for(:public)
|
38
|
+
public_path.should == Merb.dir_for(:public) / 'slices' / 'auth-slice'
|
39
|
+
[:stylesheet, :javascript, :image].each do |type|
|
40
|
+
AuthSlice.app_dir_for(type).should == public_path / "#{type}s"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should have a public_dir_for method" do
|
45
|
+
public_path = AuthSlice.public_dir_for(:public)
|
46
|
+
public_path.should == '/slices' / 'auth-slice'
|
47
|
+
[:stylesheet, :javascript, :image].each do |type|
|
48
|
+
AuthSlice.public_dir_for(type).should == public_path / "#{type}s"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
2
|
+
|
3
|
+
prefix = 'auth-slice'
|
4
|
+
|
5
|
+
describe "Router.add_slice(:AuthSlice)" do
|
6
|
+
include Merb::Test::Rspec::RouteMatchers
|
7
|
+
|
8
|
+
before(:all) do
|
9
|
+
Merb::Router.prepare { |r| r.add_slice(:AuthSlice) } if standalone?
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have named routes for :login, :logout and :signup" do
|
13
|
+
[:login, :logout, :signup].each do |name|
|
14
|
+
url(name).should == "/#{prefix}/#{name}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should route /#{prefix}/login to Session#new" do
|
19
|
+
request_to("/#{prefix}/login", :get).should route_to(AuthSlice::Users, :login)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should route /#{prefix}/login via post to Session#create" do
|
23
|
+
request_to("/#{prefix}/login", :post).should route_to(AuthSlice::Users, :login)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should route /#{prefix}/logout via delete to Session#destroy" do
|
27
|
+
request_to("/#{prefix}/logout", :delete).should route_to(AuthSlice::Users, :logout)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe "Session Controller", "index action" do
|
4
|
+
before(:all) do
|
5
|
+
Merb::Router.prepare { |r| r.add_slice(:AuthSlice) } if standalone?
|
6
|
+
end
|
7
|
+
|
8
|
+
def login_with(params = {}, &blk)
|
9
|
+
dispatch_to(AuthSlice::Users, :login, params, {:request_method => 'post'}, &blk)
|
10
|
+
end
|
11
|
+
|
12
|
+
def logout(&blk)
|
13
|
+
dispatch_to(AuthSlice::Users, :logout, {}, {}, &blk)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'logins and redirects' do
|
17
|
+
controller = login_with(:username => 'quentin', :password => 'test') {|c|
|
18
|
+
c.should_receive(:verify_login).with('quentin', 'test').and_return(mock("User", :id => 1, :name => 'quentin'))
|
19
|
+
}
|
20
|
+
|
21
|
+
controller.session[:user].should_not be_nil
|
22
|
+
controller.session[:user].should == 1
|
23
|
+
controller.should redirect_to("/")
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'fails login and does not redirect' do
|
27
|
+
controller = login_with(:username => 'quentin', :password => 'bad password') {|c|
|
28
|
+
c.should_receive(:verify_login).with('quentin', 'bad password').and_return(nil)
|
29
|
+
}
|
30
|
+
controller.session[:user].should be_nil
|
31
|
+
controller.should be_successful
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'logs out' do
|
35
|
+
controller = logout {|c|
|
36
|
+
c.stub!(:current_user).and_return(mock("User", :forget_me => true))
|
37
|
+
}
|
38
|
+
controller.session[:user].should be_nil
|
39
|
+
controller.should redirect
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'remembers me' do
|
43
|
+
controller = login_with(:username => 'quentin', :password => 'test', :remember_me => "1") {|c|
|
44
|
+
user = mock("User", :id => 1)
|
45
|
+
c.should_receive(:verify_login).with('quentin', 'test').and_return(user)
|
46
|
+
user.should_receive(:remember_me)
|
47
|
+
user.should_receive(:remember_token).and_return("abc123")
|
48
|
+
user.should_receive(:remember_token_expires_at).and_return(Date.today)
|
49
|
+
}
|
50
|
+
controller.cookies["auth_token"].should_not be_nil
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'does not remember me' do
|
54
|
+
controller = login_with(:username => 'quentin', :password => 'test', :remember_me => "0") {|c|
|
55
|
+
user = mock("User", :id => 1)
|
56
|
+
c.should_receive(:verify_login).with('quentin', 'test').and_return(user)
|
57
|
+
}
|
58
|
+
controller.cookies["auth_token"].should be_nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'deletes token on logout' do
|
62
|
+
controller = logout {|c| controller.stub!(:current_user).and_return(@quentin) }
|
63
|
+
controller.cookies["auth_token"].should == nil
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
it 'logs in with cookie' do
|
68
|
+
controller = login_with do |c|
|
69
|
+
c.request.env[Merb::Const::HTTP_COOKIE] = "auth_token=abc123"
|
70
|
+
c.should_receive(:verify_login).and_return(nil)
|
71
|
+
user = mock("User", :id => 1, :remember_token? => true)
|
72
|
+
c.should_receive(:find_user_by_remember_token).with('abc123').and_return(user)
|
73
|
+
user.should_receive(:remember_me)
|
74
|
+
user.should_receive(:remember_token).and_return("abc123")
|
75
|
+
user.should_receive(:remember_token_expires_at).and_return(Date.today)
|
76
|
+
end
|
77
|
+
controller.should be_logged_in
|
78
|
+
end
|
79
|
+
|
80
|
+
def auth_token(token)
|
81
|
+
CGI::Cookie.new('name' => 'auth_token', 'value' => token)
|
82
|
+
end
|
83
|
+
|
84
|
+
def cookie_for(user)
|
85
|
+
auth_token user.remember_token
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
2
|
+
|
3
|
+
def user_hash(options = {})
|
4
|
+
{ 'name' => 'ctran',
|
5
|
+
'username' => "ctran",
|
6
|
+
'email' => "ctran@example.com",
|
7
|
+
'password' => "sekret",
|
8
|
+
'password_confirmation' => "sekret"}.merge(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe AuthSlice::Users do
|
12
|
+
before(:all) do
|
13
|
+
Merb::Router.prepare { |r| r.add_slice(:AuthSlice) } if standalone?
|
14
|
+
end
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
@user = mock("User", user_hash)
|
18
|
+
AuthSlice::User.should_receive(:new).with(user_hash).and_return(@user)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'allows signup and redirect to /' do
|
22
|
+
@user.should_receive(:save).and_return(true)
|
23
|
+
|
24
|
+
controller = dispatch_to(AuthSlice::Users, :signup, {'auth_slice::user' => user_hash }, {:request_method => 'post'})
|
25
|
+
controller.assigns(:user).should == @user
|
26
|
+
controller.should redirect_to('/')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'reject signup and render errors in template' do
|
30
|
+
@user.should_receive(:save).and_return(false)
|
31
|
+
controller = dispatch_to(AuthSlice::Users, :signup, {'auth_slice::user' => user_hash}, {:request_method => 'post'}) {|c|
|
32
|
+
c.should_receive(:render)
|
33
|
+
}
|
34
|
+
controller.assigns(:user).should == @user
|
35
|
+
controller.should respond_successfully
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
module AuthSlice
|
4
|
+
class Main < Application
|
5
|
+
def index
|
6
|
+
'index'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "AuthSlice::Main (controller)" do
|
12
|
+
before :all do
|
13
|
+
Merb::Router.prepare { |r| r.add_slice(:AuthSlice) } if standalone?
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should have helper methods for dealing with public paths" do
|
17
|
+
controller = dispatch_to(AuthSlice::Main, :index)
|
18
|
+
controller.public_path_for(:image).should == "/slices/auth-slice/images"
|
19
|
+
controller.public_path_for(:javascript).should == "/slices/auth-slice/javascripts"
|
20
|
+
controller.public_path_for(:stylesheet).should == "/slices/auth-slice/stylesheets"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should have a slice-specific _template_root" do
|
24
|
+
AuthSlice::Main._template_root.should == AuthSlice.dir_for(:view)
|
25
|
+
AuthSlice::Main._template_root.should == AuthSlice::Application._template_root
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), "shared_user_spec")
|
2
|
+
|
3
|
+
require 'activerecord'
|
4
|
+
use_orm :activerecord
|
5
|
+
|
6
|
+
describe "User with Activerecord adapter" do
|
7
|
+
before(:all) do
|
8
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
9
|
+
AuthSlice.use_adapter(:activerecord)
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
AuthSlice::User.create_db_table
|
14
|
+
end
|
15
|
+
|
16
|
+
after(:each) do
|
17
|
+
AuthSlice::User.drop_db_table
|
18
|
+
end
|
19
|
+
|
20
|
+
it_should_behave_like "AuthSlice::User"
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), "shared_user_spec")
|
2
|
+
|
3
|
+
use_orm :datamapper
|
4
|
+
|
5
|
+
describe "User with Datamapper adapter" do
|
6
|
+
before(:all) do
|
7
|
+
DataMapper.setup(:default, 'sqlite3::memory:')
|
8
|
+
AuthSlice.use_adapter(:datamapper)
|
9
|
+
end
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
AuthSlice::User.create_db_table
|
13
|
+
end
|
14
|
+
|
15
|
+
after(:each) do
|
16
|
+
AuthSlice::User.drop_db_table
|
17
|
+
end
|
18
|
+
|
19
|
+
it_should_behave_like "AuthSlice::User"
|
20
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), "..", "spec_helper" )
|
2
|
+
|
3
|
+
def valid_user_hash(options = {})
|
4
|
+
{ :name => 'ctran',
|
5
|
+
:username => "ctran",
|
6
|
+
:email => "ctran@example.com",
|
7
|
+
:password => "sekret",
|
8
|
+
:password_confirmation => "sekret"}.merge(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "AuthSlice::User", :shared => true do
|
12
|
+
describe "username" do
|
13
|
+
it "should require username field" do
|
14
|
+
user = AuthSlice::User.new
|
15
|
+
user.should respond_to(:username)
|
16
|
+
user.should_not be_valid
|
17
|
+
user.errors.on(:username).should_not be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should fail validation with username less than 3 chars" do
|
21
|
+
user = AuthSlice::User.new
|
22
|
+
user.username = "AB"
|
23
|
+
user.should_not be_valid
|
24
|
+
user.errors.on(:username).should_not be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should require username with between 3 and 40 chars" do
|
28
|
+
user = AuthSlice::User.new(valid_user_hash(:username => nil))
|
29
|
+
[3,40].each do |num|
|
30
|
+
user.username = "a" * num
|
31
|
+
user.should be_valid
|
32
|
+
user.errors.on(:username).should be_nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should fail validation with username over 90 chars" do
|
37
|
+
user = AuthSlice::User.new
|
38
|
+
user.username = "A" * 41
|
39
|
+
user.valid?
|
40
|
+
user.errors.on(:username).should_not be_nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should make a valid user with all required fields set" do
|
44
|
+
user = AuthSlice::User.new(valid_user_hash)
|
45
|
+
user.save.should be_true
|
46
|
+
user.errors.should be_empty
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should set timestamps after save" do
|
50
|
+
user = AuthSlice::User.new(valid_user_hash)
|
51
|
+
user.save.should be_true
|
52
|
+
user.created_at.should_not be_nil
|
53
|
+
user.updated_at.should_not be_nil
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should make sure username is unique" do
|
57
|
+
user = AuthSlice::User.new( valid_user_hash(:username => "Daniel") )
|
58
|
+
user2 = AuthSlice::User.new( valid_user_hash(:username => "Daniel"))
|
59
|
+
user.save.should be_true
|
60
|
+
user.username.should == "daniel"
|
61
|
+
user2.save.should be_false
|
62
|
+
user2.errors.on(:username).should_not be_nil
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should make sure username is unique regardless of case" do
|
66
|
+
user = AuthSlice::User.new( valid_user_hash(:username => "Daniel") )
|
67
|
+
user2 = AuthSlice::User.new( valid_user_hash(:username => "daniel"))
|
68
|
+
user.save.should be_true
|
69
|
+
user.username = "Daniel"
|
70
|
+
user2.save.should be_false
|
71
|
+
user2.errors.on(:username).should_not be_nil
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should downcase username" do
|
75
|
+
user = AuthSlice::User.new( valid_user_hash(:username => "DaNieL"))
|
76
|
+
user.username.should == "daniel"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should authenticate a user using a class method" do
|
80
|
+
user = AuthSlice::User.new(valid_user_hash)
|
81
|
+
user.save.should be_true
|
82
|
+
AuthSlice::User.authenticate(valid_user_hash[:username], valid_user_hash[:password]).should_not be_nil
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should not authenticate a user using the wrong password" do
|
86
|
+
user = AuthSlice::User.new(valid_user_hash)
|
87
|
+
user.save.should be_true
|
88
|
+
AuthSlice::User.authenticate(valid_user_hash[:username], "not_the_password").should be_nil
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should not authenticate a user using the wrong username" do
|
92
|
+
user = AuthSlice::User.create(valid_user_hash)
|
93
|
+
AuthSlice::User.authenticate("not_the_username", valid_user_hash[:password]).should be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should not authenticate a user that does not exist" do
|
97
|
+
AuthSlice::User.authenticate("i_dont_exist", "password").should be_nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "the password fields for User" do
|
102
|
+
before(:each) do
|
103
|
+
@user = AuthSlice::User.new( valid_user_hash )
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should respond to password" do
|
107
|
+
@user.should respond_to(:password)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should respond to password_confirmation" do
|
111
|
+
@user.should respond_to(:password_confirmation)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should have a protected password_required method" do
|
115
|
+
@user.protected_methods.should include("password_required?")
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should respond to crypted_password" do
|
119
|
+
@user.should respond_to(:crypted_password)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should require password if password is required" do
|
123
|
+
user = AuthSlice::User.new( valid_user_hash(:password => nil))
|
124
|
+
user.stub!(:password_required?).and_return(true)
|
125
|
+
user.should_not be_valid
|
126
|
+
user.errors.on(:password).should_not be_nil
|
127
|
+
user.errors.on(:password).should_not be_empty
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should set the salt" do
|
131
|
+
user = AuthSlice::User.new(valid_user_hash)
|
132
|
+
user.salt.should be_nil
|
133
|
+
user.send(:encrypt_password)
|
134
|
+
user.salt.should_not be_nil
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should require the password on create" do
|
138
|
+
user = AuthSlice::User.new(valid_user_hash(:password => nil))
|
139
|
+
user.save.should_not be_true
|
140
|
+
user.errors.on(:password).should_not be_nil
|
141
|
+
user.errors.on(:password).should_not be_empty
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should require password_confirmation if the password_required?" do
|
145
|
+
user = AuthSlice::User.new(valid_user_hash(:password_confirmation => nil))
|
146
|
+
user.save.should_not be_true
|
147
|
+
(user.errors.on(:password) || user.errors.on(:password_confirmation)).should_not be_nil
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should fail when password is outside 4 and 40 chars" do
|
151
|
+
[3,41].each do |num|
|
152
|
+
user = AuthSlice::User.new(valid_user_hash(:password => ("a" * num)))
|
153
|
+
user.should_not be_valid
|
154
|
+
user.errors.on(:password).should_not be_nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should pass when password is within 4 and 40 chars" do
|
159
|
+
[4,30,40].each do |num|
|
160
|
+
user = AuthSlice::User.new(valid_user_hash(:password => ("a" * num), :password_confirmation => ("a" * num)))
|
161
|
+
user.should be_valid
|
162
|
+
user.errors.on(:password).should be_nil
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should autenticate against a password" do
|
167
|
+
user = AuthSlice::User.new(valid_user_hash)
|
168
|
+
user.save.should be_true
|
169
|
+
user.should be_authenticated(valid_user_hash[:password])
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should not require a password when saving an existing user" do
|
173
|
+
user = AuthSlice::User.create(valid_user_hash)
|
174
|
+
user = AuthSlice::User.find_by_username(valid_user_hash[:username])
|
175
|
+
user.password.should be_nil
|
176
|
+
user.password_confirmation.should be_nil
|
177
|
+
user.username = "some_different_username_to_allow_saving"
|
178
|
+
user.save.should be_true
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "remember_me" do
|
183
|
+
predicate_matchers[:remember_token] = :remember_token?
|
184
|
+
|
185
|
+
before do
|
186
|
+
@user = AuthSlice::User.new(valid_user_hash)
|
187
|
+
|
188
|
+
t = Date.today
|
189
|
+
Date.stub!(:today).and_return(t)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should have a remember_token_expires_at attribute" do
|
193
|
+
@user.attributes.keys.any?{|a| a.to_s == "remember_token_expires_at"}.should_not be_nil
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should return true if remember_token_expires_at is set and is in the future" do
|
197
|
+
@user.remember_token_expires_at = Date.today + 7
|
198
|
+
@user.should remember_token
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should set remember_token_expires_at to a specific date" do
|
202
|
+
time = Date.new(2009,12,25)
|
203
|
+
@user.remember_me_until(time)
|
204
|
+
@user.remember_token_expires_at.should == time
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should set the remember_me token when remembering" do
|
208
|
+
time = Date.new(2009,12,25)
|
209
|
+
@user.remember_me_until(time)
|
210
|
+
@user.remember_token.should_not be_nil
|
211
|
+
@user.save
|
212
|
+
@user = AuthSlice::User.find_by_username(valid_user_hash[:username])
|
213
|
+
@user.remember_token.should_not be_nil
|
214
|
+
@user.remember_token_expires_at.should == time
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should set remember_me token for" do
|
218
|
+
remember_until = Date.today + 7
|
219
|
+
@user.remember_me_for(7)
|
220
|
+
@user.remember_token_expires_at.should == (remember_until)
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should remember_me token for two weeks" do
|
224
|
+
@user.remember_me
|
225
|
+
@user.remember_token_expires_at.should == (Date.today + 14)
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should forget me" do
|
229
|
+
@user.remember_me
|
230
|
+
@user.save
|
231
|
+
@user.forget_me
|
232
|
+
@user.remember_token.should be_nil
|
233
|
+
@user.remember_token_expires_at.should be_nil
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should persist the remember_me token to the database" do
|
237
|
+
@user.remember_me
|
238
|
+
@user.save
|
239
|
+
|
240
|
+
@user = AuthSlice::User.find_by_username(valid_user_hash[:username])
|
241
|
+
@user.remember_token.should_not be_nil
|
242
|
+
@user.remember_token_expires_at == (Date.today + 14)
|
243
|
+
|
244
|
+
@user.forget_me
|
245
|
+
|
246
|
+
@user = AuthSlice::User.find_by_username(valid_user_hash[:username])
|
247
|
+
@user.remember_token.should be_nil
|
248
|
+
@user.remember_token_expires_at.should be_nil
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|