merb_auth_slice_multisite 0.8.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +147 -0
- data/VERSION.yml +4 -0
- data/app/controllers/application.rb +5 -0
- data/app/controllers/exceptions.rb +33 -0
- data/app/controllers/passwords.rb +29 -0
- data/app/controllers/sessions.rb +56 -0
- data/app/helpers/application_helper.rb +64 -0
- data/app/mailers/send_password_mailer.rb +11 -0
- data/app/mailers/views/send_password_mailer/send_password.text.erb +3 -0
- data/app/models/site.rb +26 -0
- data/app/views/exceptions/unauthenticated.html.erb +61 -0
- data/app/views/layout/merb_auth_slice_multisite.html.erb +16 -0
- data/config/database.yml +33 -0
- data/config/dependencies.rb +33 -0
- data/config/init.rb +84 -0
- data/config/router.rb +5 -0
- data/lib/merb-auth-more/strategies/multisite/multisite_password_form.rb +77 -0
- data/lib/merb-auth-remember-me/mixins/authenticated_user.rb +97 -0
- data/lib/merb-auth-remember-me/mixins/authenticated_user/dm_authenticated_user.rb +17 -0
- data/lib/merb-auth-remember-me/strategies/remember_me.rb +55 -0
- data/lib/merb_auth_slice_multisite.rb +107 -0
- data/lib/merb_auth_slice_multisite/merbtasks.rb +103 -0
- data/lib/merb_auth_slice_multisite/mixins/user_belongs_to_site.rb +63 -0
- data/lib/merb_auth_slice_multisite/mixins/user_belongs_to_site/dm_user_belongs_to_site.rb +28 -0
- data/lib/merb_auth_slice_multisite/slicetasks.rb +18 -0
- data/lib/merb_auth_slice_multisite/spectasks.rb +54 -0
- data/public/javascripts/master.js +0 -0
- data/public/stylesheets/master.css +2 -0
- data/spec/mailers/send_password_mailer_spec.rb +47 -0
- data/spec/mixins/authenticated_user_spec.rb +33 -0
- data/spec/mixins/user_belongs_to_site_spec.rb +56 -0
- data/spec/models/site_spec.rb +56 -0
- data/spec/spec_helper.rb +101 -0
- data/spec/strategies/remember_me_spec.rb +62 -0
- data/stubs/app/controllers/sessions.rb +19 -0
- data/stubs/app/views/exceptions/unauthenticated.html.erb +61 -0
- metadata +91 -0
data/README.textile
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
h1. MerbAuthSliceMultisite
|
2
|
+
|
3
|
+
This slice setups multisite capabilities in your merb application with subdomains (i.e. coolcars.yourapp.com) and an authentication check.
|
4
|
+
|
5
|
+
Noteworthy: This multisite gem validates the usernames by the scope of the subdomain. This means someone can create another subdomain site using the same username and password, but technically it will be a new user in the users table - similar to how blinksale works. This is how I prefer things. It saves the hassle of a has_and_belongs_to_many relationship and the extra signup hoops you have to go through as a user if you want to create multiple accounts - lighthouse is an example of this.
|
6
|
+
|
7
|
+
h2. Instructions for installation:
|
8
|
+
|
9
|
+
1. Add github as a gem source & install
|
10
|
+
<pre><code>gem sources -a http://gems.github.com
|
11
|
+
sudo gem install scottmotte-merb_auth_slice_multisite
|
12
|
+
</code></pre>
|
13
|
+
|
14
|
+
2. Setup your application to use the gem.* Add the following to the end of dependencies.rb.
|
15
|
+
<pre><code>dependency "scottmotte-merb_auth_slice_multisite", :require_as => 'merb_auth_slice_multisite'</code></pre>
|
16
|
+
|
17
|
+
3. Remove default merb-auth-slice-password in dependencies.rb
|
18
|
+
<pre></code><strike>dependency "merb-auth-slice-password"</strike></code></pre>
|
19
|
+
(merb_auth_slice_multisite is now standalone. it does not depend on merb-auth-slice-password)
|
20
|
+
|
21
|
+
4. Add in mixin. In your user model or in merb/merb-auth/setup.rb add the mixin
|
22
|
+
include Merb::Authentication::Mixins::UserBelongsToSite and then migrate your database.
|
23
|
+
<pre><code>
|
24
|
+
# in model
|
25
|
+
class User
|
26
|
+
include Merb::Authentication::Mixins::UserBelongsToSite
|
27
|
+
include Merb::Authentication::Mixins::AuthenticatedUser #for remember me functionality
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
# or as I prefer in merb/merb-auth/setup.rb
|
32
|
+
Merb::Authentication.user_class.class_eval{
|
33
|
+
include Merb::Authentication::Mixins::SaltedUser
|
34
|
+
include Merb::Authentication::Mixins::ActivatedUser
|
35
|
+
include Merb::Authentication::Mixins::UserBelongsToSite # <-- this one
|
36
|
+
include Merb::Authentication::Mixins::AuthenticatedUser # <-- and this one
|
37
|
+
}
|
38
|
+
</code></pre>
|
39
|
+
|
40
|
+
_Don't forget to migrate your database schema with rake db:autoupgrade or rake db:automigrate_
|
41
|
+
|
42
|
+
5. Setup strategies.rb - make sure it looks like the following. merb_auth_slice_multisite uses its own custom strategy so including the others will mess things up.
|
43
|
+
<pre><code>Merb::Slices::config[:"merb_auth_slice_multisite"][:no_default_strategies] = false</code></pre>
|
44
|
+
|
45
|
+
As an aside, here's what an example router might look like using the slice to support subdomains. See how it checks for subdomain equaling www or nil and routes to the main site. And then everything else goes to the pages controller or users controller that has a subdomain. All of the controller actions then user @current_site.pages.all and @current_site.users.all instead of just User.all & Page.all. Starting to come together in your mind :)
|
46
|
+
|
47
|
+
<pre><code>
|
48
|
+
Merb.logger.info("Compiling routes...")
|
49
|
+
Merb::Router.prepare do
|
50
|
+
|
51
|
+
# Brochure site - equal to site_url from settings.yml and has no first_subdomain else do below
|
52
|
+
match(:first_subdomain => /^(www)*$/) do
|
53
|
+
resources :sites, :collection => { :changed_on_spreedly => :post }
|
54
|
+
resources :static
|
55
|
+
match('/signup').to(:controller => 'sites', :action => 'new')
|
56
|
+
match('/').to(:controller => 'static', :action => 'index')
|
57
|
+
end
|
58
|
+
|
59
|
+
# Subdomain sites
|
60
|
+
resources :pages
|
61
|
+
resources :users, :identify => :login
|
62
|
+
|
63
|
+
match('/').to(:controller => 'pages', :action => 'index')
|
64
|
+
slice(:merb_auth_slice_multisite, :name_prefix => nil, :path_prefix => "") # /login, /logout
|
65
|
+
end
|
66
|
+
</pre></code>
|
67
|
+
|
68
|
+
6. Add the slice's routes to your router
|
69
|
+
<pre><code>slice(:merb_auth_slice_multisite, :name_prefix => nil, :path_prefix => "")</code></pre>
|
70
|
+
|
71
|
+
7. Setup @current_site value. I haven't worked out how to make it automatically accessible yet so for now paste the following into your app's application.rb file.
|
72
|
+
<pre><code>
|
73
|
+
before :get_site
|
74
|
+
def get_site
|
75
|
+
# uses @current_site - for example, to create pages under current site do @current_site.pages.new
|
76
|
+
@current_site = Site.first(:subdomain => request.first_subdomain)
|
77
|
+
raise NotFound unless @current_site
|
78
|
+
end
|
79
|
+
</code></pre>
|
80
|
+
|
81
|
+
8. Configure forgot_password functionality. Add the following into merb/merb-auth/setup.rb
|
82
|
+
<pre><code># To change the parameter names for the password or login field you may set either of these two options
|
83
|
+
#
|
84
|
+
# Merb::Plugins.config[:"merb-auth"][:login_param] = :email
|
85
|
+
# Merb::Plugins.config[:"merb-auth"][:password_param] = :my_password_field_name
|
86
|
+
Merb::Slices::config[:merb_auth_slice_multisite][:send_password_from_email] = "no-reply@yourapp.com"
|
87
|
+
Merb::Slices::config[:merb_auth_slice_multisite][:domain] = "example.com"</code></pre>
|
88
|
+
|
89
|
+
|
90
|
+
h2. Additional details:
|
91
|
+
|
92
|
+
Schema/Migrations. The mixin adds some fields to your user model. Where needed include these in your migrations if you are using migrations.
|
93
|
+
<pre><code># Relationships/Associations
|
94
|
+
belongs_to :site
|
95
|
+
property :site_id, Integer
|
96
|
+
validates_is_unique :login, :scope => :site_id
|
97
|
+
validates_is_unique :email, :scope => :site_id
|
98
|
+
</code></pre>
|
99
|
+
|
100
|
+
Site model. You're probably wondering where the heck is the site model. It's in the slice. You can override it by running one of the rake tasks or you can create your own site.rb model and add additional fields which is what I do. For example, if you have pages under a site, you might do something like:
|
101
|
+
<pre><code># site.rb
|
102
|
+
class Site
|
103
|
+
has n, :pages, :order => [:position.asc]
|
104
|
+
end
|
105
|
+
</code></pre>
|
106
|
+
|
107
|
+
@current_site. You can use @current_site in your controllers like so:
|
108
|
+
<pre><code>
|
109
|
+
class Pages < Application
|
110
|
+
# provides :xml, :yaml, :js
|
111
|
+
|
112
|
+
def index
|
113
|
+
@pages = @current_site.pages.all
|
114
|
+
display @pages
|
115
|
+
end
|
116
|
+
|
117
|
+
def show(id)
|
118
|
+
@page = @current_site.pages.get(id)
|
119
|
+
raise NotFound unless @page
|
120
|
+
display @page
|
121
|
+
end
|
122
|
+
|
123
|
+
end # Pages
|
124
|
+
</pre></code>
|
125
|
+
|
126
|
+
|
127
|
+
h2. Assumptions
|
128
|
+
|
129
|
+
* works for subdomains (i.e. coolcars.yourapp.com)
|
130
|
+
* merb only
|
131
|
+
* merb-auth-core dependency
|
132
|
+
* merb-auth-more dependency
|
133
|
+
* *only supports datamapper so far* (help me extend it! fork the project and request me to pull)
|
134
|
+
* A site has n (has_many) users. A user belongs_to a site.
|
135
|
+
* You can have multiple users with the same username and password as long as they each belong_to a different site. For example, there can be an admin user with the credentials { :login => 'admin', :email => 'admin@example.org', :site_id => 1} and an admin user with the credentials { :login => 'admin', :email => 'admin@example.org', :site_id => 66}. As long as the site_id is different then it is ok. This allows more freedom when your users want to setup multiple sites.
|
136
|
+
|
137
|
+
|
138
|
+
h2. How does it work?
|
139
|
+
|
140
|
+
When logging in the "user" object found by merb-auth-core will be asked whether the user's login, password, and site_id match. It matches the site_id against the @current_site.id, and the login/password from the standard form fields.
|
141
|
+
|
142
|
+
|
143
|
+
h2. Rake tasks
|
144
|
+
|
145
|
+
To see all available tasks for MerbAuthSliceMultisite run:
|
146
|
+
|
147
|
+
rake -T slices:merb_auth_slice_multisite
|
data/VERSION.yml
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# the mixin to provide the exceptions controller action for Unauthenticated
|
2
|
+
module MerbAuthSliceMultisite::ExceptionsMixin
|
3
|
+
def unauthenticated
|
4
|
+
provides :xml, :js, :json, :yaml
|
5
|
+
|
6
|
+
case content_type
|
7
|
+
when :html
|
8
|
+
render
|
9
|
+
else
|
10
|
+
basic_authentication.request!
|
11
|
+
""
|
12
|
+
end
|
13
|
+
end # unauthenticated
|
14
|
+
end
|
15
|
+
|
16
|
+
Merb::Authentication.customize_default do
|
17
|
+
|
18
|
+
Exceptions.class_eval do
|
19
|
+
include Merb::Slices::Support # Required to provide slice_url
|
20
|
+
|
21
|
+
# # This stuff allows us to provide a default view
|
22
|
+
the_view_path = File.expand_path(File.dirname(__FILE__) / ".." / "views")
|
23
|
+
self._template_roots ||= []
|
24
|
+
self._template_roots << [the_view_path, :_template_location]
|
25
|
+
self._template_roots << [Merb.dir_for(:view), :_template_location]
|
26
|
+
|
27
|
+
include MerbAuthSliceMultisite::ExceptionsMixin
|
28
|
+
|
29
|
+
show_action :unauthenticated
|
30
|
+
|
31
|
+
end# Exceptions.class_eval
|
32
|
+
|
33
|
+
end # Customize default
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class MerbAuthSliceMultisite::Passwords < MerbAuthSliceMultisite::Application
|
2
|
+
|
3
|
+
def send_password
|
4
|
+
@login_param = Merb::Authentication::Strategies::Multisite::Base.login_param
|
5
|
+
@site_id_param = Merb::Authentication::Strategies::Multisite::Base.site_id_param
|
6
|
+
@user = Merb::Authentication.user_class.first(@login_param => params[@login_param], @site_id_param => params[@site_id_param])
|
7
|
+
|
8
|
+
if @user
|
9
|
+
from = MerbAuthSliceMultisite[:send_password_from_email]
|
10
|
+
raise "No :send_password_from_email option set for Merb::Slices::config[:merb_auth_slice_multisite][:send_password_from_email]" unless from
|
11
|
+
@user.password = @user.password_confirmation = new_generated_password
|
12
|
+
send_mail(MerbAuthSliceMultisite::SendPasswordMailer, :send_password, { :subject => (MerbAuthSliceMultisite[:send_password_subject] || "Forgetful? :)"), :from => from, :to => @user.email }, { :user => @user })
|
13
|
+
@user.save
|
14
|
+
redirect "/", :message => {:notice => "Password sent. Check your email."}
|
15
|
+
else
|
16
|
+
redirect "/", :message => {:error => "User with #{@login_param} \"%s\" not found".t(params[@login_param].freeze)}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def new_generated_password
|
23
|
+
chars = ("a".."z").to_a
|
24
|
+
start_password = ""
|
25
|
+
1.upto(6) { |i| start_password << chars[rand(chars.size-1)] }
|
26
|
+
@password = start_password
|
27
|
+
end
|
28
|
+
|
29
|
+
end # MerbAuthSliceMultisite::Passwords
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class MerbAuthSliceMultisite::Sessions < MerbAuthSliceMultisite::Application
|
2
|
+
|
3
|
+
before :_maintain_auth_session_before, :exclude => [:destroy] # Need to hang onto the redirection during the session.abandon!
|
4
|
+
before :_abandon_session, :only => [:update, :destroy]
|
5
|
+
before :_maintain_auth_session_after, :exclude => [:destroy] # Need to hang onto the redirection during the session.abandon!
|
6
|
+
before :ensure_authenticated, :only => [:update]
|
7
|
+
|
8
|
+
# redirect from an after filter for max flexibility
|
9
|
+
# We can then put it into a slice and ppl can easily
|
10
|
+
# customize the action
|
11
|
+
after :redirect_after_login, :only => :update, :if => lambda{ !(300..399).include?(status) }
|
12
|
+
after :redirect_after_logout, :only => :destroy
|
13
|
+
|
14
|
+
def update
|
15
|
+
"Add an after filter to do stuff after login"
|
16
|
+
end
|
17
|
+
|
18
|
+
def destroy
|
19
|
+
"Add an after filter to do stuff after logout"
|
20
|
+
cookies.delete :auth_token
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
private
|
25
|
+
# @overwritable
|
26
|
+
def redirect_after_login
|
27
|
+
message[:notice] = "Authenticated Successfully"
|
28
|
+
redirect_back_or "/", :message => message, :ignore => [slice_url(:login), slice_url(:logout)]
|
29
|
+
end
|
30
|
+
|
31
|
+
# @overwritable
|
32
|
+
def redirect_after_logout
|
33
|
+
message[:notice] = "Logged Out"
|
34
|
+
redirect "/", :message => message
|
35
|
+
end
|
36
|
+
|
37
|
+
# @private
|
38
|
+
def _maintain_auth_session_before
|
39
|
+
@_maintain_auth_session = {}
|
40
|
+
Merb::Authentication.maintain_session_keys.each do |k|
|
41
|
+
@_maintain_auth_session[k] = session[k]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# @private
|
46
|
+
def _maintain_auth_session_after
|
47
|
+
@_maintain_auth_session.each do |k,v|
|
48
|
+
session[k] = v
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# @private
|
53
|
+
def _abandon_session
|
54
|
+
session.abandon!
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Merb
|
2
|
+
module MerbAuthSliceMultisite
|
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
|
+
::MerbAuthSliceMultisite.public_path_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
|
+
::MerbAuthSliceMultisite.app_path_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
|
+
::MerbAuthSliceMultisite.slice_path_for(type, *segments)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class MerbAuthSliceMultisite::SendPasswordMailer < Merb::MailController
|
2
|
+
|
3
|
+
controller_for_slice MerbAuthSliceMultisite, :templates_for => :mailer, :path => "views"
|
4
|
+
|
5
|
+
def send_password
|
6
|
+
@user = params[:user]
|
7
|
+
Merb.logger.info "Sending Password to #{@user.email}"
|
8
|
+
render_mail :layout => nil
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
data/app/models/site.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
class Site
|
2
|
+
include DataMapper::Resource
|
3
|
+
include DataMapper::Timestamp
|
4
|
+
|
5
|
+
# Schema
|
6
|
+
property :id, Serial
|
7
|
+
property :subdomain, String, :nullable => false, :length => (1..40), :unique => true, :format => /^[a-zA-Z0-9\-]*?$/
|
8
|
+
property :created_at, DateTime
|
9
|
+
property :updated_at, DateTime
|
10
|
+
|
11
|
+
# Relationships/Associates
|
12
|
+
has n, :users, :order => [:login.asc]
|
13
|
+
|
14
|
+
# Validations
|
15
|
+
validates_with_method :check_subdomain
|
16
|
+
|
17
|
+
ReservedSubdomains = %w[backstage admin blog dev ftp mail email pop pop3 imap smtp stage stats status www]
|
18
|
+
def check_subdomain
|
19
|
+
if ReservedSubdomains.include?(self.subdomain)
|
20
|
+
[false, "Subdomain '#{self.subdomain}' is reserved."]
|
21
|
+
else
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
<% @login_param = Merb::Authentication::Strategies::Multisite::Base.login_param %>
|
2
|
+
<% @password_param = Merb::Authentication::Strategies::Multisite::Base.password_param %>
|
3
|
+
<% @site_id_param = Merb::Authentication::Strategies::Multisite::Base.site_id_param %>
|
4
|
+
<%
|
5
|
+
# make @current_site value. application.rb does not get call
|
6
|
+
# because the authentication is protected at the rack level - which is better,
|
7
|
+
# but it means I have to add the following duplicate line of code as far as I know.
|
8
|
+
@current_site = Site.first(:subdomain => request.first_subdomain)
|
9
|
+
%>
|
10
|
+
|
11
|
+
<%= error_messages_for session.authentication %>
|
12
|
+
<form action="<%= slice_url(:merb_auth_slice_multisite, :perform_login) %>" method="post" id="loginForm">
|
13
|
+
<h3>Login</h3>
|
14
|
+
<input type="hidden" name="<%= @site_id_param.to_s %>" value="<%= @current_site.id %>" id="<%= @site_id_param.to_s %>">
|
15
|
+
<input type="hidden" name="_method" value="PUT" />
|
16
|
+
|
17
|
+
<div id="loginFields" class="fields">
|
18
|
+
<div id="loginElements" class="elements">
|
19
|
+
<label for="<%= @login_param.to_s %>"><%= @login_param.to_s.capitalize %>:</label>
|
20
|
+
<div id="loginElement" class="element">
|
21
|
+
<input type="text" name="<%= @login_param.to_s %>" value="" id="<%= @login_param.to_s %>">
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
<div id="passwordElements" class="elements">
|
25
|
+
<label for="<%= @password_param.to_s %>"><%= @password_param.to_s.capitalize %>:</label>
|
26
|
+
<div id="passwordElement" class="element">
|
27
|
+
<input type="password" name="<%= @password_param.to_s %>" value="" id="<%= @password_param.to_s %>">
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
<div id="remember_meElements" class="elements">
|
31
|
+
<div id="remember_meElement" class="element">
|
32
|
+
<input type="checkbox" name="remember_me" value="1" id="remember_me" /> <label for="remember_me">Remember me</label>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
<div id="loginActions" class="actions">
|
36
|
+
<div id="loginAction" class="action">
|
37
|
+
<input type="submit" name="loginSubmit" value="Log In" id="loginSubmit" />
|
38
|
+
</div>
|
39
|
+
<div id="forgotToggleAction" class="action">
|
40
|
+
<a href="#" id="forgotToggle">Forgot password</a>
|
41
|
+
</div>
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
</form>
|
45
|
+
|
46
|
+
<form action="<%= slice_url(:merb_auth_slice_multisite, :send_password) %>" method="post" id="forgotForm">
|
47
|
+
<input type="hidden" name="<%= @site_id_param.to_s %>" value="<%= @current_site.id %>" id="<%= @site_id_param.to_s %>">
|
48
|
+
<div id="forgotFields" class="fields">
|
49
|
+
<div id="forgotLoginElements" class="elements">
|
50
|
+
<label for="<%= @login_param.to_s %>"><%= @login_param.to_s.capitalize %>:</label>
|
51
|
+
<div id="forgotLoginElement" class="element">
|
52
|
+
<input type="text" class="text" name="<%= @login_param.to_s %>" id="<%= @login_param.to_s %>" />
|
53
|
+
</div>
|
54
|
+
</div>
|
55
|
+
<div id="forgotLoginActions" class="actions">
|
56
|
+
<div id="forgotLoginAction" class="action">
|
57
|
+
<input type="submit" name="forgotLoginSubmit" value="Reset Password" id="forgotLoginSubmit" />
|
58
|
+
</div>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
</form>
|