merb-auth 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +64 -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/views/layout/merb_auth.html.erb +47 -0
- data/app/views/users/login.html.erb +31 -0
- data/app/views/users/signup.html.erb +29 -0
- data/lib/merb-auth/adapter/activerecord.rb +52 -0
- data/lib/merb-auth/adapter/datamapper.rb +78 -0
- data/lib/merb-auth/merbtasks.rb +166 -0
- data/lib/merb-auth/model.rb +80 -0
- data/lib/merb-auth/slicetasks.rb +18 -0
- data/lib/merb-auth.rb +72 -0
- data/public/stylesheets/master.css +157 -0
- data/spec/controllers/router_spec.rb +29 -0
- data/spec/controllers/session_spec.rb +87 -0
- data/spec/controllers/users_spec.rb +41 -0
- data/spec/controllers/view_helper_spec.rb +27 -0
- data/spec/merb-auth_spec.rb +52 -0
- data/spec/models/ar_user_spec.rb +20 -0
- data/spec/models/dm_user_spec.rb +22 -0
- data/spec/models/shared_user_spec.rb +251 -0
- data/spec/spec_helper.rb +42 -0
- metadata +98 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 PragmaQuest Inc
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
MerbAuth
|
2
|
+
=========
|
3
|
+
|
4
|
+
An user authentication slice for Merb, with support for ActiveRecord and DataMapper.
|
5
|
+
See http://github.com/ctran/merb-skel for an example application that uses this slice
|
6
|
+
|
7
|
+
== Installation:
|
8
|
+
|
9
|
+
> gem install merb
|
10
|
+
> gem install merb-slices
|
11
|
+
|
12
|
+
To use activerecord adapter
|
13
|
+
> gem install activerecord
|
14
|
+
> gem merb_activerecord
|
15
|
+
|
16
|
+
To use datamapper adapter
|
17
|
+
> gem install datamapper
|
18
|
+
> gem install merb_datamapper
|
19
|
+
|
20
|
+
=== config/init.rb
|
21
|
+
|
22
|
+
# add the slice as a regular dependency
|
23
|
+
dependency 'merb-auth'
|
24
|
+
|
25
|
+
=== config/router.rb
|
26
|
+
|
27
|
+
# This will add the following routes /login, /logout and /signup
|
28
|
+
r.slice(:MerbAuth)
|
29
|
+
|
30
|
+
# This will add the following routes /merb-auth/login, /merb-auth/logout and /merb-auth/signup
|
31
|
+
r.add_slice(:MerbAuth)
|
32
|
+
|
33
|
+
# This will add the following routes /user/login, /user/logout and /user/signup
|
34
|
+
r.add_slice(:MerbAuth, 'user') # same as :path => 'user'
|
35
|
+
|
36
|
+
=== Normally you should also run the following rake task:
|
37
|
+
> rake slices:merb_auth:install
|
38
|
+
|
39
|
+
== Customization/Overrides
|
40
|
+
|
41
|
+
By default, the user model class MerbAuth::User is aliased to User.
|
42
|
+
|
43
|
+
You can also put your application-level overrides in:
|
44
|
+
|
45
|
+
host-app/slices/merb-auth/app - controllers, models, views ...
|
46
|
+
|
47
|
+
Templates are located in this order:
|
48
|
+
|
49
|
+
1. host-app/slices/merb-auth/app/views/*
|
50
|
+
2. gems/merb-auth/app/views/*
|
51
|
+
3. host-app/app/views/*
|
52
|
+
|
53
|
+
You can use the host application's layout by configuring the
|
54
|
+
merb-auth slice in a before_app_loads block:
|
55
|
+
|
56
|
+
Merb::Slices.config[:merb_auth] = { :layout => :application }
|
57
|
+
|
58
|
+
By default :merb_auth is used. If you need to override
|
59
|
+
stylesheets or javascripts, just specify your own files in your layout
|
60
|
+
instead/in addition to the ones supplied (if any) in
|
61
|
+
host-app/public/slices/merb-auth.
|
62
|
+
|
63
|
+
In any case don't edit those files directly as they may be clobbered any time
|
64
|
+
rake merb_auth:install is run.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
require 'merb-core/version'
|
5
|
+
require 'merb-core/test/tasks/spectasks'
|
6
|
+
|
7
|
+
PLUGIN = "merb-auth"
|
8
|
+
NAME = "merb-auth"
|
9
|
+
AUTHOR = "Cuong Tran"
|
10
|
+
EMAIL = "ctran@pragmaquest.com"
|
11
|
+
HOMEPAGE = "http://merb-slices.rubyforge.org/merb-auth/"
|
12
|
+
SUMMARY = "Merb Slice that provides user authentication"
|
13
|
+
SLICE_VERSION = "0.1.0"
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.name = NAME
|
17
|
+
s.version = SLICE_VERSION
|
18
|
+
s.platform = Gem::Platform::RUBY
|
19
|
+
s.has_rdoc = true
|
20
|
+
s.extra_rdoc_files = ["README", "LICENSE"]
|
21
|
+
s.summary = SUMMARY
|
22
|
+
s.description = s.summary
|
23
|
+
s.author = AUTHOR
|
24
|
+
s.email = EMAIL
|
25
|
+
s.homepage = HOMEPAGE
|
26
|
+
s.add_dependency('merb-slices', '>= 0.9.4')
|
27
|
+
s.require_path = 'lib'
|
28
|
+
s.files = %w(LICENSE README Rakefile) + Dir.glob("{lib,spec,app,public}/**/*")
|
29
|
+
end
|
30
|
+
|
31
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
32
|
+
pkg.gem_spec = spec
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Install Foo as a gem"
|
36
|
+
task :install => [:package] do
|
37
|
+
sh %{sudo gem install pkg/#{NAME}-#{SLICE_VERSION} --no-update-sources --local}
|
38
|
+
end
|
39
|
+
|
40
|
+
namespace :jruby do
|
41
|
+
|
42
|
+
desc "Run :package and install the resulting .gem with jruby"
|
43
|
+
task :install => :package do
|
44
|
+
sh %{#{SUDO} jruby -S gem install pkg/#{NAME}-#{VERSION}.gem --no-rdoc --no-ri}
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module MerbAuth
|
2
|
+
module ControllerMixin
|
3
|
+
protected
|
4
|
+
# Returns true or false if the user is logged in.
|
5
|
+
# Preloads @current_user with the user model if they're logged in.
|
6
|
+
def logged_in?
|
7
|
+
current_user != :false
|
8
|
+
end
|
9
|
+
|
10
|
+
# Accesses the current user from the session. Set it to :false if login fails
|
11
|
+
# so that future calls do not hit the database.
|
12
|
+
def current_user
|
13
|
+
@current_user ||= (login_from_session || login_from_basic_auth || login_from_cookie || :false)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Store the given user in the session.
|
17
|
+
def current_user=(new_user)
|
18
|
+
session[:user] = (new_user.nil? || new_user.is_a?(Symbol)) ? nil : new_user.id
|
19
|
+
@current_user = new_user
|
20
|
+
end
|
21
|
+
|
22
|
+
# Check if the user is authorized
|
23
|
+
#
|
24
|
+
# Override this method in your controllers if you want to restrict access
|
25
|
+
# to only a few actions or if you want to check if the user
|
26
|
+
# has the correct rights.
|
27
|
+
#
|
28
|
+
# Example:
|
29
|
+
#
|
30
|
+
# # only allow nonbobs
|
31
|
+
# def authorized?
|
32
|
+
# current_user.username != "bob"
|
33
|
+
# end
|
34
|
+
def authorized?
|
35
|
+
logged_in?
|
36
|
+
end
|
37
|
+
|
38
|
+
# Filter method to enforce a login requirement.
|
39
|
+
#
|
40
|
+
# To require logins for all actions, use this in your controllers:
|
41
|
+
#
|
42
|
+
# before_filter :login_required
|
43
|
+
#
|
44
|
+
# To require logins for specific actions, use this in your controllers:
|
45
|
+
#
|
46
|
+
# before_filter :login_required, :only => [ :edit, :update ]
|
47
|
+
#
|
48
|
+
# To skip this in a subclassed controller:
|
49
|
+
#
|
50
|
+
# skip_before_filter :login_required
|
51
|
+
#
|
52
|
+
def login_required
|
53
|
+
authorized? || throw(:halt, :access_denied)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Redirect as appropriate when an access request fails.
|
57
|
+
#
|
58
|
+
# The default HTML action is to redirect to the login screen.
|
59
|
+
#
|
60
|
+
# The default XML action is to render the text Couldn't authenticate you.
|
61
|
+
# To provide this response wrapped in XML, make sure to specify an
|
62
|
+
# XML layout, such as /app/views/layouts/application.xml.builder.
|
63
|
+
#
|
64
|
+
# Override this method in your controllers if you want to have special
|
65
|
+
# behavior in case the user is not authorized
|
66
|
+
# to access the requested action. For example, a popup window might
|
67
|
+
# simply close itself.
|
68
|
+
def access_denied
|
69
|
+
case content_type
|
70
|
+
when :html
|
71
|
+
store_location
|
72
|
+
redirect url(:login)
|
73
|
+
when :xml
|
74
|
+
headers["Status"] = "Unauthorized"
|
75
|
+
headers["WWW-Authenticate"] = %(Basic realm="Web Password")
|
76
|
+
self.status = 401
|
77
|
+
render "Couldn't authenticate you"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Store the URI of the current request in the session.
|
82
|
+
#
|
83
|
+
# We can return to this location by calling #redirect_back_or_default.
|
84
|
+
def store_location
|
85
|
+
session[:return_to] = request.uri
|
86
|
+
end
|
87
|
+
|
88
|
+
# Redirect to the URI stored by the most recent store_location call or
|
89
|
+
# to the passed default.
|
90
|
+
def redirect_back_or_default(default)
|
91
|
+
loc = session[:return_to] || default
|
92
|
+
session[:return_to] = nil
|
93
|
+
redirect loc
|
94
|
+
end
|
95
|
+
|
96
|
+
# Inclusion hook to make #current_user and #logged_in?
|
97
|
+
# available as ActionView helper methods.
|
98
|
+
# def self.included(base)
|
99
|
+
# base.send :helper_method, :current_user, :logged_in?
|
100
|
+
# end
|
101
|
+
|
102
|
+
# Called from #current_user. First attempt to login by the user id stored in the session.
|
103
|
+
def login_from_session
|
104
|
+
self.current_user = find_user_by_id(session[:user]) if session[:user]
|
105
|
+
end
|
106
|
+
|
107
|
+
# Called from #current_user. Now, attempt to login by basic authentication information.
|
108
|
+
def login_from_basic_auth
|
109
|
+
username, passwd = get_auth_data
|
110
|
+
self.current_user = verify_login(username, passwd) if username && passwd
|
111
|
+
end
|
112
|
+
|
113
|
+
# Called from #current_user. Finaly, attempt to login by an expiring token in the cookie.
|
114
|
+
def login_from_cookie
|
115
|
+
user = cookies[:auth_token] && find_user_by_remember_token(cookies[:auth_token])
|
116
|
+
if user && user.remember_token?
|
117
|
+
user.remember_me
|
118
|
+
cookies[:auth_token] = { :value => user.remember_token, :expires => Time.parse(user.remember_token_expires_at.strftime) }
|
119
|
+
self.current_user = user
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def reset_session
|
124
|
+
session.data.each{|k,v| session.data.delete(k)}
|
125
|
+
end
|
126
|
+
|
127
|
+
protected
|
128
|
+
def verify_login(username, password)
|
129
|
+
MerbAuth::User.authenticate(username, password)
|
130
|
+
end
|
131
|
+
|
132
|
+
def find_user_by_id(user_id)
|
133
|
+
MerbAuth::User.find_by_id(user_id)
|
134
|
+
end
|
135
|
+
|
136
|
+
def find_user_by_remember_token(token)
|
137
|
+
MerbAuth::User.find_by_remember_token(token)
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
@@http_auth_headers = %w(Authorization HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION X_HTTP_AUTHORIZATION REDIRECT_X_HTTP_AUTHORIZATION)
|
142
|
+
|
143
|
+
# gets BASIC auth info
|
144
|
+
def get_auth_data
|
145
|
+
auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
|
146
|
+
auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
|
147
|
+
return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class MerbAuth::Users < MerbAuth::Application
|
2
|
+
provides :html
|
3
|
+
|
4
|
+
skip_before :login_required
|
5
|
+
|
6
|
+
def login
|
7
|
+
if request.post?
|
8
|
+
self.current_user = verify_login(params[:username], params[:password])
|
9
|
+
if logged_in?
|
10
|
+
if params[:remember_me] == "1"
|
11
|
+
self.current_user.remember_me
|
12
|
+
cookies[:auth_token] = {
|
13
|
+
:value => self.current_user.remember_token,
|
14
|
+
:expires => Time.parse(current_user.remember_token_expires_at.strftime)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
return redirect_back_or_default('/')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
render
|
22
|
+
end
|
23
|
+
|
24
|
+
def logout
|
25
|
+
self.current_user.forget_me if logged_in?
|
26
|
+
cookies.delete :auth_token
|
27
|
+
reset_session
|
28
|
+
redirect_back_or_default('/')
|
29
|
+
end
|
30
|
+
|
31
|
+
def signup
|
32
|
+
cookies.delete :auth_token
|
33
|
+
@user = MerbAuth::User.new(params['merb_auth::user'] || {})
|
34
|
+
|
35
|
+
if request.post? && @user.save
|
36
|
+
return redirect_back_or_default('/')
|
37
|
+
end
|
38
|
+
|
39
|
+
render
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Merb
|
2
|
+
module MerbAuth
|
3
|
+
module ApplicationHelper
|
4
|
+
|
5
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
6
|
+
#
|
7
|
+
# @return <String>
|
8
|
+
# A path relative to the public directory, with added segments.
|
9
|
+
def image_path(*segments)
|
10
|
+
public_path_for(:image, *segments)
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
14
|
+
#
|
15
|
+
# @return <String>
|
16
|
+
# A path relative to the public directory, with added segments.
|
17
|
+
def javascript_path(*segments)
|
18
|
+
public_path_for(:javascript, *segments)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
22
|
+
#
|
23
|
+
# @return <String>
|
24
|
+
# A path relative to the public directory, with added segments.
|
25
|
+
def stylesheet_path(*segments)
|
26
|
+
public_path_for(:stylesheet, *segments)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Construct a path relative to the public directory
|
30
|
+
#
|
31
|
+
# @param <Symbol> The type of component.
|
32
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
33
|
+
#
|
34
|
+
# @return <String>
|
35
|
+
# A path relative to the public directory, with added segments.
|
36
|
+
def public_path_for(type, *segments)
|
37
|
+
File.join(::MerbAuth.public_dir_for(type), *segments)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Construct an app-level path.
|
41
|
+
#
|
42
|
+
# @param <Symbol> The type of component.
|
43
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
44
|
+
#
|
45
|
+
# @return <String>
|
46
|
+
# A path within the host application, with added segments.
|
47
|
+
def app_path_for(type, *segments)
|
48
|
+
File.join(::MerbAuth.app_dir_for(type), *segments)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Construct a slice-level path.
|
52
|
+
#
|
53
|
+
# @param <Symbol> The type of component.
|
54
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
55
|
+
#
|
56
|
+
# @return <String>
|
57
|
+
# A path within the slice source (Gem), with added segments.
|
58
|
+
def slice_path_for(type, *segments)
|
59
|
+
File.join(::MerbAuth.dir_for(type), *segments)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
|
3
|
+
<head>
|
4
|
+
<title>Auth::Slice Sample Layout</title>
|
5
|
+
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
6
|
+
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.1/build/reset-fonts-grids/reset-fonts-grids.css">
|
7
|
+
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.1/build/base/base-min.css">
|
8
|
+
<link href="<%= public_path_for :stylesheet, 'master.css' %>" type="text/css" charset="utf-8" rel="stylesheet" media="all"/>
|
9
|
+
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
|
10
|
+
<script type="text/javascript">
|
11
|
+
(function($) {
|
12
|
+
$(document).ready(function() {
|
13
|
+
$(":text:visible:enabled:first").focus();
|
14
|
+
});
|
15
|
+
})(jQuery);
|
16
|
+
</script>
|
17
|
+
</head>
|
18
|
+
<body>
|
19
|
+
<div id="container">
|
20
|
+
<div id="header-container">
|
21
|
+
<span style="float:right;margin-right:50px">
|
22
|
+
<% if logged_in? %>
|
23
|
+
Welcome <%= current_user.name %>
|
24
|
+
| <a href="<%= url(:logout) %>">Sign out</a>
|
25
|
+
<% else %>
|
26
|
+
<a href="<%= url(:signup) %>">Join now</a>
|
27
|
+
| <a href="<%= url(:login) %>">Sign in</a>
|
28
|
+
<% end %>
|
29
|
+
</span>
|
30
|
+
<h1>Sample MerbAuth App</h1>
|
31
|
+
<hr />
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<div id="main-container">
|
35
|
+
<%= catch_content :for_layout %>
|
36
|
+
</div>
|
37
|
+
|
38
|
+
<hr />
|
39
|
+
|
40
|
+
<div id="footer-container">
|
41
|
+
<div class="left"><%= __FILE__ %></div>
|
42
|
+
<div class="right">© 2008 PragmaQuest Inc. All rights reserved.</div>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
</body>
|
46
|
+
</html>
|
47
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
<div>
|
3
|
+
<div class="form_description">
|
4
|
+
<h2>Member sign in</h2>
|
5
|
+
</div>
|
6
|
+
|
7
|
+
<form action="<%= url(:login) %>" method="post">
|
8
|
+
<% if request.post? -%>
|
9
|
+
<div class="error">
|
10
|
+
<h2>Incorrect username and password</h2>
|
11
|
+
</div>
|
12
|
+
<% end -%>
|
13
|
+
|
14
|
+
<p><label for="username">Username or e-mail</label>
|
15
|
+
<input type="text" name="username" value="<%= params[:username] %>"/></p>
|
16
|
+
|
17
|
+
<p><label for="password">Password</label>
|
18
|
+
<input type="password" name="password"/></p>
|
19
|
+
|
20
|
+
<p><input type="checkbox" name='remember_me' id='remember_me' value="1"/>
|
21
|
+
<label id='remember_me_lb' for="remember_me">Keep me signed in</label></p>
|
22
|
+
|
23
|
+
<p><input type="submit" value="Sign in"/> <span style="margin-left:20px"><a href="#">Forgot password?</a></span></p>
|
24
|
+
</form>
|
25
|
+
|
26
|
+
<form action="#" method="post" style="display:none">
|
27
|
+
<p><label for="openid_url">OpenID</label>
|
28
|
+
<input type="text" value="" size="40" id="openid_url" name="openid_url"/> <small>(e.g. http://username.myopenid.com)</small>
|
29
|
+
</p>
|
30
|
+
</form>
|
31
|
+
</div>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
<div>
|
3
|
+
<div class="form_description">
|
4
|
+
<h2>Sign up here (it's absolutely free)</h2>
|
5
|
+
</div>
|
6
|
+
|
7
|
+
<% form_for @user, :action => url(:signup) do %>
|
8
|
+
<%= error_messages_for :user, lambda{|err| "<li>#{err.join('<br/>')}</li>"} %>
|
9
|
+
|
10
|
+
<p>
|
11
|
+
<%= text_control :name, :label => "Name" %>
|
12
|
+
</p>
|
13
|
+
<p>
|
14
|
+
<%= text_control :username, :label => "Username" %>
|
15
|
+
</p>
|
16
|
+
<p>
|
17
|
+
<%= text_control :email, :label => "E-mail" %>
|
18
|
+
</p>
|
19
|
+
<p>
|
20
|
+
<%= password_control :password, :label => "Password" %>
|
21
|
+
</p>
|
22
|
+
<p>
|
23
|
+
<%= password_control :password_confirmation, :label => "Password Confirmation" %>
|
24
|
+
</p>
|
25
|
+
<p>
|
26
|
+
<%= submit_button "Sign up" %> <span style="margin-left:20px">Already a member? <a href="<%= url(:login) %>">Sign in here</a></span>
|
27
|
+
</p>
|
28
|
+
<% end %>
|
29
|
+
</div>
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module MerbAuth
|
2
|
+
module Adapter
|
3
|
+
module Activerecord
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
include MerbAuth::BaseModel
|
7
|
+
extend ClassMethods
|
8
|
+
|
9
|
+
validates_presence_of :name
|
10
|
+
validates_presence_of :username
|
11
|
+
validates_presence_of :email
|
12
|
+
validates_length_of :username, :within => 3..40
|
13
|
+
validates_length_of :password, :within => 4..40, :if => :password_required?
|
14
|
+
validates_presence_of :password_confirmation, :if => :password_required?
|
15
|
+
validates_confirmation_of :password, :if => :password_required?
|
16
|
+
validates_uniqueness_of :username, :case_sensitive => false, :if => lambda { |u| !u.username.blank? }
|
17
|
+
validates_uniqueness_of :email, :case_sensitive => false, :if => lambda { |u| !u.email.blank? }
|
18
|
+
|
19
|
+
before_save :encrypt_password
|
20
|
+
|
21
|
+
def username=(value)
|
22
|
+
self[:username] = value.downcase if value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
def drop_db_table
|
29
|
+
self.connection.drop_table("users")
|
30
|
+
end
|
31
|
+
|
32
|
+
def create_db_table
|
33
|
+
self.connection.create_table("users") do |t|
|
34
|
+
t.string :name, :limit => 40, :null => false
|
35
|
+
t.string :username, :limit => 40, :null => false
|
36
|
+
t.string :email, :null => false
|
37
|
+
t.string :crypted_password, :limit => 40
|
38
|
+
t.string :salt, :limit => 40, :null => false
|
39
|
+
t.string :remember_token
|
40
|
+
t.date :remember_token_expires_at
|
41
|
+
t.timestamps
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
MerbAuth.send(:remove_const, :User) if defined? MerbAuth::User
|
50
|
+
class MerbAuth::User < ActiveRecord::Base
|
51
|
+
include MerbAuth::Adapter::Activerecord
|
52
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
require 'dm-validations'
|
3
|
+
require 'dm-timestamps'
|
4
|
+
require 'dm-aggregates'
|
5
|
+
|
6
|
+
module MerbAuth
|
7
|
+
module Adapter
|
8
|
+
module Datamapper
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
include ::DataMapper::Resource
|
12
|
+
include MerbAuth::BaseModel
|
13
|
+
extend ClassMethods
|
14
|
+
|
15
|
+
storage_names[:default] = 'users'
|
16
|
+
|
17
|
+
property :id, Integer, :serial => true
|
18
|
+
property :name, String, :length => 3..40, :nullable => false
|
19
|
+
property :username, String, :length => 3..40, :nullable => false
|
20
|
+
property :email, String, :format => :email_address, :nullable => false
|
21
|
+
property :crypted_password, String, :length => 40
|
22
|
+
property :salt, String, :length => 40
|
23
|
+
property :remember_token_expires_at, Date
|
24
|
+
property :remember_token, String
|
25
|
+
property :created_at, DateTime
|
26
|
+
property :updated_at, DateTime
|
27
|
+
|
28
|
+
validates_is_unique :username, :email
|
29
|
+
validates_length :password, :in => 4..40, :if => :password_required?
|
30
|
+
validates_is_confirmed :password, :groups => :create
|
31
|
+
|
32
|
+
before :save, :encrypt_password
|
33
|
+
|
34
|
+
def username=(value)
|
35
|
+
attribute_set(:username, value.downcase) if value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module ClassMethods
|
41
|
+
def create_db_table
|
42
|
+
self.auto_migrate!
|
43
|
+
end
|
44
|
+
|
45
|
+
def drop_db_table
|
46
|
+
self.repository do |r|
|
47
|
+
r.adapter.destroy_model_storage(r, self)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_by_id(id)
|
52
|
+
MerbAuth::User.first(:id => id)
|
53
|
+
end
|
54
|
+
|
55
|
+
def find_by_remember_token(rt)
|
56
|
+
MerbAuth::User.first(:remember_token => rt)
|
57
|
+
end
|
58
|
+
|
59
|
+
def find_by_username(username)
|
60
|
+
if MerbAuth::User.properties[:activated_at]
|
61
|
+
MerbAuth::User.first(:username => username, :activated_at.not => nil)
|
62
|
+
else
|
63
|
+
MerbAuth::User.first(:username => username)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_by_activiation_code(activation_code)
|
68
|
+
MerbAuth::User.first(:activation_code => activation_code)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
MerbAuth.send(:remove_const, :User) if defined? MerbAuth::User
|
76
|
+
class MerbAuth::User
|
77
|
+
include MerbAuth::Adapter::Datamapper
|
78
|
+
end
|