refinerycms-authentication 0.9.9.1

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.
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 %>