##// END OF EJS Templates
Dry Users API responders....
Jean-Philippe Lang -
r4340:ea59d93dc82d
parent child
Show More
@@ -1,229 +1,225
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 @status = params[:status] ? params[:status].to_i : 1
33 @status = params[:status] ? params[:status].to_i : 1
34 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
34 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
35
35
36 unless params[:name].blank?
36 unless params[:name].blank?
37 name = "%#{params[:name].strip.downcase}%"
37 name = "%#{params[:name].strip.downcase}%"
38 c << ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ? OR LOWER(mail) LIKE ?", name, name, name, name]
38 c << ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ? OR LOWER(mail) LIKE ?", name, name, name, name]
39 end
39 end
40
40
41 @user_count = User.count(:conditions => c.conditions)
41 @user_count = User.count(:conditions => c.conditions)
42 @user_pages = Paginator.new self, @user_count,
42 @user_pages = Paginator.new self, @user_count,
43 per_page_option,
43 per_page_option,
44 params['page']
44 params['page']
45 @users = User.find :all,:order => sort_clause,
45 @users = User.find :all,:order => sort_clause,
46 :conditions => c.conditions,
46 :conditions => c.conditions,
47 :limit => @user_pages.items_per_page,
47 :limit => @user_pages.items_per_page,
48 :offset => @user_pages.current.offset
48 :offset => @user_pages.current.offset
49
49
50 respond_to do |format|
50 respond_to do |format|
51 format.html { render :layout => !request.xhr? }
51 format.html { render :layout => !request.xhr? }
52 format.json { render :template => 'users/index.apit' }
52 format.api { render :template => 'users/index.apit' }
53 format.xml { render :template => 'users/index.apit' }
54 end
53 end
55 end
54 end
56
55
57 def show
56 def show
58 @user = User.find(params[:id])
57 @user = User.find(params[:id])
59
58
60 # show projects based on current user visibility
59 # show projects based on current user visibility
61 @memberships = @user.memberships.all(:conditions => Project.visible_by(User.current))
60 @memberships = @user.memberships.all(:conditions => Project.visible_by(User.current))
62
61
63 events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
62 events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
64 @events_by_day = events.group_by(&:event_date)
63 @events_by_day = events.group_by(&:event_date)
65
64
66 unless User.current.admin?
65 unless User.current.admin?
67 if !@user.active? || (@user != User.current && @memberships.empty? && events.empty?)
66 if !@user.active? || (@user != User.current && @memberships.empty? && events.empty?)
68 render_404
67 render_404
69 return
68 return
70 end
69 end
71 end
70 end
72
71
73 respond_to do |format|
72 respond_to do |format|
74 format.html { render :layout => 'base' }
73 format.html { render :layout => 'base' }
75 format.json { render :template => 'users/show.apit' }
74 format.api { render :template => 'users/show.apit' }
76 format.xml { render :template => 'users/show.apit' }
77 end
75 end
78 rescue ActiveRecord::RecordNotFound
76 rescue ActiveRecord::RecordNotFound
79 render_404
77 render_404
80 end
78 end
81
79
82 def new
80 def new
83 @notification_options = User::MAIL_NOTIFICATION_OPTIONS
81 @notification_options = User::MAIL_NOTIFICATION_OPTIONS
84 @notification_option = Setting.default_notification_option
82 @notification_option = Setting.default_notification_option
85
83
86 @user = User.new(:language => Setting.default_language)
84 @user = User.new(:language => Setting.default_language)
87 @auth_sources = AuthSource.find(:all)
85 @auth_sources = AuthSource.find(:all)
88 end
86 end
89
87
90 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
88 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
91 def create
89 def create
92 @notification_options = User::MAIL_NOTIFICATION_OPTIONS
90 @notification_options = User::MAIL_NOTIFICATION_OPTIONS
93 @notification_option = Setting.default_notification_option
91 @notification_option = Setting.default_notification_option
94
92
95 @user = User.new(params[:user])
93 @user = User.new(params[:user])
96 @user.admin = params[:user][:admin] || false
94 @user.admin = params[:user][:admin] || false
97 @user.login = params[:user][:login]
95 @user.login = params[:user][:login]
98 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless @user.auth_source_id
96 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless @user.auth_source_id
99
97
100 # TODO: Similar to My#account
98 # TODO: Similar to My#account
101 @user.mail_notification = params[:notification_option] || 'only_my_events'
99 @user.mail_notification = params[:notification_option] || 'only_my_events'
102 @user.pref.attributes = params[:pref]
100 @user.pref.attributes = params[:pref]
103 @user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
101 @user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
104
102
105 if @user.save
103 if @user.save
106 @user.pref.save
104 @user.pref.save
107 @user.notified_project_ids = (params[:notification_option] == 'selected' ? params[:notified_project_ids] : [])
105 @user.notified_project_ids = (params[:notification_option] == 'selected' ? params[:notified_project_ids] : [])
108
106
109 Mailer.deliver_account_information(@user, params[:password]) if params[:send_information]
107 Mailer.deliver_account_information(@user, params[:password]) if params[:send_information]
110
108
111 respond_to do |format|
109 respond_to do |format|
112 format.html {
110 format.html {
113 flash[:notice] = l(:notice_successful_create)
111 flash[:notice] = l(:notice_successful_create)
114 redirect_to(params[:continue] ?
112 redirect_to(params[:continue] ?
115 {:controller => 'users', :action => 'new'} :
113 {:controller => 'users', :action => 'new'} :
116 {:controller => 'users', :action => 'edit', :id => @user}
114 {:controller => 'users', :action => 'edit', :id => @user}
117 )
115 )
118 }
116 }
119 format.json { render :template => 'users/show.apit', :status => :created, :location => user_url(@user) }
117 format.api { render :template => 'users/show.apit', :status => :created, :location => user_url(@user) }
120 format.xml { render :template => 'users/show.apit', :status => :created, :location => user_url(@user) }
121 end
118 end
122 else
119 else
123 @auth_sources = AuthSource.find(:all)
120 @auth_sources = AuthSource.find(:all)
124 @notification_option = @user.mail_notification
121 @notification_option = @user.mail_notification
125
122
126 respond_to do |format|
123 respond_to do |format|
127 format.html { render :action => 'new' }
124 format.html { render :action => 'new' }
128 format.json { render :json => {:errors => @user.errors}, :status => :unprocessable_entity, :layout => false }
125 format.json { render :json => {:errors => @user.errors}, :status => :unprocessable_entity, :layout => false }
129 format.xml { render :xml => @user.errors, :status => :unprocessable_entity, :layout => false }
126 format.xml { render :xml => @user.errors, :status => :unprocessable_entity, :layout => false }
130 end
127 end
131 end
128 end
132 end
129 end
133
130
134 def edit
131 def edit
135 @user = User.find(params[:id])
132 @user = User.find(params[:id])
136 @notification_options = @user.valid_notification_options
133 @notification_options = @user.valid_notification_options
137 @notification_option = @user.mail_notification
134 @notification_option = @user.mail_notification
138
135
139 @auth_sources = AuthSource.find(:all)
136 @auth_sources = AuthSource.find(:all)
140 @membership ||= Member.new
137 @membership ||= Member.new
141 end
138 end
142
139
143 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
140 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
144 def update
141 def update
145 @user = User.find(params[:id])
142 @user = User.find(params[:id])
146 @notification_options = @user.valid_notification_options
143 @notification_options = @user.valid_notification_options
147 @notification_option = @user.mail_notification
144 @notification_option = @user.mail_notification
148
145
149 @user.admin = params[:user][:admin] if params[:user][:admin]
146 @user.admin = params[:user][:admin] if params[:user][:admin]
150 @user.login = params[:user][:login] if params[:user][:login]
147 @user.login = params[:user][:login] if params[:user][:login]
151 if params[:password].present? && (@user.auth_source_id.nil? || params[:user][:auth_source_id].blank?)
148 if params[:password].present? && (@user.auth_source_id.nil? || params[:user][:auth_source_id].blank?)
152 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
149 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
153 end
150 end
154 @user.group_ids = params[:user][:group_ids] if params[:user][:group_ids]
151 @user.group_ids = params[:user][:group_ids] if params[:user][:group_ids]
155 @user.attributes = params[:user]
152 @user.attributes = params[:user]
156 # Was the account actived ? (do it before User#save clears the change)
153 # Was the account actived ? (do it before User#save clears the change)
157 was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
154 was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
158 # TODO: Similar to My#account
155 # TODO: Similar to My#account
159 @user.mail_notification = params[:notification_option] || 'only_my_events'
156 @user.mail_notification = params[:notification_option] || 'only_my_events'
160 @user.pref.attributes = params[:pref]
157 @user.pref.attributes = params[:pref]
161 @user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
158 @user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
162
159
163 if @user.save
160 if @user.save
164 @user.pref.save
161 @user.pref.save
165 @user.notified_project_ids = (params[:notification_option] == 'selected' ? params[:notified_project_ids] : [])
162 @user.notified_project_ids = (params[:notification_option] == 'selected' ? params[:notified_project_ids] : [])
166
163
167 if was_activated
164 if was_activated
168 Mailer.deliver_account_activated(@user)
165 Mailer.deliver_account_activated(@user)
169 elsif @user.active? && params[:send_information] && !params[:password].blank? && @user.auth_source_id.nil?
166 elsif @user.active? && params[:send_information] && !params[:password].blank? && @user.auth_source_id.nil?
170 Mailer.deliver_account_information(@user, params[:password])
167 Mailer.deliver_account_information(@user, params[:password])
171 end
168 end
172
169
173 respond_to do |format|
170 respond_to do |format|
174 format.html {
171 format.html {
175 flash[:notice] = l(:notice_successful_update)
172 flash[:notice] = l(:notice_successful_update)
176 redirect_to :back
173 redirect_to :back
177 }
174 }
178 format.json { head :ok }
175 format.api { head :ok }
179 format.xml { head :ok }
180 end
176 end
181 else
177 else
182 @auth_sources = AuthSource.find(:all)
178 @auth_sources = AuthSource.find(:all)
183 @membership ||= Member.new
179 @membership ||= Member.new
184
180
185 respond_to do |format|
181 respond_to do |format|
186 format.html { render :action => :edit }
182 format.html { render :action => :edit }
187 format.json { render :json => {:errors => @user.errors}, :status => :unprocessable_entity, :layout => false }
183 format.json { render :json => {:errors => @user.errors}, :status => :unprocessable_entity, :layout => false }
188 format.xml { render :xml => @user.errors, :status => :unprocessable_entity, :layout => false }
184 format.xml { render :xml => @user.errors, :status => :unprocessable_entity, :layout => false }
189 end
185 end
190 end
186 end
191 rescue ::ActionController::RedirectBackError
187 rescue ::ActionController::RedirectBackError
192 redirect_to :controller => 'users', :action => 'edit', :id => @user
188 redirect_to :controller => 'users', :action => 'edit', :id => @user
193 end
189 end
194
190
195 def edit_membership
191 def edit_membership
196 @user = User.find(params[:id])
192 @user = User.find(params[:id])
197 @membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
193 @membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
198 @membership.save if request.post?
194 @membership.save if request.post?
199 respond_to do |format|
195 respond_to do |format|
200 if @membership.valid?
196 if @membership.valid?
201 format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
197 format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
202 format.js {
198 format.js {
203 render(:update) {|page|
199 render(:update) {|page|
204 page.replace_html "tab-content-memberships", :partial => 'users/memberships'
200 page.replace_html "tab-content-memberships", :partial => 'users/memberships'
205 page.visual_effect(:highlight, "member-#{@membership.id}")
201 page.visual_effect(:highlight, "member-#{@membership.id}")
206 }
202 }
207 }
203 }
208 else
204 else
209 format.js {
205 format.js {
210 render(:update) {|page|
206 render(:update) {|page|
211 page.alert(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', ')))
207 page.alert(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', ')))
212 }
208 }
213 }
209 }
214 end
210 end
215 end
211 end
216 end
212 end
217
213
218 def destroy_membership
214 def destroy_membership
219 @user = User.find(params[:id])
215 @user = User.find(params[:id])
220 @membership = Member.find(params[:membership_id])
216 @membership = Member.find(params[:membership_id])
221 if request.post? && @membership.deletable?
217 if request.post? && @membership.deletable?
222 @membership.destroy
218 @membership.destroy
223 end
219 end
224 respond_to do |format|
220 respond_to do |format|
225 format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
221 format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
226 format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'users/memberships'} }
222 format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'users/memberships'} }
227 end
223 end
228 end
224 end
229 end
225 end
@@ -1,94 +1,104
1
1
2 require 'active_record'
2 require 'active_record'
3
3
4 module ActiveRecord
4 module ActiveRecord
5 class Base
5 class Base
6 include Redmine::I18n
6 include Redmine::I18n
7
7
8 # Translate attribute names for validation errors display
8 # Translate attribute names for validation errors display
9 def self.human_attribute_name(attr)
9 def self.human_attribute_name(attr)
10 l("field_#{attr.to_s.gsub(/_id$/, '')}")
10 l("field_#{attr.to_s.gsub(/_id$/, '')}")
11 end
11 end
12 end
12 end
13 end
13 end
14
14
15 module ActiveRecord
15 module ActiveRecord
16 class Errors
16 class Errors
17 def full_messages(options = {})
17 def full_messages(options = {})
18 full_messages = []
18 full_messages = []
19
19
20 @errors.each_key do |attr|
20 @errors.each_key do |attr|
21 @errors[attr].each do |message|
21 @errors[attr].each do |message|
22 next unless message
22 next unless message
23
23
24 if attr == "base"
24 if attr == "base"
25 full_messages << message
25 full_messages << message
26 elsif attr == "custom_values"
26 elsif attr == "custom_values"
27 # Replace the generic "custom values is invalid"
27 # Replace the generic "custom values is invalid"
28 # with the errors on custom values
28 # with the errors on custom values
29 @base.custom_values.each do |value|
29 @base.custom_values.each do |value|
30 value.errors.each do |attr, msg|
30 value.errors.each do |attr, msg|
31 full_messages << value.custom_field.name + ' ' + msg
31 full_messages << value.custom_field.name + ' ' + msg
32 end
32 end
33 end
33 end
34 else
34 else
35 attr_name = @base.class.human_attribute_name(attr)
35 attr_name = @base.class.human_attribute_name(attr)
36 full_messages << attr_name + ' ' + message.to_s
36 full_messages << attr_name + ' ' + message.to_s
37 end
37 end
38 end
38 end
39 end
39 end
40 full_messages
40 full_messages
41 end
41 end
42 end
42 end
43 end
43 end
44
44
45 module ActionView
45 module ActionView
46 module Helpers
46 module Helpers
47 module DateHelper
47 module DateHelper
48 # distance_of_time_in_words breaks when difference is greater than 30 years
48 # distance_of_time_in_words breaks when difference is greater than 30 years
49 def distance_of_date_in_words(from_date, to_date = 0, options = {})
49 def distance_of_date_in_words(from_date, to_date = 0, options = {})
50 from_date = from_date.to_date if from_date.respond_to?(:to_date)
50 from_date = from_date.to_date if from_date.respond_to?(:to_date)
51 to_date = to_date.to_date if to_date.respond_to?(:to_date)
51 to_date = to_date.to_date if to_date.respond_to?(:to_date)
52 distance_in_days = (to_date - from_date).abs
52 distance_in_days = (to_date - from_date).abs
53
53
54 I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
54 I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
55 case distance_in_days
55 case distance_in_days
56 when 0..60 then locale.t :x_days, :count => distance_in_days.round
56 when 0..60 then locale.t :x_days, :count => distance_in_days.round
57 when 61..720 then locale.t :about_x_months, :count => (distance_in_days / 30).round
57 when 61..720 then locale.t :about_x_months, :count => (distance_in_days / 30).round
58 else locale.t :over_x_years, :count => (distance_in_days / 365).floor
58 else locale.t :over_x_years, :count => (distance_in_days / 365).floor
59 end
59 end
60 end
60 end
61 end
61 end
62 end
62 end
63 end
63 end
64 end
64 end
65
65
66 ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" }
66 ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" }
67
67
68 # Adds :async_smtp and :async_sendmail delivery methods
68 # Adds :async_smtp and :async_sendmail delivery methods
69 # to perform email deliveries asynchronously
69 # to perform email deliveries asynchronously
70 module AsynchronousMailer
70 module AsynchronousMailer
71 %w(smtp sendmail).each do |type|
71 %w(smtp sendmail).each do |type|
72 define_method("perform_delivery_async_#{type}") do |mail|
72 define_method("perform_delivery_async_#{type}") do |mail|
73 Thread.start do
73 Thread.start do
74 send "perform_delivery_#{type}", mail
74 send "perform_delivery_#{type}", mail
75 end
75 end
76 end
76 end
77 end
77 end
78 end
78 end
79
79
80 ActionMailer::Base.send :include, AsynchronousMailer
80 ActionMailer::Base.send :include, AsynchronousMailer
81
81
82 # TODO: Hack to support i18n 4.x on Rails 2.3.5. Remove post 2.3.6.
82 # TODO: Hack to support i18n 4.x on Rails 2.3.5. Remove post 2.3.6.
83 # See http://www.redmine.org/issues/6428 and http://www.redmine.org/issues/5608
83 # See http://www.redmine.org/issues/6428 and http://www.redmine.org/issues/5608
84 module I18n
84 module I18n
85 module Backend
85 module Backend
86 module Base
86 module Base
87 def warn_syntax_deprecation!(*args)
87 def warn_syntax_deprecation!(*args)
88 return if @skip_syntax_deprecation
88 return if @skip_syntax_deprecation
89 warn "The {{key}} interpolation syntax in I18n messages is deprecated. Please use %{key} instead.\nDowngrade your i18n gem to 0.3.7 (everything above must be deinstalled) to remove this warning, see http://www.redmine.org/issues/5608 for more information."
89 warn "The {{key}} interpolation syntax in I18n messages is deprecated. Please use %{key} instead.\nDowngrade your i18n gem to 0.3.7 (everything above must be deinstalled) to remove this warning, see http://www.redmine.org/issues/5608 for more information."
90 @skip_syntax_deprecation = true
90 @skip_syntax_deprecation = true
91 end
91 end
92 end
92 end
93 end
93 end
94 end
94 end
95
96 module ActionController
97 module MimeResponds
98 class Responder
99 def api(&block)
100 any(:xml, :json, &block)
101 end
102 end
103 end
104 end
General Comments 0
You need to be logged in to leave comments. Login now