refinerycms-authentication 0.9.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/app/controllers/admin/users_controller.rb +90 -0
  2. data/app/controllers/passwords_controller.rb +43 -0
  3. data/app/controllers/registrations_controller.rb +67 -0
  4. data/app/controllers/sessions_controller.rb +23 -0
  5. data/app/helpers/sessions_helper.rb +2 -0
  6. data/app/helpers/users_helper.rb +2 -0
  7. data/app/mailers/user_mailer.rb +20 -0
  8. data/app/models/role.rb +16 -0
  9. data/app/models/roles_users.rb +6 -0
  10. data/app/models/user.rb +60 -0
  11. data/app/models/user_plugin.rb +5 -0
  12. data/app/views/admin/users/_form.html.erb +92 -0
  13. data/app/views/admin/users/_user.html.erb +19 -0
  14. data/app/views/admin/users/_users.html.erb +4 -0
  15. data/app/views/admin/users/edit.html.erb +1 -0
  16. data/app/views/admin/users/index.html.erb +12 -0
  17. data/app/views/admin/users/new.html.erb +1 -0
  18. data/app/views/layouts/login.html.erb +21 -0
  19. data/app/views/passwords/edit.html.erb +31 -0
  20. data/app/views/passwords/new.html.erb +18 -0
  21. data/app/views/registrations/new.html.erb +41 -0
  22. data/app/views/sessions/new.html.erb +29 -0
  23. data/app/views/user_mailer/reset_notification.html.erb +12 -0
  24. data/app/views/user_mailer/reset_notification.text.plain.erb +7 -0
  25. data/config/locales/cs.yml +75 -0
  26. data/config/locales/da.yml +72 -0
  27. data/config/locales/de.yml +72 -0
  28. data/config/locales/el.yml +72 -0
  29. data/config/locales/en.yml +72 -0
  30. data/config/locales/es.yml +100 -0
  31. data/config/locales/fr.yml +72 -0
  32. data/config/locales/it.yml +97 -0
  33. data/config/locales/lolcat.yml +55 -0
  34. data/config/locales/lt.yml +55 -0
  35. data/config/locales/lv.yml +72 -0
  36. data/config/locales/nb.yml +72 -0
  37. data/config/locales/nl.yml +70 -0
  38. data/config/locales/pl.yml +100 -0
  39. data/config/locales/pt-BR.yml +68 -0
  40. data/config/locales/rs.yml +72 -0
  41. data/config/locales/ru.yml +97 -0
  42. data/config/locales/sl.yml +61 -0
  43. data/config/locales/sv.yml +64 -0
  44. data/config/locales/vi.yml +72 -0
  45. data/config/locales/zh-CN.yml +72 -0
  46. data/config/locales/zh-TW.yml +72 -0
  47. data/config/routes.rb +31 -0
  48. data/db/migrate/20100913234705_create_refinerycms_authentication_schema.rb +43 -0
  49. data/db/migrate/20100929035252_add_missing_indexes_to_roles_users.rb +11 -0
  50. data/db/migrate/20101206013505_change_to_devise_users_table.rb +27 -0
  51. data/db/migrate/20110106184757_add_remember_created_at_to_users.rb +9 -0
  52. data/features/lost_password.feature +49 -0
  53. data/features/manage_users.feature +61 -0
  54. data/features/step_definitions/lost_password.rb +8 -0
  55. data/features/step_definitions/user_steps.rb +36 -0
  56. data/features/support/factories.rb +18 -0
  57. data/features/support/paths.rb +24 -0
  58. data/lib/authenticated_system.rb +29 -0
  59. data/lib/gemspec.rb +34 -0
  60. data/lib/generators/refinerycms_authentication_generator.rb +8 -0
  61. data/lib/refinerycms-authentication.rb +47 -0
  62. data/license.md +21 -0
  63. data/readme.md +17 -0
  64. data/refinerycms-authentication.gemspec +112 -0
  65. data/spec/models/user_spec.rb +159 -0
  66. metadata +144 -0
@@ -0,0 +1,90 @@
1
+ module Admin
2
+ class UsersController < Admin::BaseController
3
+
4
+ crudify :user, :order => 'username ASC', :title_attribute => 'username'
5
+
6
+ before_filter :load_available_plugins_and_roles, :only => [:new, :create, :edit, :update]
7
+
8
+ def index
9
+ search_all_users if searching?
10
+ paginate_all_users
11
+
12
+ render :partial => 'users' if request.xhr?
13
+ end
14
+
15
+ def new
16
+ @user = User.new
17
+ @selected_plugin_names = []
18
+ end
19
+
20
+ def create
21
+ @user = User.new(params[:user])
22
+ @selected_plugin_names = params[:user][:plugins] || []
23
+ @selected_role_names = params[:user][:roles] || []
24
+
25
+ if @user.save
26
+ @user.plugins = @selected_plugin_names
27
+ # if the user is a superuser and can assign roles according to this site's
28
+ # settings then the roles are set with the POST data.
29
+ unless current_user.has_role?(:superuser) and RefinerySetting.find_or_set(:superuser_can_assign_roles, false)
30
+ @user.add_role(:refinery)
31
+ else
32
+ @user.roles = @selected_role_names.collect{|r| Role[r.downcase.to_sym]}
33
+ end
34
+
35
+ redirect_to(admin_users_url, :notice => t('created', :what => @user.username, :scope => 'refinery.crudify'))
36
+ else
37
+ render :action => 'new'
38
+ end
39
+ end
40
+
41
+ def edit
42
+ @user = User.find params[:id]
43
+ @selected_plugin_names = @user.plugins.collect{|p| p.name}
44
+ end
45
+
46
+ def update
47
+ # Store what the user selected.
48
+ @selected_role_names = params[:user].delete(:roles) || []
49
+ unless current_user.has_role?(:superuser) and RefinerySetting.find_or_set(:superuser_can_assign_roles, false)
50
+ @selected_role_names = @user.roles.collect{|r| r.title}
51
+ end
52
+ @selected_plugin_names = params[:user][:plugins]
53
+
54
+ # Prevent the current user from locking themselves out of the User manager
55
+ if current_user.id == @user.id and (params[:user][:plugins].exclude?("refinery_users") || @selected_role_names.map(&:downcase).exclude?("refinery"))
56
+ flash.now[:error] = t('cannot_remove_user_plugin_from_current_user', :scope => 'admin.users.update')
57
+ render :action => "edit"
58
+ else
59
+ # Store the current plugins and roles for this user.
60
+ @previously_selected_plugin_names = @user.plugins.collect{|p| p.name}
61
+ @previously_selected_roles = @user.roles
62
+ @user.roles = @selected_role_names.collect{|r| Role[r.downcase.to_sym]}
63
+ if params[:user][:password].blank? and params[:user][:password_confirmation].blank?
64
+ params[:user].delete(:password)
65
+ params[:user].delete(:password_confirmation)
66
+ end
67
+
68
+ if @user.update_attributes(params[:user])
69
+ redirect_to admin_users_url, :notice => t('updated', :what => @user.username, :scope => 'refinery.crudify')
70
+ else
71
+ @user.plugins = @previously_selected_plugin_names
72
+ @user.roles = @previously_selected_roles
73
+ @user.save
74
+ render :action => 'edit'
75
+ end
76
+ end
77
+ end
78
+
79
+ protected
80
+
81
+ def load_available_plugins_and_roles
82
+ @available_plugins = ::Refinery::Plugins.registered.in_menu.collect{|a|
83
+ {:name => a.name, :title => a.title}
84
+ }.sort_by {|a| a[:title]}
85
+
86
+ @available_roles = Role.all
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,43 @@
1
+ class PasswordsController < ::Devise::PasswordsController
2
+ layout 'login'
3
+
4
+ # Rather than overriding devise, it seems better to just apply the notice here.
5
+ after_filter :give_notice, :only => [:update]
6
+ def give_notice
7
+ unless %w(notice error alert).include?(flash.keys.map(&:to_s)) or @user.errors.any?
8
+ flash[:notice] = t('successful', :scope => 'users.reset', :email => @user.email)
9
+ end
10
+ end
11
+ protected :give_notice
12
+
13
+ # GET /registrations/password/edit?reset_password_token=abcdef
14
+ def edit
15
+ if params[:reset_password_token] and (@user = User.find_by_reset_password_token(params[:reset_password_token])).present?
16
+ render_with_scope :edit
17
+ else
18
+ redirect_to(new_user_password_url, :flash => ({
19
+ :error => t('code_invalid', :scope => 'users.reset')
20
+ }))
21
+ end
22
+ end
23
+
24
+ # POST /registrations/password
25
+ def create
26
+ if params[:user].present? and (email = params[:user][:email]).present? and
27
+ (user = User.find_by_email(email)).present?
28
+
29
+ # Call devise reset function.
30
+ user.send(:generate_reset_password_token!)
31
+ UserMailer.reset_notification(user, request).deliver
32
+ redirect_to new_user_session_path, :notice => t('email_reset_sent', :scope => 'users.forgot') and return
33
+ else
34
+ @user = User.new(params[:user])
35
+ flash.now[:error] = if (email = params[:user][:email]).blank?
36
+ t('blank_email', :scope => 'users.forgot')
37
+ else
38
+ t('email_not_associated_with_account_html', :email => email, :scope => 'users.forgot').html_safe
39
+ end
40
+ render_with_scope :new
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,67 @@
1
+ class RegistrationsController < ::Devise::RegistrationsController
2
+
3
+ # Protect these actions behind an admin login
4
+ before_filter :redirect?, :only => [:new, :create]
5
+
6
+ layout 'login'
7
+
8
+ def new
9
+ @user = User.new
10
+ end
11
+
12
+ # This method should only be used to create the first Refinery user.
13
+ def create
14
+ @user = User.new(params[:user])
15
+ @selected_plugin_titles = params[:user][:plugins] || []
16
+
17
+ @user.save if @user.valid?
18
+
19
+ if @user.errors.empty?
20
+ @user.add_role(:refinery)
21
+ @user.plugins = @selected_plugin_titles
22
+ @user.save
23
+ if Role[:refinery].users.count == 1
24
+ # this is the superuser if this user is the only user.
25
+ @user.add_role(:superuser)
26
+ @user.save
27
+
28
+ # set this user as the recipient of inquiry notifications, if we're using that engine.
29
+ if defined?(InquirySetting) and
30
+ (notification_recipients = InquirySetting.find_or_create_by_name("Notification Recipients")).present?
31
+ notification_recipients.update_attributes({
32
+ :value => @user.email,
33
+ :destroyable => false
34
+ })
35
+ end
36
+ end
37
+
38
+ flash[:message] = "<h2>#{t('welcome', :scope => 'users.create', :who => @user.username).gsub(/\.$/, '')}.</h2>".html_safe
39
+
40
+ site_name_setting = RefinerySetting.find_or_create_by_name('site_name', :value => "Company Name")
41
+ if site_name_setting.value.to_s =~ /^(|Company\ Name)$/ or Role[:refinery].users.count == 1
42
+ flash[:message] << "<p>#{t('setup_website_name_html', :scope => 'users',
43
+ :link => edit_admin_refinery_setting_url(site_name_setting, :dialog => true),
44
+ :title => t('edit', :scope => 'admin.refinery_settings'))}</p>".html_safe
45
+ end
46
+ sign_in(@user)
47
+ redirect_back_or_default(admin_root_url)
48
+ else
49
+ render :action => 'new'
50
+ end
51
+ end
52
+
53
+ protected
54
+
55
+ def redirect?
56
+ if refinery_user?
57
+ redirect_to admin_users_url
58
+ elsif refinery_users_exist?
59
+ redirect_to new_user_session_path
60
+ end
61
+ end
62
+
63
+ def refinery_users_exist?
64
+ Role[:refinery].users.any?
65
+ end
66
+
67
+ end
@@ -0,0 +1,23 @@
1
+ class SessionsController < ::Devise::SessionsController
2
+ layout 'login'
3
+
4
+ before_filter :clear_unauthenticated_flash, :only => [:new]
5
+
6
+ def create
7
+ super
8
+ rescue BCrypt::Errors::InvalidSalt
9
+ flash[:error] = t('password_encryption', :scope => 'users.forgot')
10
+ redirect_to new_user_password_path
11
+ end
12
+
13
+ protected
14
+ # We don't like this alert.
15
+ def clear_unauthenticated_flash
16
+ if flash.keys.include?(:alert) and flash.values.any?{|v|
17
+ ['unauthenticated', t('unauthenticated', :scope => 'devise.failure')].include?(v)
18
+ }
19
+ flash.delete(:alert)
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,2 @@
1
+ module SessionsHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module UsersHelper
2
+ end
@@ -0,0 +1,20 @@
1
+ class UserMailer < ActionMailer::Base
2
+
3
+ def reset_notification(user, request)
4
+ @user = user
5
+ @url = edit_user_password_url(:host => request.host_with_port,
6
+ :reset_password_token => @user.reset_password_token)
7
+
8
+ domain = request.domain(RefinerySetting.find_or_set(:tld_length, 1))
9
+
10
+ mail(:to => user.email,
11
+ :subject => t('subject', :scope => 'user_mailer.reset_notification'),
12
+ :from => "\"#{RefinerySetting[:site_name]}\" <no-reply@#{domain}>")
13
+ end
14
+
15
+ protected
16
+
17
+ def url_prefix(request)
18
+ "#{request.protocol}#{request.host_with_port}"
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ class Role < ActiveRecord::Base
2
+
3
+ has_and_belongs_to_many :users
4
+
5
+ before_validation :camelize_title
6
+ validates :title, :uniqueness => true
7
+
8
+ def camelize_title(role_title = self.title)
9
+ self.title = role_title.to_s.camelize
10
+ end
11
+
12
+ def self.[](title)
13
+ find_or_create_by_title(title.to_s.camelize)
14
+ end
15
+
16
+ end
@@ -0,0 +1,6 @@
1
+ class RolesUsers < ActiveRecord::Base
2
+
3
+ belongs_to :role
4
+ belongs_to :user
5
+
6
+ end
@@ -0,0 +1,60 @@
1
+ require 'devise'
2
+
3
+ class User < ActiveRecord::Base
4
+ has_and_belongs_to_many :roles
5
+ has_many :plugins, :class_name => "UserPlugin", :order => "position ASC", :dependent => :destroy
6
+ has_friendly_id :username, :use_slug => true
7
+
8
+ # Include default devise modules. Others available are:
9
+ # :token_authenticatable, :confirmable, :lockable and :timeoutable
10
+ devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
11
+
12
+ # Setup accessible (or protected) attributes for your model
13
+ # :login is a virtual attribute for authenticating by either username or email
14
+ # This is in addition to a real persisted field like 'username'
15
+ attr_accessor :login
16
+ attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :plugins, :login
17
+
18
+ validates :username, :presence => true, :uniqueness => true
19
+
20
+ class << self
21
+ # Find user by email or username.
22
+ # https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign_in-using-their-username-or-email-address
23
+ def find_for_database_authentication(conditions)
24
+ value = conditions[authentication_keys.first]
25
+ where(["username = :value OR email = :value", { :value => value }]).first
26
+ end
27
+ end
28
+
29
+ def plugins=(plugin_names)
30
+ if persisted? # don't add plugins when the user_id is nil.
31
+ UserPlugin.delete_all(:user_id => id)
32
+
33
+ plugin_names.each_with_index do |plugin_name, index|
34
+ plugins.create(:name => plugin_name, :position => index) if plugin_name.is_a?(String)
35
+ end
36
+ end
37
+ end
38
+
39
+ def authorized_plugins
40
+ plugins.collect { |p| p.name } | Refinery::Plugins.always_allowed.names
41
+ end
42
+
43
+ def can_delete?(user_to_delete = self)
44
+ user_to_delete.persisted? and
45
+ !user_to_delete.has_role?(:superuser) and
46
+ Role[:refinery].users.count > 1 and
47
+ id != user_to_delete.id
48
+ end
49
+
50
+ def add_role(title)
51
+ raise ArgumentException, "Role should be the title of the role not a role object." if title.is_a?(Role)
52
+ roles << Role[title] unless has_role?(title)
53
+ end
54
+
55
+ def has_role?(title)
56
+ raise ArgumentException, "Role should be the title of the role not a role object." if title.is_a?(Role)
57
+ (role = Role.find_by_title(title.to_s.camelize)).present? and roles.collect{|r| r.id}.include?(role.id)
58
+ end
59
+
60
+ end
@@ -0,0 +1,5 @@
1
+ class UserPlugin < ActiveRecord::Base
2
+
3
+ belongs_to :user
4
+
5
+ end
@@ -0,0 +1,92 @@
1
+ <%= form_for [:admin, @user] do |f| %>
2
+
3
+ <%= render :partial => "/shared/admin/error_messages",
4
+ :locals => {
5
+ :object => @user,
6
+ :include_object_name => true
7
+ } %>
8
+
9
+ <div class='field'>
10
+ <%= f.label :username %>
11
+ <%= f.text_field :username %>
12
+ </div>
13
+ <div class='field'>
14
+ <%= f.label :email %>
15
+ <%= f.text_field :email %>
16
+ </div>
17
+ <div class='field'>
18
+ <%= f.label :password %>
19
+ <%= f.password_field :password, :autocomplete => 'off' %>
20
+ <%= "<br /><span class='preview'>#{t('.blank_password_keeps_current')}</span>".html_safe if @user.persisted? %>
21
+ </div>
22
+ <div class='field'>
23
+ <%= f.label :password_confirmation %>
24
+ <%= f.password_field :password_confirmation, :autocomplete => 'off' %>
25
+ </div>
26
+ <div class='field plugin_access'>
27
+ <span class='label_with_help'>
28
+ <%= f.label :plugin_access, t('.plugin_access'), :class => "title_label" %>
29
+ <%= link_to "(#{t('.enable_all')})", "", :id => "user_plugins_enable_all" %>
30
+ </span>
31
+ <ul id='plugins' class='checkboxes'>
32
+ <% @available_plugins.each do |plugin| -%>
33
+ <% if Refinery::Plugins.always_allowed.names.include?(plugin[:name]) or
34
+ (plugin[:name] == 'refinery_users' and @user.id == current_user.id) %>
35
+ <%= hidden_field_tag 'user[plugins][]', plugin[:name],
36
+ :id => "plugins_#{plugin[:name]}" %>
37
+ <% else %>
38
+ <li>
39
+ <%= check_box_tag 'user[plugins][]', plugin[:name],
40
+ @selected_plugin_names.include?(plugin[:name]),
41
+ :id => "plugins_#{plugin[:name]}" %>
42
+ <%= f.label 'user[plugins][]',
43
+ t('title', :scope => "plugins.#{plugin[:name].downcase}", :default => plugin[:title]),
44
+ :class => "stripped",
45
+ :for => "plugins_#{plugin[:name]}" %>
46
+ </li>
47
+ <% end %>
48
+ <% end %>
49
+ </ul>
50
+ </div>
51
+
52
+ <% if current_user.has_role?(:superuser) and RefinerySetting.find_or_set(:superuser_can_assign_roles, false) %>
53
+ <div class='field role_access'>
54
+ <span class='label_with_help'>
55
+ <%= f.label :role_access, t('.role_access'), :class => "title_label" %>
56
+ </span>
57
+ <ul id='roles' class='checkboxes'>
58
+ <% @available_roles.each do |role|
59
+ downcased_title = (title = role[:title]).downcase -%>
60
+ <li>
61
+ <%= check_box_tag 'user[roles][]', downcased_title, @user.has_role?(title),
62
+ :id => "roles_#{downcased_title}" %>
63
+ <%= f.label 'user[roles][]',
64
+ t(downcased_title, :scope => 'roles', :default => title),
65
+ :class => 'stripped',
66
+ :for => "roles_#{downcased_title}" %>
67
+ </li>
68
+ <% end %>
69
+ </ul>
70
+ </div>
71
+ <% end %>
72
+
73
+ <%= render :partial => "/shared/admin/form_actions",
74
+ :locals => {
75
+ :f => f,
76
+ :continue_editing => false,
77
+ :hide_delete => !current_user.can_delete?(@user),
78
+ :delete_title => t('delete', :scope => 'admin.users'),
79
+ :delete_confirmation => t('message', :scope => 'shared.admin.delete', :title => @user.username)
80
+ } %>
81
+ <% end %>
82
+
83
+ <% content_for :javascripts do %>
84
+ <script>
85
+ $(document).ready(function() {
86
+ $('#user_plugins_enable_all').click(function(e, a) {
87
+ $('div.field.plugin_access ul#plugins li input:checkbox').attr('checked', true);
88
+ e.preventDefault();
89
+ });
90
+ });
91
+ </script>
92
+ <% end %>