##// END OF EJS Templates
Extracts user groups assignment from controller....
Jean-Philippe Lang -
r4385:0a2ec6ef0472
parent child
Show More
@@ -1,222 +1,221
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2010 Jean-Philippe Lang
2 # Copyright (C) 2006-2010 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class UsersController < ApplicationController
18 class UsersController < ApplicationController
19 layout 'admin'
19 layout 'admin'
20
20
21 before_filter :require_admin, :except => :show
21 before_filter :require_admin, :except => :show
22 accept_key_auth :index, :show, :create, :update
22 accept_key_auth :index, :show, :create, :update
23
23
24 helper :sort
24 helper :sort
25 include SortHelper
25 include SortHelper
26 helper :custom_fields
26 helper :custom_fields
27 include CustomFieldsHelper
27 include CustomFieldsHelper
28
28
29 def index
29 def index
30 sort_init 'login', 'asc'
30 sort_init 'login', 'asc'
31 sort_update %w(login firstname lastname mail admin created_on last_login_on)
31 sort_update %w(login firstname lastname mail admin created_on last_login_on)
32
32
33 case params[:format]
33 case params[:format]
34 when 'xml', 'json'
34 when 'xml', 'json'
35 @offset, @limit = api_offset_and_limit
35 @offset, @limit = api_offset_and_limit
36 else
36 else
37 @limit = per_page_option
37 @limit = per_page_option
38 end
38 end
39
39
40 @status = params[:status] ? params[:status].to_i : 1
40 @status = params[:status] ? params[:status].to_i : 1
41 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
41 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
42
42
43 unless params[:name].blank?
43 unless params[:name].blank?
44 name = "%#{params[:name].strip.downcase}%"
44 name = "%#{params[:name].strip.downcase}%"
45 c << ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ? OR LOWER(mail) LIKE ?", name, name, name, name]
45 c << ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ? OR LOWER(mail) LIKE ?", name, name, name, name]
46 end
46 end
47
47
48 @user_count = User.count(:conditions => c.conditions)
48 @user_count = User.count(:conditions => c.conditions)
49 @user_pages = Paginator.new self, @user_count, @limit, params['page']
49 @user_pages = Paginator.new self, @user_count, @limit, params['page']
50 @offset ||= @user_pages.current.offset
50 @offset ||= @user_pages.current.offset
51 @users = User.find :all,
51 @users = User.find :all,
52 :order => sort_clause,
52 :order => sort_clause,
53 :conditions => c.conditions,
53 :conditions => c.conditions,
54 :limit => @limit,
54 :limit => @limit,
55 :offset => @offset
55 :offset => @offset
56
56
57 respond_to do |format|
57 respond_to do |format|
58 format.html { render :layout => !request.xhr? }
58 format.html { render :layout => !request.xhr? }
59 format.api
59 format.api
60 end
60 end
61 end
61 end
62
62
63 def show
63 def show
64 @user = User.find(params[:id])
64 @user = User.find(params[:id])
65
65
66 # show projects based on current user visibility
66 # show projects based on current user visibility
67 @memberships = @user.memberships.all(:conditions => Project.visible_by(User.current))
67 @memberships = @user.memberships.all(:conditions => Project.visible_by(User.current))
68
68
69 events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
69 events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
70 @events_by_day = events.group_by(&:event_date)
70 @events_by_day = events.group_by(&:event_date)
71
71
72 unless User.current.admin?
72 unless User.current.admin?
73 if !@user.active? || (@user != User.current && @memberships.empty? && events.empty?)
73 if !@user.active? || (@user != User.current && @memberships.empty? && events.empty?)
74 render_404
74 render_404
75 return
75 return
76 end
76 end
77 end
77 end
78
78
79 respond_to do |format|
79 respond_to do |format|
80 format.html { render :layout => 'base' }
80 format.html { render :layout => 'base' }
81 format.api
81 format.api
82 end
82 end
83 rescue ActiveRecord::RecordNotFound
83 rescue ActiveRecord::RecordNotFound
84 render_404
84 render_404
85 end
85 end
86
86
87 def new
87 def new
88 @user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option)
88 @user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option)
89 @auth_sources = AuthSource.find(:all)
89 @auth_sources = AuthSource.find(:all)
90 end
90 end
91
91
92 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
92 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
93 def create
93 def create
94 @user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option)
94 @user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option)
95 @user.safe_attributes = params[:user]
95 @user.safe_attributes = params[:user]
96 @user.admin = params[:user][:admin] || false
96 @user.admin = params[:user][:admin] || false
97 @user.login = params[:user][:login]
97 @user.login = params[:user][:login]
98 @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] unless @user.auth_source_id
98 @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] unless @user.auth_source_id
99
99
100 # TODO: Similar to My#account
100 # TODO: Similar to My#account
101 @user.pref.attributes = params[:pref]
101 @user.pref.attributes = params[:pref]
102 @user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
102 @user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
103
103
104 if @user.save
104 if @user.save
105 @user.pref.save
105 @user.pref.save
106 @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
106 @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
107
107
108 Mailer.deliver_account_information(@user, params[:password]) if params[:send_information]
108 Mailer.deliver_account_information(@user, params[:password]) if params[:send_information]
109
109
110 respond_to do |format|
110 respond_to do |format|
111 format.html {
111 format.html {
112 flash[:notice] = l(:notice_successful_create)
112 flash[:notice] = l(:notice_successful_create)
113 redirect_to(params[:continue] ?
113 redirect_to(params[:continue] ?
114 {:controller => 'users', :action => 'new'} :
114 {:controller => 'users', :action => 'new'} :
115 {:controller => 'users', :action => 'edit', :id => @user}
115 {:controller => 'users', :action => 'edit', :id => @user}
116 )
116 )
117 }
117 }
118 format.api { render :action => 'show', :status => :created, :location => user_url(@user) }
118 format.api { render :action => 'show', :status => :created, :location => user_url(@user) }
119 end
119 end
120 else
120 else
121 @auth_sources = AuthSource.find(:all)
121 @auth_sources = AuthSource.find(:all)
122 # Clear password input
122 # Clear password input
123 @user.password = @user.password_confirmation = nil
123 @user.password = @user.password_confirmation = nil
124
124
125 respond_to do |format|
125 respond_to do |format|
126 format.html { render :action => 'new' }
126 format.html { render :action => 'new' }
127 format.api { render_validation_errors(@user) }
127 format.api { render_validation_errors(@user) }
128 end
128 end
129 end
129 end
130 end
130 end
131
131
132 def edit
132 def edit
133 @user = User.find(params[:id])
133 @user = User.find(params[:id])
134
134
135 @auth_sources = AuthSource.find(:all)
135 @auth_sources = AuthSource.find(:all)
136 @membership ||= Member.new
136 @membership ||= Member.new
137 end
137 end
138
138
139 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
139 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
140 def update
140 def update
141 @user = User.find(params[:id])
141 @user = User.find(params[:id])
142
142
143 @user.admin = params[:user][:admin] if params[:user][:admin]
143 @user.admin = params[:user][:admin] if params[:user][:admin]
144 @user.login = params[:user][:login] if params[:user][:login]
144 @user.login = params[:user][:login] if params[:user][:login]
145 if params[:user][:password].present? && (@user.auth_source_id.nil? || params[:user][:auth_source_id].blank?)
145 if params[:user][:password].present? && (@user.auth_source_id.nil? || params[:user][:auth_source_id].blank?)
146 @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation]
146 @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation]
147 end
147 end
148 @user.group_ids = params[:user][:group_ids] if params[:user][:group_ids]
149 @user.safe_attributes = params[:user]
148 @user.safe_attributes = params[:user]
150 # Was the account actived ? (do it before User#save clears the change)
149 # Was the account actived ? (do it before User#save clears the change)
151 was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
150 was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
152 # TODO: Similar to My#account
151 # TODO: Similar to My#account
153 @user.pref.attributes = params[:pref]
152 @user.pref.attributes = params[:pref]
154 @user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
153 @user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
155
154
156 if @user.save
155 if @user.save
157 @user.pref.save
156 @user.pref.save
158 @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
157 @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
159
158
160 if was_activated
159 if was_activated
161 Mailer.deliver_account_activated(@user)
160 Mailer.deliver_account_activated(@user)
162 elsif @user.active? && params[:send_information] && !params[:user][:password].blank? && @user.auth_source_id.nil?
161 elsif @user.active? && params[:send_information] && !params[:user][:password].blank? && @user.auth_source_id.nil?
163 Mailer.deliver_account_information(@user, params[:user][:password])
162 Mailer.deliver_account_information(@user, params[:user][:password])
164 end
163 end
165
164
166 respond_to do |format|
165 respond_to do |format|
167 format.html {
166 format.html {
168 flash[:notice] = l(:notice_successful_update)
167 flash[:notice] = l(:notice_successful_update)
169 redirect_to :back
168 redirect_to :back
170 }
169 }
171 format.api { head :ok }
170 format.api { head :ok }
172 end
171 end
173 else
172 else
174 @auth_sources = AuthSource.find(:all)
173 @auth_sources = AuthSource.find(:all)
175 @membership ||= Member.new
174 @membership ||= Member.new
176 # Clear password input
175 # Clear password input
177 @user.password = @user.password_confirmation = nil
176 @user.password = @user.password_confirmation = nil
178
177
179 respond_to do |format|
178 respond_to do |format|
180 format.html { render :action => :edit }
179 format.html { render :action => :edit }
181 format.api { render_validation_errors(@user) }
180 format.api { render_validation_errors(@user) }
182 end
181 end
183 end
182 end
184 rescue ::ActionController::RedirectBackError
183 rescue ::ActionController::RedirectBackError
185 redirect_to :controller => 'users', :action => 'edit', :id => @user
184 redirect_to :controller => 'users', :action => 'edit', :id => @user
186 end
185 end
187
186
188 def edit_membership
187 def edit_membership
189 @user = User.find(params[:id])
188 @user = User.find(params[:id])
190 @membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
189 @membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
191 @membership.save if request.post?
190 @membership.save if request.post?
192 respond_to do |format|
191 respond_to do |format|
193 if @membership.valid?
192 if @membership.valid?
194 format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
193 format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
195 format.js {
194 format.js {
196 render(:update) {|page|
195 render(:update) {|page|
197 page.replace_html "tab-content-memberships", :partial => 'users/memberships'
196 page.replace_html "tab-content-memberships", :partial => 'users/memberships'
198 page.visual_effect(:highlight, "member-#{@membership.id}")
197 page.visual_effect(:highlight, "member-#{@membership.id}")
199 }
198 }
200 }
199 }
201 else
200 else
202 format.js {
201 format.js {
203 render(:update) {|page|
202 render(:update) {|page|
204 page.alert(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', ')))
203 page.alert(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', ')))
205 }
204 }
206 }
205 }
207 end
206 end
208 end
207 end
209 end
208 end
210
209
211 def destroy_membership
210 def destroy_membership
212 @user = User.find(params[:id])
211 @user = User.find(params[:id])
213 @membership = Member.find(params[:membership_id])
212 @membership = Member.find(params[:membership_id])
214 if request.post? && @membership.deletable?
213 if request.post? && @membership.deletable?
215 @membership.destroy
214 @membership.destroy
216 end
215 end
217 respond_to do |format|
216 respond_to do |format|
218 format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
217 format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
219 format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'users/memberships'} }
218 format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'users/memberships'} }
220 end
219 end
221 end
220 end
222 end
221 end
@@ -1,499 +1,502
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2009 Jean-Philippe Lang
2 # Copyright (C) 2006-2009 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require "digest/sha1"
18 require "digest/sha1"
19
19
20 class User < Principal
20 class User < Principal
21 include Redmine::SafeAttributes
21 include Redmine::SafeAttributes
22
22
23 # Account statuses
23 # Account statuses
24 STATUS_ANONYMOUS = 0
24 STATUS_ANONYMOUS = 0
25 STATUS_ACTIVE = 1
25 STATUS_ACTIVE = 1
26 STATUS_REGISTERED = 2
26 STATUS_REGISTERED = 2
27 STATUS_LOCKED = 3
27 STATUS_LOCKED = 3
28
28
29 USER_FORMATS = {
29 USER_FORMATS = {
30 :firstname_lastname => '#{firstname} #{lastname}',
30 :firstname_lastname => '#{firstname} #{lastname}',
31 :firstname => '#{firstname}',
31 :firstname => '#{firstname}',
32 :lastname_firstname => '#{lastname} #{firstname}',
32 :lastname_firstname => '#{lastname} #{firstname}',
33 :lastname_coma_firstname => '#{lastname}, #{firstname}',
33 :lastname_coma_firstname => '#{lastname}, #{firstname}',
34 :username => '#{login}'
34 :username => '#{login}'
35 }
35 }
36
36
37 MAIL_NOTIFICATION_OPTIONS = [
37 MAIL_NOTIFICATION_OPTIONS = [
38 ['all', :label_user_mail_option_all],
38 ['all', :label_user_mail_option_all],
39 ['selected', :label_user_mail_option_selected],
39 ['selected', :label_user_mail_option_selected],
40 ['only_my_events', :label_user_mail_option_only_my_events],
40 ['only_my_events', :label_user_mail_option_only_my_events],
41 ['only_assigned', :label_user_mail_option_only_assigned],
41 ['only_assigned', :label_user_mail_option_only_assigned],
42 ['only_owner', :label_user_mail_option_only_owner],
42 ['only_owner', :label_user_mail_option_only_owner],
43 ['none', :label_user_mail_option_none]
43 ['none', :label_user_mail_option_none]
44 ]
44 ]
45
45
46 has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)},
46 has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)},
47 :after_remove => Proc.new {|user, group| group.user_removed(user)}
47 :after_remove => Proc.new {|user, group| group.user_removed(user)}
48 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
48 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
49 has_many :changesets, :dependent => :nullify
49 has_many :changesets, :dependent => :nullify
50 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
50 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
51 has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'"
51 has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'"
52 has_one :api_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='api'"
52 has_one :api_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='api'"
53 belongs_to :auth_source
53 belongs_to :auth_source
54
54
55 # Active non-anonymous users scope
55 # Active non-anonymous users scope
56 named_scope :active, :conditions => "#{User.table_name}.status = #{STATUS_ACTIVE}"
56 named_scope :active, :conditions => "#{User.table_name}.status = #{STATUS_ACTIVE}"
57
57
58 acts_as_customizable
58 acts_as_customizable
59
59
60 attr_accessor :password, :password_confirmation
60 attr_accessor :password, :password_confirmation
61 attr_accessor :last_before_login_on
61 attr_accessor :last_before_login_on
62 # Prevents unauthorized assignments
62 # Prevents unauthorized assignments
63 attr_protected :login, :admin, :password, :password_confirmation, :hashed_password, :group_ids
63 attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
64
64
65 validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
65 validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
66 validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }, :case_sensitive => false
66 validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }, :case_sensitive => false
67 validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false
67 validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false
68 # Login must contain lettres, numbers, underscores only
68 # Login must contain lettres, numbers, underscores only
69 validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
69 validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
70 validates_length_of :login, :maximum => 30
70 validates_length_of :login, :maximum => 30
71 validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-\.]*$/i
71 validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-\.]*$/i
72 validates_length_of :firstname, :lastname, :maximum => 30
72 validates_length_of :firstname, :lastname, :maximum => 30
73 validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
73 validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
74 validates_length_of :mail, :maximum => 60, :allow_nil => true
74 validates_length_of :mail, :maximum => 60, :allow_nil => true
75 validates_confirmation_of :password, :allow_nil => true
75 validates_confirmation_of :password, :allow_nil => true
76 validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
76 validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
77
77
78 def before_create
78 def before_create
79 self.mail_notification = Setting.default_notification_option if self.mail_notification.blank?
79 self.mail_notification = Setting.default_notification_option if self.mail_notification.blank?
80 true
80 true
81 end
81 end
82
82
83 def before_save
83 def before_save
84 # update hashed_password if password was set
84 # update hashed_password if password was set
85 self.hashed_password = User.hash_password(self.password) if self.password && self.auth_source_id.blank?
85 self.hashed_password = User.hash_password(self.password) if self.password && self.auth_source_id.blank?
86 end
86 end
87
87
88 def reload(*args)
88 def reload(*args)
89 @name = nil
89 @name = nil
90 super
90 super
91 end
91 end
92
92
93 def mail=(arg)
93 def mail=(arg)
94 write_attribute(:mail, arg.to_s.strip)
94 write_attribute(:mail, arg.to_s.strip)
95 end
95 end
96
96
97 def identity_url=(url)
97 def identity_url=(url)
98 if url.blank?
98 if url.blank?
99 write_attribute(:identity_url, '')
99 write_attribute(:identity_url, '')
100 else
100 else
101 begin
101 begin
102 write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
102 write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
103 rescue OpenIdAuthentication::InvalidOpenId
103 rescue OpenIdAuthentication::InvalidOpenId
104 # Invlaid url, don't save
104 # Invlaid url, don't save
105 end
105 end
106 end
106 end
107 self.read_attribute(:identity_url)
107 self.read_attribute(:identity_url)
108 end
108 end
109
109
110 # Returns the user that matches provided login and password, or nil
110 # Returns the user that matches provided login and password, or nil
111 def self.try_to_login(login, password)
111 def self.try_to_login(login, password)
112 # Make sure no one can sign in with an empty password
112 # Make sure no one can sign in with an empty password
113 return nil if password.to_s.empty?
113 return nil if password.to_s.empty?
114 user = find_by_login(login)
114 user = find_by_login(login)
115 if user
115 if user
116 # user is already in local database
116 # user is already in local database
117 return nil if !user.active?
117 return nil if !user.active?
118 if user.auth_source
118 if user.auth_source
119 # user has an external authentication method
119 # user has an external authentication method
120 return nil unless user.auth_source.authenticate(login, password)
120 return nil unless user.auth_source.authenticate(login, password)
121 else
121 else
122 # authentication with local password
122 # authentication with local password
123 return nil unless User.hash_password(password) == user.hashed_password
123 return nil unless User.hash_password(password) == user.hashed_password
124 end
124 end
125 else
125 else
126 # user is not yet registered, try to authenticate with available sources
126 # user is not yet registered, try to authenticate with available sources
127 attrs = AuthSource.authenticate(login, password)
127 attrs = AuthSource.authenticate(login, password)
128 if attrs
128 if attrs
129 user = new(attrs)
129 user = new(attrs)
130 user.login = login
130 user.login = login
131 user.language = Setting.default_language
131 user.language = Setting.default_language
132 if user.save
132 if user.save
133 user.reload
133 user.reload
134 logger.info("User '#{user.login}' created from external auth source: #{user.auth_source.type} - #{user.auth_source.name}") if logger && user.auth_source
134 logger.info("User '#{user.login}' created from external auth source: #{user.auth_source.type} - #{user.auth_source.name}") if logger && user.auth_source
135 end
135 end
136 end
136 end
137 end
137 end
138 user.update_attribute(:last_login_on, Time.now) if user && !user.new_record?
138 user.update_attribute(:last_login_on, Time.now) if user && !user.new_record?
139 user
139 user
140 rescue => text
140 rescue => text
141 raise text
141 raise text
142 end
142 end
143
143
144 # Returns the user who matches the given autologin +key+ or nil
144 # Returns the user who matches the given autologin +key+ or nil
145 def self.try_to_autologin(key)
145 def self.try_to_autologin(key)
146 tokens = Token.find_all_by_action_and_value('autologin', key)
146 tokens = Token.find_all_by_action_and_value('autologin', key)
147 # Make sure there's only 1 token that matches the key
147 # Make sure there's only 1 token that matches the key
148 if tokens.size == 1
148 if tokens.size == 1
149 token = tokens.first
149 token = tokens.first
150 if (token.created_on > Setting.autologin.to_i.day.ago) && token.user && token.user.active?
150 if (token.created_on > Setting.autologin.to_i.day.ago) && token.user && token.user.active?
151 token.user.update_attribute(:last_login_on, Time.now)
151 token.user.update_attribute(:last_login_on, Time.now)
152 token.user
152 token.user
153 end
153 end
154 end
154 end
155 end
155 end
156
156
157 # Return user's full name for display
157 # Return user's full name for display
158 def name(formatter = nil)
158 def name(formatter = nil)
159 if formatter
159 if formatter
160 eval('"' + (USER_FORMATS[formatter] || USER_FORMATS[:firstname_lastname]) + '"')
160 eval('"' + (USER_FORMATS[formatter] || USER_FORMATS[:firstname_lastname]) + '"')
161 else
161 else
162 @name ||= eval('"' + (USER_FORMATS[Setting.user_format] || USER_FORMATS[:firstname_lastname]) + '"')
162 @name ||= eval('"' + (USER_FORMATS[Setting.user_format] || USER_FORMATS[:firstname_lastname]) + '"')
163 end
163 end
164 end
164 end
165
165
166 def active?
166 def active?
167 self.status == STATUS_ACTIVE
167 self.status == STATUS_ACTIVE
168 end
168 end
169
169
170 def registered?
170 def registered?
171 self.status == STATUS_REGISTERED
171 self.status == STATUS_REGISTERED
172 end
172 end
173
173
174 def locked?
174 def locked?
175 self.status == STATUS_LOCKED
175 self.status == STATUS_LOCKED
176 end
176 end
177
177
178 def activate
178 def activate
179 self.status = STATUS_ACTIVE
179 self.status = STATUS_ACTIVE
180 end
180 end
181
181
182 def register
182 def register
183 self.status = STATUS_REGISTERED
183 self.status = STATUS_REGISTERED
184 end
184 end
185
185
186 def lock
186 def lock
187 self.status = STATUS_LOCKED
187 self.status = STATUS_LOCKED
188 end
188 end
189
189
190 def activate!
190 def activate!
191 update_attribute(:status, STATUS_ACTIVE)
191 update_attribute(:status, STATUS_ACTIVE)
192 end
192 end
193
193
194 def register!
194 def register!
195 update_attribute(:status, STATUS_REGISTERED)
195 update_attribute(:status, STATUS_REGISTERED)
196 end
196 end
197
197
198 def lock!
198 def lock!
199 update_attribute(:status, STATUS_LOCKED)
199 update_attribute(:status, STATUS_LOCKED)
200 end
200 end
201
201
202 def check_password?(clear_password)
202 def check_password?(clear_password)
203 if auth_source_id.present?
203 if auth_source_id.present?
204 auth_source.authenticate(self.login, clear_password)
204 auth_source.authenticate(self.login, clear_password)
205 else
205 else
206 User.hash_password(clear_password) == self.hashed_password
206 User.hash_password(clear_password) == self.hashed_password
207 end
207 end
208 end
208 end
209
209
210 # Does the backend storage allow this user to change their password?
210 # Does the backend storage allow this user to change their password?
211 def change_password_allowed?
211 def change_password_allowed?
212 return true if auth_source_id.blank?
212 return true if auth_source_id.blank?
213 return auth_source.allow_password_changes?
213 return auth_source.allow_password_changes?
214 end
214 end
215
215
216 # Generate and set a random password. Useful for automated user creation
216 # Generate and set a random password. Useful for automated user creation
217 # Based on Token#generate_token_value
217 # Based on Token#generate_token_value
218 #
218 #
219 def random_password
219 def random_password
220 chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
220 chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
221 password = ''
221 password = ''
222 40.times { |i| password << chars[rand(chars.size-1)] }
222 40.times { |i| password << chars[rand(chars.size-1)] }
223 self.password = password
223 self.password = password
224 self.password_confirmation = password
224 self.password_confirmation = password
225 self
225 self
226 end
226 end
227
227
228 def pref
228 def pref
229 self.preference ||= UserPreference.new(:user => self)
229 self.preference ||= UserPreference.new(:user => self)
230 end
230 end
231
231
232 def time_zone
232 def time_zone
233 @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])
233 @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])
234 end
234 end
235
235
236 def wants_comments_in_reverse_order?
236 def wants_comments_in_reverse_order?
237 self.pref[:comments_sorting] == 'desc'
237 self.pref[:comments_sorting] == 'desc'
238 end
238 end
239
239
240 # Return user's RSS key (a 40 chars long string), used to access feeds
240 # Return user's RSS key (a 40 chars long string), used to access feeds
241 def rss_key
241 def rss_key
242 token = self.rss_token || Token.create(:user => self, :action => 'feeds')
242 token = self.rss_token || Token.create(:user => self, :action => 'feeds')
243 token.value
243 token.value
244 end
244 end
245
245
246 # Return user's API key (a 40 chars long string), used to access the API
246 # Return user's API key (a 40 chars long string), used to access the API
247 def api_key
247 def api_key
248 token = self.api_token || self.create_api_token(:action => 'api')
248 token = self.api_token || self.create_api_token(:action => 'api')
249 token.value
249 token.value
250 end
250 end
251
251
252 # Return an array of project ids for which the user has explicitly turned mail notifications on
252 # Return an array of project ids for which the user has explicitly turned mail notifications on
253 def notified_projects_ids
253 def notified_projects_ids
254 @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
254 @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
255 end
255 end
256
256
257 def notified_project_ids=(ids)
257 def notified_project_ids=(ids)
258 Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
258 Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
259 Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
259 Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
260 @notified_projects_ids = nil
260 @notified_projects_ids = nil
261 notified_projects_ids
261 notified_projects_ids
262 end
262 end
263
263
264 # Only users that belong to more than 1 project can select projects for which they are notified
264 # Only users that belong to more than 1 project can select projects for which they are notified
265 def valid_notification_options
265 def valid_notification_options
266 # Note that @user.membership.size would fail since AR ignores
266 # Note that @user.membership.size would fail since AR ignores
267 # :include association option when doing a count
267 # :include association option when doing a count
268 if memberships.length < 1
268 if memberships.length < 1
269 MAIL_NOTIFICATION_OPTIONS.delete_if {|option| option.first == 'selected'}
269 MAIL_NOTIFICATION_OPTIONS.delete_if {|option| option.first == 'selected'}
270 else
270 else
271 MAIL_NOTIFICATION_OPTIONS
271 MAIL_NOTIFICATION_OPTIONS
272 end
272 end
273 end
273 end
274
274
275 # Find a user account by matching the exact login and then a case-insensitive
275 # Find a user account by matching the exact login and then a case-insensitive
276 # version. Exact matches will be given priority.
276 # version. Exact matches will be given priority.
277 def self.find_by_login(login)
277 def self.find_by_login(login)
278 # force string comparison to be case sensitive on MySQL
278 # force string comparison to be case sensitive on MySQL
279 type_cast = (ActiveRecord::Base.connection.adapter_name == 'MySQL') ? 'BINARY' : ''
279 type_cast = (ActiveRecord::Base.connection.adapter_name == 'MySQL') ? 'BINARY' : ''
280
280
281 # First look for an exact match
281 # First look for an exact match
282 user = first(:conditions => ["#{type_cast} login = ?", login])
282 user = first(:conditions => ["#{type_cast} login = ?", login])
283 # Fail over to case-insensitive if none was found
283 # Fail over to case-insensitive if none was found
284 user ||= first(:conditions => ["#{type_cast} LOWER(login) = ?", login.to_s.downcase])
284 user ||= first(:conditions => ["#{type_cast} LOWER(login) = ?", login.to_s.downcase])
285 end
285 end
286
286
287 def self.find_by_rss_key(key)
287 def self.find_by_rss_key(key)
288 token = Token.find_by_value(key)
288 token = Token.find_by_value(key)
289 token && token.user.active? ? token.user : nil
289 token && token.user.active? ? token.user : nil
290 end
290 end
291
291
292 def self.find_by_api_key(key)
292 def self.find_by_api_key(key)
293 token = Token.find_by_action_and_value('api', key)
293 token = Token.find_by_action_and_value('api', key)
294 token && token.user.active? ? token.user : nil
294 token && token.user.active? ? token.user : nil
295 end
295 end
296
296
297 # Makes find_by_mail case-insensitive
297 # Makes find_by_mail case-insensitive
298 def self.find_by_mail(mail)
298 def self.find_by_mail(mail)
299 find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase])
299 find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase])
300 end
300 end
301
301
302 def to_s
302 def to_s
303 name
303 name
304 end
304 end
305
305
306 # Returns the current day according to user's time zone
306 # Returns the current day according to user's time zone
307 def today
307 def today
308 if time_zone.nil?
308 if time_zone.nil?
309 Date.today
309 Date.today
310 else
310 else
311 Time.now.in_time_zone(time_zone).to_date
311 Time.now.in_time_zone(time_zone).to_date
312 end
312 end
313 end
313 end
314
314
315 def logged?
315 def logged?
316 true
316 true
317 end
317 end
318
318
319 def anonymous?
319 def anonymous?
320 !logged?
320 !logged?
321 end
321 end
322
322
323 # Return user's roles for project
323 # Return user's roles for project
324 def roles_for_project(project)
324 def roles_for_project(project)
325 roles = []
325 roles = []
326 # No role on archived projects
326 # No role on archived projects
327 return roles unless project && project.active?
327 return roles unless project && project.active?
328 if logged?
328 if logged?
329 # Find project membership
329 # Find project membership
330 membership = memberships.detect {|m| m.project_id == project.id}
330 membership = memberships.detect {|m| m.project_id == project.id}
331 if membership
331 if membership
332 roles = membership.roles
332 roles = membership.roles
333 else
333 else
334 @role_non_member ||= Role.non_member
334 @role_non_member ||= Role.non_member
335 roles << @role_non_member
335 roles << @role_non_member
336 end
336 end
337 else
337 else
338 @role_anonymous ||= Role.anonymous
338 @role_anonymous ||= Role.anonymous
339 roles << @role_anonymous
339 roles << @role_anonymous
340 end
340 end
341 roles
341 roles
342 end
342 end
343
343
344 # Return true if the user is a member of project
344 # Return true if the user is a member of project
345 def member_of?(project)
345 def member_of?(project)
346 !roles_for_project(project).detect {|role| role.member?}.nil?
346 !roles_for_project(project).detect {|role| role.member?}.nil?
347 end
347 end
348
348
349 # Return true if the user is allowed to do the specified action on a specific context
349 # Return true if the user is allowed to do the specified action on a specific context
350 # Action can be:
350 # Action can be:
351 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
351 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
352 # * a permission Symbol (eg. :edit_project)
352 # * a permission Symbol (eg. :edit_project)
353 # Context can be:
353 # Context can be:
354 # * a project : returns true if user is allowed to do the specified action on this project
354 # * a project : returns true if user is allowed to do the specified action on this project
355 # * a group of projects : returns true if user is allowed on every project
355 # * a group of projects : returns true if user is allowed on every project
356 # * nil with options[:global] set : check if user has at least one role allowed for this action,
356 # * nil with options[:global] set : check if user has at least one role allowed for this action,
357 # or falls back to Non Member / Anonymous permissions depending if the user is logged
357 # or falls back to Non Member / Anonymous permissions depending if the user is logged
358 def allowed_to?(action, context, options={})
358 def allowed_to?(action, context, options={})
359 if context && context.is_a?(Project)
359 if context && context.is_a?(Project)
360 # No action allowed on archived projects
360 # No action allowed on archived projects
361 return false unless context.active?
361 return false unless context.active?
362 # No action allowed on disabled modules
362 # No action allowed on disabled modules
363 return false unless context.allows_to?(action)
363 return false unless context.allows_to?(action)
364 # Admin users are authorized for anything else
364 # Admin users are authorized for anything else
365 return true if admin?
365 return true if admin?
366
366
367 roles = roles_for_project(context)
367 roles = roles_for_project(context)
368 return false unless roles
368 return false unless roles
369 roles.detect {|role| (context.is_public? || role.member?) && role.allowed_to?(action)}
369 roles.detect {|role| (context.is_public? || role.member?) && role.allowed_to?(action)}
370
370
371 elsif context && context.is_a?(Array)
371 elsif context && context.is_a?(Array)
372 # Authorize if user is authorized on every element of the array
372 # Authorize if user is authorized on every element of the array
373 context.map do |project|
373 context.map do |project|
374 allowed_to?(action,project,options)
374 allowed_to?(action,project,options)
375 end.inject do |memo,allowed|
375 end.inject do |memo,allowed|
376 memo && allowed
376 memo && allowed
377 end
377 end
378 elsif options[:global]
378 elsif options[:global]
379 # Admin users are always authorized
379 # Admin users are always authorized
380 return true if admin?
380 return true if admin?
381
381
382 # authorize if user has at least one role that has this permission
382 # authorize if user has at least one role that has this permission
383 roles = memberships.collect {|m| m.roles}.flatten.uniq
383 roles = memberships.collect {|m| m.roles}.flatten.uniq
384 roles.detect {|r| r.allowed_to?(action)} || (self.logged? ? Role.non_member.allowed_to?(action) : Role.anonymous.allowed_to?(action))
384 roles.detect {|r| r.allowed_to?(action)} || (self.logged? ? Role.non_member.allowed_to?(action) : Role.anonymous.allowed_to?(action))
385 else
385 else
386 false
386 false
387 end
387 end
388 end
388 end
389
389
390 # Is the user allowed to do the specified action on any project?
390 # Is the user allowed to do the specified action on any project?
391 # See allowed_to? for the actions and valid options.
391 # See allowed_to? for the actions and valid options.
392 def allowed_to_globally?(action, options)
392 def allowed_to_globally?(action, options)
393 allowed_to?(action, nil, options.reverse_merge(:global => true))
393 allowed_to?(action, nil, options.reverse_merge(:global => true))
394 end
394 end
395
395
396 safe_attributes 'login',
396 safe_attributes 'login',
397 'firstname',
397 'firstname',
398 'lastname',
398 'lastname',
399 'mail',
399 'mail',
400 'mail_notification',
400 'mail_notification',
401 'language',
401 'language',
402 'custom_field_values',
402 'custom_field_values',
403 'custom_fields',
403 'custom_fields',
404 'identity_url'
404 'identity_url'
405
405
406 safe_attributes 'status',
406 safe_attributes 'status',
407 'auth_source_id',
407 'auth_source_id',
408 :if => lambda {|user, current_user| current_user.admin?}
408 :if => lambda {|user, current_user| current_user.admin?}
409
409
410 safe_attributes 'group_ids',
411 :if => lambda {|user, current_user| current_user.admin? && !user.new_record?}
412
410 # Utility method to help check if a user should be notified about an
413 # Utility method to help check if a user should be notified about an
411 # event.
414 # event.
412 #
415 #
413 # TODO: only supports Issue events currently
416 # TODO: only supports Issue events currently
414 def notify_about?(object)
417 def notify_about?(object)
415 case mail_notification
418 case mail_notification
416 when 'all'
419 when 'all'
417 true
420 true
418 when 'selected'
421 when 'selected'
419 # Handled by the Project
422 # Handled by the Project
420 when 'none'
423 when 'none'
421 false
424 false
422 when 'only_my_events'
425 when 'only_my_events'
423 if object.is_a?(Issue) && (object.author == self || object.assigned_to == self)
426 if object.is_a?(Issue) && (object.author == self || object.assigned_to == self)
424 true
427 true
425 else
428 else
426 false
429 false
427 end
430 end
428 when 'only_assigned'
431 when 'only_assigned'
429 if object.is_a?(Issue) && object.assigned_to == self
432 if object.is_a?(Issue) && object.assigned_to == self
430 true
433 true
431 else
434 else
432 false
435 false
433 end
436 end
434 when 'only_owner'
437 when 'only_owner'
435 if object.is_a?(Issue) && object.author == self
438 if object.is_a?(Issue) && object.author == self
436 true
439 true
437 else
440 else
438 false
441 false
439 end
442 end
440 else
443 else
441 false
444 false
442 end
445 end
443 end
446 end
444
447
445 def self.current=(user)
448 def self.current=(user)
446 @current_user = user
449 @current_user = user
447 end
450 end
448
451
449 def self.current
452 def self.current
450 @current_user ||= User.anonymous
453 @current_user ||= User.anonymous
451 end
454 end
452
455
453 # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only
456 # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only
454 # one anonymous user per database.
457 # one anonymous user per database.
455 def self.anonymous
458 def self.anonymous
456 anonymous_user = AnonymousUser.find(:first)
459 anonymous_user = AnonymousUser.find(:first)
457 if anonymous_user.nil?
460 if anonymous_user.nil?
458 anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
461 anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
459 raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
462 raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
460 end
463 end
461 anonymous_user
464 anonymous_user
462 end
465 end
463
466
464 protected
467 protected
465
468
466 def validate
469 def validate
467 # Password length validation based on setting
470 # Password length validation based on setting
468 if !password.nil? && password.size < Setting.password_min_length.to_i
471 if !password.nil? && password.size < Setting.password_min_length.to_i
469 errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
472 errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
470 end
473 end
471 end
474 end
472
475
473 private
476 private
474
477
475 # Return password digest
478 # Return password digest
476 def self.hash_password(clear_password)
479 def self.hash_password(clear_password)
477 Digest::SHA1.hexdigest(clear_password || "")
480 Digest::SHA1.hexdigest(clear_password || "")
478 end
481 end
479 end
482 end
480
483
481 class AnonymousUser < User
484 class AnonymousUser < User
482
485
483 def validate_on_create
486 def validate_on_create
484 # There should be only one AnonymousUser in the database
487 # There should be only one AnonymousUser in the database
485 errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first)
488 errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first)
486 end
489 end
487
490
488 def available_custom_fields
491 def available_custom_fields
489 []
492 []
490 end
493 end
491
494
492 # Overrides a few properties
495 # Overrides a few properties
493 def logged?; false end
496 def logged?; false end
494 def admin; false end
497 def admin; false end
495 def name(*args); I18n.t(:label_user_anonymous) end
498 def name(*args); I18n.t(:label_user_anonymous) end
496 def mail; nil end
499 def mail; nil end
497 def time_zone; nil end
500 def time_zone; nil end
498 def rss_key; nil end
501 def rss_key; nil end
499 end
502 end
@@ -1,200 +1,207
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19 require 'my_controller'
19 require 'my_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class MyController; def rescue_action(e) raise e end; end
22 class MyController; def rescue_action(e) raise e end; end
23
23
24 class MyControllerTest < ActionController::TestCase
24 class MyControllerTest < ActionController::TestCase
25 fixtures :users, :user_preferences, :roles, :projects, :issues, :issue_statuses, :trackers, :enumerations, :custom_fields
25 fixtures :users, :user_preferences, :roles, :projects, :issues, :issue_statuses, :trackers, :enumerations, :custom_fields
26
26
27 def setup
27 def setup
28 @controller = MyController.new
28 @controller = MyController.new
29 @request = ActionController::TestRequest.new
29 @request = ActionController::TestRequest.new
30 @request.session[:user_id] = 2
30 @request.session[:user_id] = 2
31 @response = ActionController::TestResponse.new
31 @response = ActionController::TestResponse.new
32 end
32 end
33
33
34 def test_index
34 def test_index
35 get :index
35 get :index
36 assert_response :success
36 assert_response :success
37 assert_template 'page'
37 assert_template 'page'
38 end
38 end
39
39
40 def test_page
40 def test_page
41 get :page
41 get :page
42 assert_response :success
42 assert_response :success
43 assert_template 'page'
43 assert_template 'page'
44 end
44 end
45
45
46 def test_my_account_should_show_editable_custom_fields
46 def test_my_account_should_show_editable_custom_fields
47 get :account
47 get :account
48 assert_response :success
48 assert_response :success
49 assert_template 'account'
49 assert_template 'account'
50 assert_equal User.find(2), assigns(:user)
50 assert_equal User.find(2), assigns(:user)
51
51
52 assert_tag :input, :attributes => { :name => 'user[custom_field_values][4]'}
52 assert_tag :input, :attributes => { :name => 'user[custom_field_values][4]'}
53 end
53 end
54
54
55 def test_my_account_should_not_show_non_editable_custom_fields
55 def test_my_account_should_not_show_non_editable_custom_fields
56 UserCustomField.find(4).update_attribute :editable, false
56 UserCustomField.find(4).update_attribute :editable, false
57
57
58 get :account
58 get :account
59 assert_response :success
59 assert_response :success
60 assert_template 'account'
60 assert_template 'account'
61 assert_equal User.find(2), assigns(:user)
61 assert_equal User.find(2), assigns(:user)
62
62
63 assert_no_tag :input, :attributes => { :name => 'user[custom_field_values][4]'}
63 assert_no_tag :input, :attributes => { :name => 'user[custom_field_values][4]'}
64 end
64 end
65
65
66 def test_update_account
66 def test_update_account
67 post :account, :user => {:firstname => "Joe",
67 post :account,
68 :login => "root",
68 :user => {
69 :admin => 1,
69 :firstname => "Joe",
70 :custom_field_values => {"4" => "0100562500"}}
70 :login => "root",
71 :admin => 1,
72 :group_ids => ['10'],
73 :custom_field_values => {"4" => "0100562500"}
74 }
75
71 assert_redirected_to '/my/account'
76 assert_redirected_to '/my/account'
72 user = User.find(2)
77 user = User.find(2)
73 assert_equal user, assigns(:user)
78 assert_equal user, assigns(:user)
74 assert_equal "Joe", user.firstname
79 assert_equal "Joe", user.firstname
75 assert_equal "jsmith", user.login
80 assert_equal "jsmith", user.login
76 assert_equal "0100562500", user.custom_value_for(4).value
81 assert_equal "0100562500", user.custom_value_for(4).value
82 # ignored
77 assert !user.admin?
83 assert !user.admin?
84 assert user.groups.empty?
78 end
85 end
79
86
80 def test_change_password
87 def test_change_password
81 get :password
88 get :password
82 assert_response :success
89 assert_response :success
83 assert_template 'password'
90 assert_template 'password'
84
91
85 # non matching password confirmation
92 # non matching password confirmation
86 post :password, :password => 'jsmith',
93 post :password, :password => 'jsmith',
87 :new_password => 'hello',
94 :new_password => 'hello',
88 :new_password_confirmation => 'hello2'
95 :new_password_confirmation => 'hello2'
89 assert_response :success
96 assert_response :success
90 assert_template 'password'
97 assert_template 'password'
91 assert_tag :tag => "div", :attributes => { :class => "errorExplanation" }
98 assert_tag :tag => "div", :attributes => { :class => "errorExplanation" }
92
99
93 # wrong password
100 # wrong password
94 post :password, :password => 'wrongpassword',
101 post :password, :password => 'wrongpassword',
95 :new_password => 'hello',
102 :new_password => 'hello',
96 :new_password_confirmation => 'hello'
103 :new_password_confirmation => 'hello'
97 assert_response :success
104 assert_response :success
98 assert_template 'password'
105 assert_template 'password'
99 assert_equal 'Wrong password', flash[:error]
106 assert_equal 'Wrong password', flash[:error]
100
107
101 # good password
108 # good password
102 post :password, :password => 'jsmith',
109 post :password, :password => 'jsmith',
103 :new_password => 'hello',
110 :new_password => 'hello',
104 :new_password_confirmation => 'hello'
111 :new_password_confirmation => 'hello'
105 assert_redirected_to '/my/account'
112 assert_redirected_to '/my/account'
106 assert User.try_to_login('jsmith', 'hello')
113 assert User.try_to_login('jsmith', 'hello')
107 end
114 end
108
115
109 def test_page_layout
116 def test_page_layout
110 get :page_layout
117 get :page_layout
111 assert_response :success
118 assert_response :success
112 assert_template 'page_layout'
119 assert_template 'page_layout'
113 end
120 end
114
121
115 def test_add_block
122 def test_add_block
116 xhr :post, :add_block, :block => 'issuesreportedbyme'
123 xhr :post, :add_block, :block => 'issuesreportedbyme'
117 assert_response :success
124 assert_response :success
118 assert User.find(2).pref[:my_page_layout]['top'].include?('issuesreportedbyme')
125 assert User.find(2).pref[:my_page_layout]['top'].include?('issuesreportedbyme')
119 end
126 end
120
127
121 def test_remove_block
128 def test_remove_block
122 xhr :post, :remove_block, :block => 'issuesassignedtome'
129 xhr :post, :remove_block, :block => 'issuesassignedtome'
123 assert_response :success
130 assert_response :success
124 assert !User.find(2).pref[:my_page_layout].values.flatten.include?('issuesassignedtome')
131 assert !User.find(2).pref[:my_page_layout].values.flatten.include?('issuesassignedtome')
125 end
132 end
126
133
127 def test_order_blocks
134 def test_order_blocks
128 xhr :post, :order_blocks, :group => 'left', 'list-left' => ['documents', 'calendar', 'latestnews']
135 xhr :post, :order_blocks, :group => 'left', 'list-left' => ['documents', 'calendar', 'latestnews']
129 assert_response :success
136 assert_response :success
130 assert_equal ['documents', 'calendar', 'latestnews'], User.find(2).pref[:my_page_layout]['left']
137 assert_equal ['documents', 'calendar', 'latestnews'], User.find(2).pref[:my_page_layout]['left']
131 end
138 end
132
139
133 context "POST to reset_rss_key" do
140 context "POST to reset_rss_key" do
134 context "with an existing rss_token" do
141 context "with an existing rss_token" do
135 setup do
142 setup do
136 @previous_token_value = User.find(2).rss_key # Will generate one if it's missing
143 @previous_token_value = User.find(2).rss_key # Will generate one if it's missing
137 post :reset_rss_key
144 post :reset_rss_key
138 end
145 end
139
146
140 should "destroy the existing token" do
147 should "destroy the existing token" do
141 assert_not_equal @previous_token_value, User.find(2).rss_key
148 assert_not_equal @previous_token_value, User.find(2).rss_key
142 end
149 end
143
150
144 should "create a new token" do
151 should "create a new token" do
145 assert User.find(2).rss_token
152 assert User.find(2).rss_token
146 end
153 end
147
154
148 should_set_the_flash_to /reset/
155 should_set_the_flash_to /reset/
149 should_redirect_to('my account') {'/my/account' }
156 should_redirect_to('my account') {'/my/account' }
150 end
157 end
151
158
152 context "with no rss_token" do
159 context "with no rss_token" do
153 setup do
160 setup do
154 assert_nil User.find(2).rss_token
161 assert_nil User.find(2).rss_token
155 post :reset_rss_key
162 post :reset_rss_key
156 end
163 end
157
164
158 should "create a new token" do
165 should "create a new token" do
159 assert User.find(2).rss_token
166 assert User.find(2).rss_token
160 end
167 end
161
168
162 should_set_the_flash_to /reset/
169 should_set_the_flash_to /reset/
163 should_redirect_to('my account') {'/my/account' }
170 should_redirect_to('my account') {'/my/account' }
164 end
171 end
165 end
172 end
166
173
167 context "POST to reset_api_key" do
174 context "POST to reset_api_key" do
168 context "with an existing api_token" do
175 context "with an existing api_token" do
169 setup do
176 setup do
170 @previous_token_value = User.find(2).api_key # Will generate one if it's missing
177 @previous_token_value = User.find(2).api_key # Will generate one if it's missing
171 post :reset_api_key
178 post :reset_api_key
172 end
179 end
173
180
174 should "destroy the existing token" do
181 should "destroy the existing token" do
175 assert_not_equal @previous_token_value, User.find(2).api_key
182 assert_not_equal @previous_token_value, User.find(2).api_key
176 end
183 end
177
184
178 should "create a new token" do
185 should "create a new token" do
179 assert User.find(2).api_token
186 assert User.find(2).api_token
180 end
187 end
181
188
182 should_set_the_flash_to /reset/
189 should_set_the_flash_to /reset/
183 should_redirect_to('my account') {'/my/account' }
190 should_redirect_to('my account') {'/my/account' }
184 end
191 end
185
192
186 context "with no api_token" do
193 context "with no api_token" do
187 setup do
194 setup do
188 assert_nil User.find(2).api_token
195 assert_nil User.find(2).api_token
189 post :reset_api_key
196 post :reset_api_key
190 end
197 end
191
198
192 should "create a new token" do
199 should "create a new token" do
193 assert User.find(2).api_token
200 assert User.find(2).api_token
194 end
201 end
195
202
196 should_set_the_flash_to /reset/
203 should_set_the_flash_to /reset/
197 should_redirect_to('my account') {'/my/account' }
204 should_redirect_to('my account') {'/my/account' }
198 end
205 end
199 end
206 end
200 end
207 end
@@ -1,240 +1,247
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19 require 'users_controller'
19 require 'users_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class UsersController; def rescue_action(e) raise e end; end
22 class UsersController; def rescue_action(e) raise e end; end
23
23
24 class UsersControllerTest < ActionController::TestCase
24 class UsersControllerTest < ActionController::TestCase
25 include Redmine::I18n
25 include Redmine::I18n
26
26
27 fixtures :users, :projects, :members, :member_roles, :roles, :auth_sources, :custom_fields, :custom_values
27 fixtures :users, :projects, :members, :member_roles, :roles, :auth_sources, :custom_fields, :custom_values
28
28
29 def setup
29 def setup
30 @controller = UsersController.new
30 @controller = UsersController.new
31 @request = ActionController::TestRequest.new
31 @request = ActionController::TestRequest.new
32 @response = ActionController::TestResponse.new
32 @response = ActionController::TestResponse.new
33 User.current = nil
33 User.current = nil
34 @request.session[:user_id] = 1 # admin
34 @request.session[:user_id] = 1 # admin
35 end
35 end
36
36
37 def test_index
37 def test_index
38 get :index
38 get :index
39 assert_response :success
39 assert_response :success
40 assert_template 'index'
40 assert_template 'index'
41 end
41 end
42
42
43 def test_index
43 def test_index
44 get :index
44 get :index
45 assert_response :success
45 assert_response :success
46 assert_template 'index'
46 assert_template 'index'
47 assert_not_nil assigns(:users)
47 assert_not_nil assigns(:users)
48 # active users only
48 # active users only
49 assert_nil assigns(:users).detect {|u| !u.active?}
49 assert_nil assigns(:users).detect {|u| !u.active?}
50 end
50 end
51
51
52 def test_index_with_name_filter
52 def test_index_with_name_filter
53 get :index, :name => 'john'
53 get :index, :name => 'john'
54 assert_response :success
54 assert_response :success
55 assert_template 'index'
55 assert_template 'index'
56 users = assigns(:users)
56 users = assigns(:users)
57 assert_not_nil users
57 assert_not_nil users
58 assert_equal 1, users.size
58 assert_equal 1, users.size
59 assert_equal 'John', users.first.firstname
59 assert_equal 'John', users.first.firstname
60 end
60 end
61
61
62 def test_show
62 def test_show
63 @request.session[:user_id] = nil
63 @request.session[:user_id] = nil
64 get :show, :id => 2
64 get :show, :id => 2
65 assert_response :success
65 assert_response :success
66 assert_template 'show'
66 assert_template 'show'
67 assert_not_nil assigns(:user)
67 assert_not_nil assigns(:user)
68
68
69 assert_tag 'li', :content => /Phone number/
69 assert_tag 'li', :content => /Phone number/
70 end
70 end
71
71
72 def test_show_should_not_display_hidden_custom_fields
72 def test_show_should_not_display_hidden_custom_fields
73 @request.session[:user_id] = nil
73 @request.session[:user_id] = nil
74 UserCustomField.find_by_name('Phone number').update_attribute :visible, false
74 UserCustomField.find_by_name('Phone number').update_attribute :visible, false
75 get :show, :id => 2
75 get :show, :id => 2
76 assert_response :success
76 assert_response :success
77 assert_template 'show'
77 assert_template 'show'
78 assert_not_nil assigns(:user)
78 assert_not_nil assigns(:user)
79
79
80 assert_no_tag 'li', :content => /Phone number/
80 assert_no_tag 'li', :content => /Phone number/
81 end
81 end
82
82
83 def test_show_should_not_fail_when_custom_values_are_nil
83 def test_show_should_not_fail_when_custom_values_are_nil
84 user = User.find(2)
84 user = User.find(2)
85
85
86 # Create a custom field to illustrate the issue
86 # Create a custom field to illustrate the issue
87 custom_field = CustomField.create!(:name => 'Testing', :field_format => 'text')
87 custom_field = CustomField.create!(:name => 'Testing', :field_format => 'text')
88 custom_value = user.custom_values.build(:custom_field => custom_field).save!
88 custom_value = user.custom_values.build(:custom_field => custom_field).save!
89
89
90 get :show, :id => 2
90 get :show, :id => 2
91 assert_response :success
91 assert_response :success
92 end
92 end
93
93
94 def test_show_inactive
94 def test_show_inactive
95 @request.session[:user_id] = nil
95 @request.session[:user_id] = nil
96 get :show, :id => 5
96 get :show, :id => 5
97 assert_response 404
97 assert_response 404
98 end
98 end
99
99
100 def test_show_should_not_reveal_users_with_no_visible_activity_or_project
100 def test_show_should_not_reveal_users_with_no_visible_activity_or_project
101 @request.session[:user_id] = nil
101 @request.session[:user_id] = nil
102 get :show, :id => 9
102 get :show, :id => 9
103 assert_response 404
103 assert_response 404
104 end
104 end
105
105
106 def test_show_inactive_by_admin
106 def test_show_inactive_by_admin
107 @request.session[:user_id] = 1
107 @request.session[:user_id] = 1
108 get :show, :id => 5
108 get :show, :id => 5
109 assert_response 200
109 assert_response 200
110 assert_not_nil assigns(:user)
110 assert_not_nil assigns(:user)
111 end
111 end
112
112
113 def test_show_displays_memberships_based_on_project_visibility
113 def test_show_displays_memberships_based_on_project_visibility
114 @request.session[:user_id] = 1
114 @request.session[:user_id] = 1
115 get :show, :id => 2
115 get :show, :id => 2
116 assert_response :success
116 assert_response :success
117 memberships = assigns(:memberships)
117 memberships = assigns(:memberships)
118 assert_not_nil memberships
118 assert_not_nil memberships
119 project_ids = memberships.map(&:project_id)
119 project_ids = memberships.map(&:project_id)
120 assert project_ids.include?(2) #private project admin can see
120 assert project_ids.include?(2) #private project admin can see
121 end
121 end
122
122
123 context "GET :new" do
123 context "GET :new" do
124 setup do
124 setup do
125 get :new
125 get :new
126 end
126 end
127
127
128 should_assign_to :user
128 should_assign_to :user
129 should_respond_with :success
129 should_respond_with :success
130 should_render_template :new
130 should_render_template :new
131 end
131 end
132
132
133 context "POST :create" do
133 context "POST :create" do
134 context "when successful" do
134 context "when successful" do
135 setup do
135 setup do
136 post :create, :user => {
136 post :create, :user => {
137 :firstname => 'John',
137 :firstname => 'John',
138 :lastname => 'Doe',
138 :lastname => 'Doe',
139 :login => 'jdoe',
139 :login => 'jdoe',
140 :password => 'test',
140 :password => 'test',
141 :password_confirmation => 'test',
141 :password_confirmation => 'test',
142 :mail => 'jdoe@gmail.com',
142 :mail => 'jdoe@gmail.com',
143 :mail_notification => 'none'
143 :mail_notification => 'none'
144 }
144 }
145 end
145 end
146
146
147 should_assign_to :user
147 should_assign_to :user
148 should_respond_with :redirect
148 should_respond_with :redirect
149 should_redirect_to('user edit') { {:controller => 'users', :action => 'edit', :id => User.find_by_login('jdoe')}}
149 should_redirect_to('user edit') { {:controller => 'users', :action => 'edit', :id => User.find_by_login('jdoe')}}
150
150
151 should 'set the users mail notification' do
151 should 'set the users mail notification' do
152 user = User.last
152 user = User.last
153 assert_equal 'none', user.mail_notification
153 assert_equal 'none', user.mail_notification
154 end
154 end
155
155
156 should 'set the password' do
156 should 'set the password' do
157 user = User.first(:order => 'id DESC')
157 user = User.first(:order => 'id DESC')
158 assert user.check_password?('test')
158 assert user.check_password?('test')
159 end
159 end
160 end
160 end
161
161
162 context "when unsuccessful" do
162 context "when unsuccessful" do
163 setup do
163 setup do
164 post :create, :user => {}
164 post :create, :user => {}
165 end
165 end
166
166
167 should_assign_to :user
167 should_assign_to :user
168 should_respond_with :success
168 should_respond_with :success
169 should_render_template :new
169 should_render_template :new
170 end
170 end
171
171
172 end
172 end
173
173
174 def test_update
174 def test_update
175 ActionMailer::Base.deliveries.clear
175 ActionMailer::Base.deliveries.clear
176 put :update, :id => 2, :user => {:firstname => 'Changed', :mail_notification => 'only_assigned'}, :pref => {:hide_mail => '1', :comments_sorting => 'desc'}
176 put :update, :id => 2, :user => {:firstname => 'Changed', :mail_notification => 'only_assigned'}, :pref => {:hide_mail => '1', :comments_sorting => 'desc'}
177
177
178 user = User.find(2)
178 user = User.find(2)
179 assert_equal 'Changed', user.firstname
179 assert_equal 'Changed', user.firstname
180 assert_equal 'only_assigned', user.mail_notification
180 assert_equal 'only_assigned', user.mail_notification
181 assert_equal true, user.pref[:hide_mail]
181 assert_equal true, user.pref[:hide_mail]
182 assert_equal 'desc', user.pref[:comments_sorting]
182 assert_equal 'desc', user.pref[:comments_sorting]
183 assert ActionMailer::Base.deliveries.empty?
183 assert ActionMailer::Base.deliveries.empty?
184 end
184 end
185
185
186 def test_update_with_group_ids_should_assign_groups
187 put :update, :id => 2, :user => {:group_ids => ['10']}
188
189 user = User.find(2)
190 assert_equal [10], user.group_ids
191 end
192
186 def test_update_with_activation_should_send_a_notification
193 def test_update_with_activation_should_send_a_notification
187 u = User.new(:firstname => 'Foo', :lastname => 'Bar', :mail => 'foo.bar@somenet.foo', :language => 'fr')
194 u = User.new(:firstname => 'Foo', :lastname => 'Bar', :mail => 'foo.bar@somenet.foo', :language => 'fr')
188 u.login = 'foo'
195 u.login = 'foo'
189 u.status = User::STATUS_REGISTERED
196 u.status = User::STATUS_REGISTERED
190 u.save!
197 u.save!
191 ActionMailer::Base.deliveries.clear
198 ActionMailer::Base.deliveries.clear
192 Setting.bcc_recipients = '1'
199 Setting.bcc_recipients = '1'
193
200
194 put :update, :id => u.id, :user => {:status => User::STATUS_ACTIVE}
201 put :update, :id => u.id, :user => {:status => User::STATUS_ACTIVE}
195 assert u.reload.active?
202 assert u.reload.active?
196 mail = ActionMailer::Base.deliveries.last
203 mail = ActionMailer::Base.deliveries.last
197 assert_not_nil mail
204 assert_not_nil mail
198 assert_equal ['foo.bar@somenet.foo'], mail.bcc
205 assert_equal ['foo.bar@somenet.foo'], mail.bcc
199 assert mail.body.include?(ll('fr', :notice_account_activated))
206 assert mail.body.include?(ll('fr', :notice_account_activated))
200 end
207 end
201
208
202 def test_update_with_password_change_should_send_a_notification
209 def test_update_with_password_change_should_send_a_notification
203 ActionMailer::Base.deliveries.clear
210 ActionMailer::Base.deliveries.clear
204 Setting.bcc_recipients = '1'
211 Setting.bcc_recipients = '1'
205
212
206 put :update, :id => 2, :user => {:password => 'newpass', :password_confirmation => 'newpass'}, :send_information => '1'
213 put :update, :id => 2, :user => {:password => 'newpass', :password_confirmation => 'newpass'}, :send_information => '1'
207 u = User.find(2)
214 u = User.find(2)
208 assert u.check_password?('newpass')
215 assert u.check_password?('newpass')
209
216
210 mail = ActionMailer::Base.deliveries.last
217 mail = ActionMailer::Base.deliveries.last
211 assert_not_nil mail
218 assert_not_nil mail
212 assert_equal [u.mail], mail.bcc
219 assert_equal [u.mail], mail.bcc
213 assert mail.body.include?('newpass')
220 assert mail.body.include?('newpass')
214 end
221 end
215
222
216 test "put :update with a password change to an AuthSource user switching to Internal authentication" do
223 test "put :update with a password change to an AuthSource user switching to Internal authentication" do
217 # Configure as auth source
224 # Configure as auth source
218 u = User.find(2)
225 u = User.find(2)
219 u.auth_source = AuthSource.find(1)
226 u.auth_source = AuthSource.find(1)
220 u.save!
227 u.save!
221
228
222 put :update, :id => u.id, :user => {:auth_source_id => '', :password => 'newpass'}, :password_confirmation => 'newpass'
229 put :update, :id => u.id, :user => {:auth_source_id => '', :password => 'newpass'}, :password_confirmation => 'newpass'
223
230
224 assert_equal nil, u.reload.auth_source
231 assert_equal nil, u.reload.auth_source
225 assert u.check_password?('newpass')
232 assert u.check_password?('newpass')
226 end
233 end
227
234
228 def test_edit_membership
235 def test_edit_membership
229 post :edit_membership, :id => 2, :membership_id => 1,
236 post :edit_membership, :id => 2, :membership_id => 1,
230 :membership => { :role_ids => [2]}
237 :membership => { :role_ids => [2]}
231 assert_redirected_to :action => 'edit', :id => '2', :tab => 'memberships'
238 assert_redirected_to :action => 'edit', :id => '2', :tab => 'memberships'
232 assert_equal [2], Member.find(1).role_ids
239 assert_equal [2], Member.find(1).role_ids
233 end
240 end
234
241
235 def test_destroy_membership
242 def test_destroy_membership
236 post :destroy_membership, :id => 2, :membership_id => 1
243 post :destroy_membership, :id => 2, :membership_id => 1
237 assert_redirected_to :action => 'edit', :id => '2', :tab => 'memberships'
244 assert_redirected_to :action => 'edit', :id => '2', :tab => 'memberships'
238 assert_nil Member.find_by_id(1)
245 assert_nil Member.find_by_id(1)
239 end
246 end
240 end
247 end
General Comments 0
You need to be logged in to leave comments. Login now