protected 1.0.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/MIT-LICENSE +20 -0
- data/README.rdoc +151 -0
- data/Rakefile +32 -0
- data/app/assets/images/protected/Sorting icons.psd +0 -0
- data/app/assets/images/protected/back_disabled.png +0 -0
- data/app/assets/images/protected/back_enabled.png +0 -0
- data/app/assets/images/protected/back_enabled_hover.png +0 -0
- data/app/assets/images/protected/favicon.ico +0 -0
- data/app/assets/images/protected/forward_disabled.png +0 -0
- data/app/assets/images/protected/forward_enabled.png +0 -0
- data/app/assets/images/protected/forward_enabled_hover.png +0 -0
- data/app/assets/images/protected/glyphicons-halflings-white.png +0 -0
- data/app/assets/images/protected/glyphicons-halflings.png +0 -0
- data/app/assets/images/protected/sort_asc.png +0 -0
- data/app/assets/images/protected/sort_asc_disabled.png +0 -0
- data/app/assets/images/protected/sort_both.png +0 -0
- data/app/assets/images/protected/sort_desc.png +0 -0
- data/app/assets/images/protected/sort_desc_disabled.png +0 -0
- data/app/assets/javascripts/protected/application.js +164 -0
- data/app/assets/javascripts/protected/bootstrap.min.js +6 -0
- data/app/assets/javascripts/protected/jquery.dataTables.min.js +154 -0
- data/app/assets/stylesheets/protected/application.css +51 -0
- data/app/assets/stylesheets/protected/bootstrap-responsive.min.css +12 -0
- data/app/assets/stylesheets/protected/bootstrap.min.css +689 -0
- data/app/controllers/protected/admin/protected_controller.rb +14 -0
- data/app/controllers/protected/admin/users_controller.rb +70 -0
- data/app/controllers/protected/application_controller.rb +18 -0
- data/app/controllers/protected/passwords_controller.rb +39 -0
- data/app/controllers/protected/sessions_controller.rb +44 -0
- data/app/controllers/protected/users_controller.rb +12 -0
- data/app/helpers/protected/application_helper.rb +4 -0
- data/app/helpers/protected/passwords_helper.rb +21 -0
- data/app/mailers/user_mailer.rb +9 -0
- data/app/models/protected.rb +5 -0
- data/app/models/protected/old_password.rb +18 -0
- data/app/models/protected/user.rb +165 -0
- data/app/views/layouts/protected/application.html.haml +38 -0
- data/app/views/protected/admin/users/_form.html.haml +27 -0
- data/app/views/protected/admin/users/_password_fields.html.haml +9 -0
- data/app/views/protected/admin/users/_role_fields.html.haml +10 -0
- data/app/views/protected/admin/users/confirm_delete.html.haml +9 -0
- data/app/views/protected/admin/users/edit.html.haml +9 -0
- data/app/views/protected/admin/users/index.html.haml +27 -0
- data/app/views/protected/admin/users/new.html.haml +9 -0
- data/app/views/protected/admin/users/show.html.haml +0 -0
- data/app/views/protected/passwords/edit.html.haml +28 -0
- data/app/views/protected/passwords/forgot_password.html.haml +20 -0
- data/app/views/protected/passwords/new.html.haml +22 -0
- data/app/views/protected/sessions/first_login.html.haml +25 -0
- data/app/views/protected/sessions/new.html.haml +22 -0
- data/app/views/protected/sessions/not_authorized.html.haml +9 -0
- data/app/views/protected/users/_form.html.haml +19 -0
- data/app/views/protected/users/edit.html.haml +19 -0
- data/app/views/user_mailer/welcome_existing_user.haml +5 -0
- data/app/views/user_mailer/welcome_login_instructions.html.haml +6 -0
- data/app/views/user_mailer/welcome_password_instructions.haml +7 -0
- data/config/initializers/devise.rb +220 -0
- data/config/locales/devise.en.yml +62 -0
- data/config/routes.rb +34 -0
- data/db/migrate/20120418194256_devise_create_add_users.rb +60 -0
- data/lib/generators/protected/USAGE +5 -0
- data/lib/generators/protected/install/install_generator.rb +26 -0
- data/lib/generators/protected/templates/README +32 -0
- data/lib/generators/protected/templates/devise.rb +233 -0
- data/lib/generators/protected/views/views_generator.rb +40 -0
- data/lib/protected.rb +4 -0
- data/lib/protected/devise_recoverable_extensions.rb +19 -0
- data/lib/protected/engine.rb +10 -0
- data/lib/protected/password_utils.rb +46 -0
- data/lib/protected/version.rb +3 -0
- data/lib/tasks/protected_tasks.rake +44 -0
- metadata +414 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Protected
|
|
2
|
+
module Admin
|
|
3
|
+
class UsersController < ProtectedController
|
|
4
|
+
before_filter :find_user, :except => [:index, :new, :create, :new_search, :search]
|
|
5
|
+
def index
|
|
6
|
+
@users = User.paginate(pagination_params)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def new
|
|
10
|
+
@user = User.new
|
|
11
|
+
@user.is_admin = false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def update
|
|
15
|
+
@user.is_admin = params[:user][:is_admin] unless current_user == @user
|
|
16
|
+
params[:user].delete(:is_admin)
|
|
17
|
+
if @user.update_without_password(params[:user])
|
|
18
|
+
flash[:success] = "User #{@user.name} updated successfully."
|
|
19
|
+
redirect_to admin_users_url
|
|
20
|
+
else
|
|
21
|
+
render :action => 'edit'
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def destroy
|
|
26
|
+
unless @user == current_user
|
|
27
|
+
@user.destroy
|
|
28
|
+
flash[:success] = "The user was deleted"
|
|
29
|
+
redirect_to ['admin','users']
|
|
30
|
+
else
|
|
31
|
+
flash[:error] = "The user could not be deleted"
|
|
32
|
+
redirect_to ['admin',@user]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def create
|
|
37
|
+
@user = User.new
|
|
38
|
+
if params[:user].present?
|
|
39
|
+
@user.is_admin = params[:user][:is_admin]
|
|
40
|
+
params[:user].delete(:is_admin)
|
|
41
|
+
end
|
|
42
|
+
@user.attributes = params[:user]
|
|
43
|
+
@user.random_password
|
|
44
|
+
if @user.save
|
|
45
|
+
flash[:success] = "User #{@user.name} created successfully."
|
|
46
|
+
redirect_to ['admin','users']
|
|
47
|
+
else
|
|
48
|
+
render :action => :new
|
|
49
|
+
end
|
|
50
|
+
rescue Errno::ETIMEDOUT
|
|
51
|
+
@user.errors.add(:base, I18n.t('devise.failure.user.service_error'))
|
|
52
|
+
render :action => :new
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def unlock
|
|
56
|
+
@user.unlock_access!
|
|
57
|
+
flash[:success] = "User's account has been unlocked"
|
|
58
|
+
redirect_to admin_users_url
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
protected
|
|
62
|
+
def find_user
|
|
63
|
+
@user = User.find(params[:id])
|
|
64
|
+
rescue ActiveRecord::RecordNotFound => e
|
|
65
|
+
flash[:error] = e.message
|
|
66
|
+
redirect_to ['admin','users']
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Protected
|
|
2
|
+
class ApplicationController < ActionController::Base
|
|
3
|
+
before_filter :authenticate_user!
|
|
4
|
+
before_filter :set_cache_buster
|
|
5
|
+
|
|
6
|
+
protect_from_forgery
|
|
7
|
+
|
|
8
|
+
def pagination_params(opts = {})
|
|
9
|
+
{ :page => params[:page].present? ? params[:page].to_i : 1, :per_page => params[:per_page].present? ? params[:per_page].to_i : 12 }.merge(opts)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def set_cache_buster
|
|
13
|
+
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
|
|
14
|
+
response.headers["Pragma"] = "no-cache"
|
|
15
|
+
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Protected
|
|
2
|
+
class PasswordsController < Devise::PasswordsController
|
|
3
|
+
def update
|
|
4
|
+
self.resource = resource_class.reset_password_by_token(params[resource_name])
|
|
5
|
+
if resource.errors.empty?
|
|
6
|
+
flash[:notice] = "Your password has been changed, please log in again."
|
|
7
|
+
sign_out_all_scopes
|
|
8
|
+
redirect_to new_user_session_url and return false
|
|
9
|
+
end
|
|
10
|
+
render :template => 'protected/passwords/edit.html.haml'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def new
|
|
14
|
+
build_resource({})
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def edit
|
|
18
|
+
unless params[:reset_password_token].present?
|
|
19
|
+
flash[:notice] = "A valid password token was not found"
|
|
20
|
+
redirect_to root_url and return false
|
|
21
|
+
else
|
|
22
|
+
self.resource = resource_class.new
|
|
23
|
+
resource.reset_password_token = params[:reset_password_token]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def create
|
|
28
|
+
|
|
29
|
+
# Refactor Me:
|
|
30
|
+
# This currently redireccts the user to a success message regardless if the email is in the database or not.
|
|
31
|
+
# This is done to prevent others from determining what emails are "good" within the system but may confuse
|
|
32
|
+
# a user who tries to reset their password but uses an incorrect address. Because they know they have an
|
|
33
|
+
# account and received a success message they will infer the application is broken when no email arrives.
|
|
34
|
+
self.resource = resource_class.reset_password_and_send_password_instructions(params[resource_name])
|
|
35
|
+
flash[:notice] = "Instructions on how to reset your password have been sent to #{resource.email}."
|
|
36
|
+
redirect_to new_user_session_url
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Protected
|
|
2
|
+
class SessionsController < Devise::SessionsController
|
|
3
|
+
before_filter :first_login?, :except => [:destroy, :first_login, :update_first_login]
|
|
4
|
+
skip_before_filter :authenticate_user!, :only => [:not_authorized, :new, :create]
|
|
5
|
+
|
|
6
|
+
helper 'protected/application'
|
|
7
|
+
|
|
8
|
+
def first_login
|
|
9
|
+
redirect_to root_url unless current_user
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def update_first_login
|
|
13
|
+
current_user.update_on_first_login!(params[:user])
|
|
14
|
+
if current_user.errors.any?
|
|
15
|
+
render :action => :first_login
|
|
16
|
+
else
|
|
17
|
+
sign_out_all_scopes
|
|
18
|
+
flash[:notice] = "Your password has been changed, please log in again."
|
|
19
|
+
redirect_to new_user_session_url
|
|
20
|
+
end
|
|
21
|
+
rescue PasswordAlreadyUsedException => e
|
|
22
|
+
current_user.errors.add(:password, e.message)
|
|
23
|
+
render :action => :first_login
|
|
24
|
+
rescue ActiveRecord::RecordInvalid => f
|
|
25
|
+
render :action => :first_login
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
protected
|
|
29
|
+
def first_login?
|
|
30
|
+
if current_user.present? && (current_user.first_login? || params[:wants_first_login] == '1')
|
|
31
|
+
params.delete(:wants_first_login)
|
|
32
|
+
redirect_to first_login_url and return true
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def after_sign_in_path_for(resource_or_scope)
|
|
37
|
+
if(current_user.is_admin?)
|
|
38
|
+
admin_users_url
|
|
39
|
+
else
|
|
40
|
+
stored_location_for(resource_or_scope) || signed_in_root_path(resource_or_scope)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Protected
|
|
2
|
+
class UsersController < ApplicationController
|
|
3
|
+
def update
|
|
4
|
+
if current_user.update_without_password(params[:user])
|
|
5
|
+
flash[:success] = "Your changes have been saved."
|
|
6
|
+
redirect_to current_user
|
|
7
|
+
else
|
|
8
|
+
render :action => :edit
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Protected
|
|
2
|
+
module PasswordsHelper
|
|
3
|
+
MESSAGES = {'match confirmation' => "Passwords should match confirmation",
|
|
4
|
+
'8 characters long' => "Password should be at least 8 characters long",
|
|
5
|
+
'special character' => "Password should have at least 1 digit, 1 capital letter and 1 special character \(\!\@\#\$\%\^\&\*\(\)\_\-\=\+\)",
|
|
6
|
+
'previous five passwords' => "You can not use previous five passwords",
|
|
7
|
+
'password token' => "You must have a valid reset password token" }
|
|
8
|
+
|
|
9
|
+
def password_instructions(messages)
|
|
10
|
+
section = ""
|
|
11
|
+
MESSAGES.each do |error, message|
|
|
12
|
+
section << "<div class=\"alert-message #{ message_class(messages, error) }\">#{message}</div>"
|
|
13
|
+
end
|
|
14
|
+
section.html_safe
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def message_class(messages, error)
|
|
18
|
+
messages.include?(error) ? "block-message error" : ""
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# == Schema Information
|
|
2
|
+
#
|
|
3
|
+
# Table name: old_passwords
|
|
4
|
+
#
|
|
5
|
+
# id :integer(4) not null, primary key
|
|
6
|
+
# encrypted_password :string(128) not null
|
|
7
|
+
# password_salt :string(255)
|
|
8
|
+
# password_archivable_id :integer(4) not null
|
|
9
|
+
# password_archivable_type :string(255) not null
|
|
10
|
+
# created_at :datetime
|
|
11
|
+
#
|
|
12
|
+
module Protected
|
|
13
|
+
class OldPassword < ActiveRecord::Base
|
|
14
|
+
belongs_to :password_archivable, :polymorphic => true
|
|
15
|
+
|
|
16
|
+
attr_accessible :encrypted_password, :password_salt, :password_archivable, :password_archivable_type, :password_archivable_id
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
|
|
2
|
+
# == Schema Information
|
|
3
|
+
#
|
|
4
|
+
# Table name: users
|
|
5
|
+
#
|
|
6
|
+
# id :integer(4) not null, primary key
|
|
7
|
+
# first_name :string(255)
|
|
8
|
+
# last_name :string(255)
|
|
9
|
+
# company :string(255)
|
|
10
|
+
# password_salt :string(255) default(""), not null
|
|
11
|
+
# remember_token :string(255)
|
|
12
|
+
# first_login :boolean(1) default(TRUE)
|
|
13
|
+
# is_admin :boolean(1)
|
|
14
|
+
# created_at :datetime
|
|
15
|
+
# updated_at :datetime
|
|
16
|
+
# email :string(255) default(""), not null
|
|
17
|
+
# encrypted_password :string(128) default(""), not null
|
|
18
|
+
# reset_password_token :string(255)
|
|
19
|
+
# reset_password_sent_at :datetime
|
|
20
|
+
# remember_created_at :datetime
|
|
21
|
+
# sign_in_count :integer(4) default(0)
|
|
22
|
+
# current_sign_in_at :datetime
|
|
23
|
+
# last_sign_in_at :datetime
|
|
24
|
+
# current_sign_in_ip :string(255)
|
|
25
|
+
# last_sign_in_ip :string(255)
|
|
26
|
+
# failed_attempts :integer(4) default(0)
|
|
27
|
+
# unlock_token :string(255)
|
|
28
|
+
# locked_at :datetime
|
|
29
|
+
# login :string(255)
|
|
30
|
+
#
|
|
31
|
+
class LoginFormatValidator < ActiveModel::EachValidator
|
|
32
|
+
def validate_each(object, attribute, value)
|
|
33
|
+
if value.present?
|
|
34
|
+
unless value.gsub(" ",'') == value
|
|
35
|
+
object.errors[attribute] << (options[:message] || "cannot contain any whitespace")
|
|
36
|
+
end
|
|
37
|
+
if [value[0], value[-1]].any?{ |x| x == "." }
|
|
38
|
+
object.errors[attribute] << (options[:message] || "cannot contain a period at the start or end")
|
|
39
|
+
end
|
|
40
|
+
unless value =~ /[a-zA-Z]/
|
|
41
|
+
object.errors[attribute] << (options[:message] || "must contain at least one letter")
|
|
42
|
+
end
|
|
43
|
+
unless value =~ /[0-9]/
|
|
44
|
+
object.errors[attribute] << (options[:message] || "must contain at least one number")
|
|
45
|
+
end
|
|
46
|
+
unless value =~ /[_\-.]/
|
|
47
|
+
object.errors[attribute] << (options[:message] || "must contain at least one these special characters \"-_.\"")
|
|
48
|
+
end
|
|
49
|
+
unless value =~ /^[a-zA-Z0-9_\-.]+$/
|
|
50
|
+
object.errors[attribute] << (options[:message] || "can only contain letters number and special characters \"-_.\"")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class UnchangeableValidator < ActiveModel::EachValidator
|
|
57
|
+
def validate_each(object, attribute, value)
|
|
58
|
+
if !object.new_record? && value.present?
|
|
59
|
+
original = object.class.send(:where, "id = #{object.id}").select("id, #{attribute.to_s}").first
|
|
60
|
+
if original.send(attribute) != value
|
|
61
|
+
object.errors[attribute] << (options[:message] || "cannot be changed once assigned")
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
module Protected
|
|
68
|
+
require File.dirname(__FILE__) + '/../../../lib/protected/devise_recoverable_extensions'
|
|
69
|
+
require File.dirname(__FILE__) + '/../../../lib/protected/password_utils'
|
|
70
|
+
|
|
71
|
+
class User < ActiveRecord::Base
|
|
72
|
+
# devise :database_authenticatable, :recoverable, :trackable, :validatable, :lockable, :timeoutable, :password_archivable,
|
|
73
|
+
# :maximum_attempts => 4, :unlock_strategy => :none
|
|
74
|
+
devise :database_authenticatable, :recoverable, :trackable, :validatable, :lockable, :timeoutable,
|
|
75
|
+
:maximum_attempts => 4, :unlock_strategy => :none
|
|
76
|
+
|
|
77
|
+
has_many :old_passwords, :as => :password_archivable, :dependent => :destroy
|
|
78
|
+
|
|
79
|
+
validates :first_name, :presence => true, :format => { :with => /^[a-zA-Z0-9_\s\-.]+$/ }
|
|
80
|
+
validates :last_name, :presence => true, :format => { :with => /^[a-zA-Z0-9_\s\-.]+$/ }, :uniqueness => { :scope => :first_name, :message => "has alredy been taken by another user with the same first name" }
|
|
81
|
+
validate :validate_password_strength, :if => lambda{new_record? || (not password.blank?)}
|
|
82
|
+
validates :login, :unchangeable => true, :presence => true, :login_format => true, :uniqueness => { :case_sensitive => false }, :length => { :maximum => 64, :minimum => 6 }
|
|
83
|
+
validates :email, :unchangeable => true
|
|
84
|
+
|
|
85
|
+
# Setup accessible (or protected) attributes for your model
|
|
86
|
+
attr_accessible :login, :email, :password, :password_confirmation, :remember_me, :first_name, :last_name, :company, :locked_at, :failed_attempts, :first_login, :current_password
|
|
87
|
+
attr_accessor :current_password
|
|
88
|
+
|
|
89
|
+
after_save :send_mail_if_needed
|
|
90
|
+
|
|
91
|
+
# TODO: Extract this code into security pack extension
|
|
92
|
+
def archive_password
|
|
93
|
+
if(self.encrypted_password_changed?)
|
|
94
|
+
self.old_passwords.create! :encrypted_password => self.encrypted_password, :password_salt => self.password_salt, :password_archivable_id => self.id, :password_archivable_type => self.class.to_s
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def update_on_first_login!(modified_user)
|
|
99
|
+
if password_used?(modified_user[:password])
|
|
100
|
+
raise PasswordAlreadyUsedException
|
|
101
|
+
else
|
|
102
|
+
update_attributes!(
|
|
103
|
+
:password => modified_user[:password],
|
|
104
|
+
:password_confirmation => modified_user[:password_confirmation],
|
|
105
|
+
:first_login => false)
|
|
106
|
+
archive_password
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def name
|
|
111
|
+
[first_name, last_name].join(' ')
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def password_used?(password)
|
|
115
|
+
self.password = password
|
|
116
|
+
return password_archive_included?
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def reset_password!(pass,conf)
|
|
120
|
+
if reset_password_token.present? and
|
|
121
|
+
pass == conf and
|
|
122
|
+
encrypted_password_changed? and
|
|
123
|
+
password_archive_included?
|
|
124
|
+
errors.add(:base, I18n.t('errors.messages.taken_in_past'))
|
|
125
|
+
else
|
|
126
|
+
super
|
|
127
|
+
end
|
|
128
|
+
self
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def random_password
|
|
132
|
+
self.password = self.password_confirmation = PasswordUtils.generate_random_password
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def send_mail_if_needed
|
|
136
|
+
if !self.changes.empty? &&
|
|
137
|
+
self.changes[:id].present? &&
|
|
138
|
+
self.changes[:id][0].nil? &&
|
|
139
|
+
self.changes[:id][1].present?
|
|
140
|
+
if self.first_login?
|
|
141
|
+
self.archive_password
|
|
142
|
+
UserMailer.welcome_login_instructions(self).deliver
|
|
143
|
+
UserMailer.welcome_password_instructions(self).deliver
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
class << self
|
|
149
|
+
def reset_password_and_send_password_instructions(params)
|
|
150
|
+
record = find_by_email(params["email"])
|
|
151
|
+
record.random_password && record.save unless record.nil?
|
|
152
|
+
send_reset_password_instructions(params)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# NOTE: To audit the devise actions we need to ensure we include this after devise has been added. This is a bug in the gem
|
|
157
|
+
# and should be fixed.
|
|
158
|
+
audit :methods => [:destroy, :unlock_access!], :attributes => [:first_name,:last_name, :company, :is_admin]
|
|
159
|
+
|
|
160
|
+
private
|
|
161
|
+
def validate_password_strength
|
|
162
|
+
errors.add(:password, I18n.t('devise.passwords.password_strength')) if not PasswordUtils.strong?(password)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
!!!
|
|
2
|
+
%html{:lang => "en"}
|
|
3
|
+
%head
|
|
4
|
+
%meta{:charset => "utf-8"}
|
|
5
|
+
%title
|
|
6
|
+
%meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"}
|
|
7
|
+
%meta{:content => "", :name => "description"}
|
|
8
|
+
%meta{:content => "", :name => "author"}
|
|
9
|
+
= stylesheet_link_tag "protected/application"
|
|
10
|
+
|
|
11
|
+
%body{ :class => "#{Rails.env} #{params[:controller]} #{params[:action]}" }
|
|
12
|
+
.navbar.navbar-fixed-top
|
|
13
|
+
.navbar-inner
|
|
14
|
+
.container-fluid
|
|
15
|
+
%a.btn.btn-navbar{"data-target" => ".nav-collapse", "data-toggle" => "collapse"}
|
|
16
|
+
%span.icon-bar
|
|
17
|
+
%span.icon-bar
|
|
18
|
+
%span.icon-bar
|
|
19
|
+
%a.brand{:href => "#"} Project name
|
|
20
|
+
.nav-collapse
|
|
21
|
+
- if current_user
|
|
22
|
+
%ul.nav
|
|
23
|
+
%li= link_to "Admin", admin_url
|
|
24
|
+
%li= link_to "Users", ['admin','users']
|
|
25
|
+
%li= link_to "Live Site", root_url
|
|
26
|
+
%ul.nav.right
|
|
27
|
+
%li= link_to "Account Settings", ['edit','admin',current_user]
|
|
28
|
+
%li= link_to 'Sign Out', destroy_user_session_url
|
|
29
|
+
|
|
30
|
+
.container-fluid
|
|
31
|
+
.row-fluid
|
|
32
|
+
- flash.each do |name, msg|
|
|
33
|
+
%div{:class => "alert alert-#{name == :notice ? "success" : "error"}"}
|
|
34
|
+
%a.close{"data-dismiss" => "alert"} ×
|
|
35
|
+
= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String)
|
|
36
|
+
= yield
|
|
37
|
+
|
|
38
|
+
= javascript_include_tag "protected/application"
|