##// END OF EJS Templates
Don't error if an invalid setting is given....
Jean-Philippe Lang -
r15348:596a196f2e7e
parent child
Show More
@@ -1,293 +1,295
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 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 Setting < ActiveRecord::Base
18 class Setting < ActiveRecord::Base
19
19
20 DATE_FORMATS = [
20 DATE_FORMATS = [
21 '%Y-%m-%d',
21 '%Y-%m-%d',
22 '%d/%m/%Y',
22 '%d/%m/%Y',
23 '%d.%m.%Y',
23 '%d.%m.%Y',
24 '%d-%m-%Y',
24 '%d-%m-%Y',
25 '%m/%d/%Y',
25 '%m/%d/%Y',
26 '%d %b %Y',
26 '%d %b %Y',
27 '%d %B %Y',
27 '%d %B %Y',
28 '%b %d, %Y',
28 '%b %d, %Y',
29 '%B %d, %Y'
29 '%B %d, %Y'
30 ]
30 ]
31
31
32 TIME_FORMATS = [
32 TIME_FORMATS = [
33 '%H:%M',
33 '%H:%M',
34 '%I:%M %p'
34 '%I:%M %p'
35 ]
35 ]
36
36
37 ENCODINGS = %w(US-ASCII
37 ENCODINGS = %w(US-ASCII
38 windows-1250
38 windows-1250
39 windows-1251
39 windows-1251
40 windows-1252
40 windows-1252
41 windows-1253
41 windows-1253
42 windows-1254
42 windows-1254
43 windows-1255
43 windows-1255
44 windows-1256
44 windows-1256
45 windows-1257
45 windows-1257
46 windows-1258
46 windows-1258
47 windows-31j
47 windows-31j
48 ISO-2022-JP
48 ISO-2022-JP
49 ISO-2022-KR
49 ISO-2022-KR
50 ISO-8859-1
50 ISO-8859-1
51 ISO-8859-2
51 ISO-8859-2
52 ISO-8859-3
52 ISO-8859-3
53 ISO-8859-4
53 ISO-8859-4
54 ISO-8859-5
54 ISO-8859-5
55 ISO-8859-6
55 ISO-8859-6
56 ISO-8859-7
56 ISO-8859-7
57 ISO-8859-8
57 ISO-8859-8
58 ISO-8859-9
58 ISO-8859-9
59 ISO-8859-13
59 ISO-8859-13
60 ISO-8859-15
60 ISO-8859-15
61 KOI8-R
61 KOI8-R
62 UTF-8
62 UTF-8
63 UTF-16
63 UTF-16
64 UTF-16BE
64 UTF-16BE
65 UTF-16LE
65 UTF-16LE
66 EUC-JP
66 EUC-JP
67 Shift_JIS
67 Shift_JIS
68 CP932
68 CP932
69 GB18030
69 GB18030
70 GBK
70 GBK
71 ISCII91
71 ISCII91
72 EUC-KR
72 EUC-KR
73 Big5
73 Big5
74 Big5-HKSCS
74 Big5-HKSCS
75 TIS-620)
75 TIS-620)
76
76
77 cattr_accessor :available_settings
77 cattr_accessor :available_settings
78 self.available_settings ||= {}
78 self.available_settings ||= {}
79
79
80 validates_uniqueness_of :name, :if => Proc.new {|setting| setting.new_record? || setting.name_changed?}
80 validates_uniqueness_of :name, :if => Proc.new {|setting| setting.new_record? || setting.name_changed?}
81 validates_inclusion_of :name, :in => Proc.new {available_settings.keys}
81 validates_inclusion_of :name, :in => Proc.new {available_settings.keys}
82 validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting|
82 validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting|
83 (s = available_settings[setting.name]) && s['format'] == 'int'
83 (s = available_settings[setting.name]) && s['format'] == 'int'
84 }
84 }
85 attr_protected :id
85 attr_protected :id
86
86
87 # Hash used to cache setting values
87 # Hash used to cache setting values
88 @cached_settings = {}
88 @cached_settings = {}
89 @cached_cleared_on = Time.now
89 @cached_cleared_on = Time.now
90
90
91 def value
91 def value
92 v = read_attribute(:value)
92 v = read_attribute(:value)
93 # Unserialize serialized settings
93 # Unserialize serialized settings
94 if available_settings[name]['serialized'] && v.is_a?(String)
94 if available_settings[name]['serialized'] && v.is_a?(String)
95 v = YAML::load(v)
95 v = YAML::load(v)
96 v = force_utf8_strings(v)
96 v = force_utf8_strings(v)
97 end
97 end
98 v = v.to_sym if available_settings[name]['format'] == 'symbol' && !v.blank?
98 v = v.to_sym if available_settings[name]['format'] == 'symbol' && !v.blank?
99 v
99 v
100 end
100 end
101
101
102 def value=(v)
102 def value=(v)
103 v = v.to_yaml if v && available_settings[name] && available_settings[name]['serialized']
103 v = v.to_yaml if v && available_settings[name] && available_settings[name]['serialized']
104 write_attribute(:value, v.to_s)
104 write_attribute(:value, v.to_s)
105 end
105 end
106
106
107 # Returns the value of the setting named name
107 # Returns the value of the setting named name
108 def self.[](name)
108 def self.[](name)
109 v = @cached_settings[name]
109 v = @cached_settings[name]
110 v ? v : (@cached_settings[name] = find_or_default(name).value)
110 v ? v : (@cached_settings[name] = find_or_default(name).value)
111 end
111 end
112
112
113 def self.[]=(name, v)
113 def self.[]=(name, v)
114 setting = find_or_default(name)
114 setting = find_or_default(name)
115 setting.value = (v ? v : "")
115 setting.value = (v ? v : "")
116 @cached_settings[name] = nil
116 @cached_settings[name] = nil
117 setting.save
117 setting.save
118 setting.value
118 setting.value
119 end
119 end
120
120
121 # Updates multiple settings from params and sends a security notification if needed
121 # Updates multiple settings from params and sends a security notification if needed
122 def self.set_all_from_params(settings)
122 def self.set_all_from_params(settings)
123 settings = (settings || {}).dup.symbolize_keys
123 return false unless settings.is_a?(Hash)
124 settings = settings.dup.symbolize_keys
124 changes = []
125 changes = []
125 settings.each do |name, value|
126 settings.each do |name, value|
127 next unless available_settings[name.to_s]
126 previous_value = Setting[name]
128 previous_value = Setting[name]
127 set_from_params name, value
129 set_from_params name, value
128 if available_settings[name.to_s]['security_notifications'] && Setting[name] != previous_value
130 if available_settings[name.to_s]['security_notifications'] && Setting[name] != previous_value
129 changes << name
131 changes << name
130 end
132 end
131 end
133 end
132 if changes.any?
134 if changes.any?
133 Mailer.security_settings_updated(changes)
135 Mailer.security_settings_updated(changes)
134 end
136 end
135 true
137 true
136 end
138 end
137
139
138 # Sets a setting value from params
140 # Sets a setting value from params
139 def self.set_from_params(name, params)
141 def self.set_from_params(name, params)
140 params = params.dup
142 params = params.dup
141 params.delete_if {|v| v.blank? } if params.is_a?(Array)
143 params.delete_if {|v| v.blank? } if params.is_a?(Array)
142 params.symbolize_keys! if params.is_a?(Hash)
144 params.symbolize_keys! if params.is_a?(Hash)
143
145
144 m = "#{name}_from_params"
146 m = "#{name}_from_params"
145 if respond_to? m
147 if respond_to? m
146 self[name.to_sym] = send m, params
148 self[name.to_sym] = send m, params
147 else
149 else
148 self[name.to_sym] = params
150 self[name.to_sym] = params
149 end
151 end
150 end
152 end
151
153
152 # Returns a hash suitable for commit_update_keywords setting
154 # Returns a hash suitable for commit_update_keywords setting
153 #
155 #
154 # Example:
156 # Example:
155 # params = {:keywords => ['fixes', 'closes'], :status_id => ["3", "5"], :done_ratio => ["", "100"]}
157 # params = {:keywords => ['fixes', 'closes'], :status_id => ["3", "5"], :done_ratio => ["", "100"]}
156 # Setting.commit_update_keywords_from_params(params)
158 # Setting.commit_update_keywords_from_params(params)
157 # # => [{'keywords => 'fixes', 'status_id' => "3"}, {'keywords => 'closes', 'status_id' => "5", 'done_ratio' => "100"}]
159 # # => [{'keywords => 'fixes', 'status_id' => "3"}, {'keywords => 'closes', 'status_id' => "5", 'done_ratio' => "100"}]
158 def self.commit_update_keywords_from_params(params)
160 def self.commit_update_keywords_from_params(params)
159 s = []
161 s = []
160 if params.is_a?(Hash) && params.key?(:keywords) && params.values.all? {|v| v.is_a? Array}
162 if params.is_a?(Hash) && params.key?(:keywords) && params.values.all? {|v| v.is_a? Array}
161 attributes = params.except(:keywords).keys
163 attributes = params.except(:keywords).keys
162 params[:keywords].each_with_index do |keywords, i|
164 params[:keywords].each_with_index do |keywords, i|
163 next if keywords.blank?
165 next if keywords.blank?
164 s << attributes.inject({}) {|h, a|
166 s << attributes.inject({}) {|h, a|
165 value = params[a][i].to_s
167 value = params[a][i].to_s
166 h[a.to_s] = value if value.present?
168 h[a.to_s] = value if value.present?
167 h
169 h
168 }.merge('keywords' => keywords)
170 }.merge('keywords' => keywords)
169 end
171 end
170 end
172 end
171 s
173 s
172 end
174 end
173
175
174 # Helper that returns an array based on per_page_options setting
176 # Helper that returns an array based on per_page_options setting
175 def self.per_page_options_array
177 def self.per_page_options_array
176 per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort
178 per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort
177 end
179 end
178
180
179 # Helper that returns a Hash with single update keywords as keys
181 # Helper that returns a Hash with single update keywords as keys
180 def self.commit_update_keywords_array
182 def self.commit_update_keywords_array
181 a = []
183 a = []
182 if commit_update_keywords.is_a?(Array)
184 if commit_update_keywords.is_a?(Array)
183 commit_update_keywords.each do |rule|
185 commit_update_keywords.each do |rule|
184 next unless rule.is_a?(Hash)
186 next unless rule.is_a?(Hash)
185 rule = rule.dup
187 rule = rule.dup
186 rule.delete_if {|k, v| v.blank?}
188 rule.delete_if {|k, v| v.blank?}
187 keywords = rule['keywords'].to_s.downcase.split(",").map(&:strip).reject(&:blank?)
189 keywords = rule['keywords'].to_s.downcase.split(",").map(&:strip).reject(&:blank?)
188 next if keywords.empty?
190 next if keywords.empty?
189 a << rule.merge('keywords' => keywords)
191 a << rule.merge('keywords' => keywords)
190 end
192 end
191 end
193 end
192 a
194 a
193 end
195 end
194
196
195 def self.openid?
197 def self.openid?
196 Object.const_defined?(:OpenID) && self[:openid].to_i > 0
198 Object.const_defined?(:OpenID) && self[:openid].to_i > 0
197 end
199 end
198
200
199 # Checks if settings have changed since the values were read
201 # Checks if settings have changed since the values were read
200 # and clears the cache hash if it's the case
202 # and clears the cache hash if it's the case
201 # Called once per request
203 # Called once per request
202 def self.check_cache
204 def self.check_cache
203 settings_updated_on = Setting.maximum(:updated_on)
205 settings_updated_on = Setting.maximum(:updated_on)
204 if settings_updated_on && @cached_cleared_on <= settings_updated_on
206 if settings_updated_on && @cached_cleared_on <= settings_updated_on
205 clear_cache
207 clear_cache
206 end
208 end
207 end
209 end
208
210
209 # Clears the settings cache
211 # Clears the settings cache
210 def self.clear_cache
212 def self.clear_cache
211 @cached_settings.clear
213 @cached_settings.clear
212 @cached_cleared_on = Time.now
214 @cached_cleared_on = Time.now
213 logger.info "Settings cache cleared." if logger
215 logger.info "Settings cache cleared." if logger
214 end
216 end
215
217
216 def self.define_plugin_setting(plugin)
218 def self.define_plugin_setting(plugin)
217 if plugin.settings
219 if plugin.settings
218 name = "plugin_#{plugin.id}"
220 name = "plugin_#{plugin.id}"
219 define_setting name, {'default' => plugin.settings[:default], 'serialized' => true}
221 define_setting name, {'default' => plugin.settings[:default], 'serialized' => true}
220 end
222 end
221 end
223 end
222
224
223 # Defines getter and setter for each setting
225 # Defines getter and setter for each setting
224 # Then setting values can be read using: Setting.some_setting_name
226 # Then setting values can be read using: Setting.some_setting_name
225 # or set using Setting.some_setting_name = "some value"
227 # or set using Setting.some_setting_name = "some value"
226 def self.define_setting(name, options={})
228 def self.define_setting(name, options={})
227 available_settings[name.to_s] = options
229 available_settings[name.to_s] = options
228
230
229 src = <<-END_SRC
231 src = <<-END_SRC
230 def self.#{name}
232 def self.#{name}
231 self[:#{name}]
233 self[:#{name}]
232 end
234 end
233
235
234 def self.#{name}?
236 def self.#{name}?
235 self[:#{name}].to_i > 0
237 self[:#{name}].to_i > 0
236 end
238 end
237
239
238 def self.#{name}=(value)
240 def self.#{name}=(value)
239 self[:#{name}] = value
241 self[:#{name}] = value
240 end
242 end
241 END_SRC
243 END_SRC
242 class_eval src, __FILE__, __LINE__
244 class_eval src, __FILE__, __LINE__
243 end
245 end
244
246
245 def self.load_available_settings
247 def self.load_available_settings
246 YAML::load(File.open("#{Rails.root}/config/settings.yml")).each do |name, options|
248 YAML::load(File.open("#{Rails.root}/config/settings.yml")).each do |name, options|
247 define_setting name, options
249 define_setting name, options
248 end
250 end
249 end
251 end
250
252
251 def self.load_plugin_settings
253 def self.load_plugin_settings
252 Redmine::Plugin.all.each do |plugin|
254 Redmine::Plugin.all.each do |plugin|
253 define_plugin_setting(plugin)
255 define_plugin_setting(plugin)
254 end
256 end
255 end
257 end
256
258
257 load_available_settings
259 load_available_settings
258 load_plugin_settings
260 load_plugin_settings
259
261
260 private
262 private
261
263
262 def force_utf8_strings(arg)
264 def force_utf8_strings(arg)
263 if arg.is_a?(String)
265 if arg.is_a?(String)
264 arg.dup.force_encoding('UTF-8')
266 arg.dup.force_encoding('UTF-8')
265 elsif arg.is_a?(Array)
267 elsif arg.is_a?(Array)
266 arg.map do |a|
268 arg.map do |a|
267 force_utf8_strings(a)
269 force_utf8_strings(a)
268 end
270 end
269 elsif arg.is_a?(Hash)
271 elsif arg.is_a?(Hash)
270 arg = arg.dup
272 arg = arg.dup
271 arg.each do |k,v|
273 arg.each do |k,v|
272 arg[k] = force_utf8_strings(v)
274 arg[k] = force_utf8_strings(v)
273 end
275 end
274 arg
276 arg
275 else
277 else
276 arg
278 arg
277 end
279 end
278 end
280 end
279
281
280 # Returns the Setting instance for the setting named name
282 # Returns the Setting instance for the setting named name
281 # (record found in database or new record with default value)
283 # (record found in database or new record with default value)
282 def self.find_or_default(name)
284 def self.find_or_default(name)
283 name = name.to_s
285 name = name.to_s
284 raise "There's no setting named #{name}" unless available_settings.has_key?(name)
286 raise "There's no setting named #{name}" unless available_settings.has_key?(name)
285 setting = where(:name => name).order(:id => :desc).first
287 setting = where(:name => name).order(:id => :desc).first
286 unless setting
288 unless setting
287 setting = new
289 setting = new
288 setting.name = name
290 setting.name = name
289 setting.value = available_settings[name]['default']
291 setting.value = available_settings[name]['default']
290 end
292 end
291 setting
293 setting
292 end
294 end
293 end
295 end
@@ -1,248 +1,257
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 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.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class SettingsControllerTest < Redmine::ControllerTest
20 class SettingsControllerTest < Redmine::ControllerTest
21 fixtures :projects, :trackers, :issue_statuses, :issues,
21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 :users
22 :users
23
23
24 def setup
24 def setup
25 User.current = nil
25 User.current = nil
26 @request.session[:user_id] = 1 # admin
26 @request.session[:user_id] = 1 # admin
27 end
27 end
28
28
29 def teardown
29 def teardown
30 Setting.delete_all
30 Setting.delete_all
31 Setting.clear_cache
31 Setting.clear_cache
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
37
38 assert_select 'input[name=?][value=?]', 'settings[app_title]', Setting.app_title
38 assert_select 'input[name=?][value=?]', 'settings[app_title]', Setting.app_title
39 end
39 end
40
40
41 def test_get_edit
41 def test_get_edit
42 get :edit
42 get :edit
43 assert_response :success
43 assert_response :success
44
44
45 assert_select 'input[name=?][value=""]', 'settings[enabled_scm][]'
45 assert_select 'input[name=?][value=""]', 'settings[enabled_scm][]'
46 end
46 end
47
47
48 def test_get_edit_should_preselect_default_issue_list_columns
48 def test_get_edit_should_preselect_default_issue_list_columns
49 with_settings :issue_list_default_columns => %w(tracker subject status updated_on) do
49 with_settings :issue_list_default_columns => %w(tracker subject status updated_on) do
50 get :edit
50 get :edit
51 assert_response :success
51 assert_response :success
52 end
52 end
53
53
54 assert_select 'select[id=selected_columns][name=?]', 'settings[issue_list_default_columns][]' do
54 assert_select 'select[id=selected_columns][name=?]', 'settings[issue_list_default_columns][]' do
55 assert_select 'option', 4
55 assert_select 'option', 4
56 assert_select 'option[value=tracker]', :text => 'Tracker'
56 assert_select 'option[value=tracker]', :text => 'Tracker'
57 assert_select 'option[value=subject]', :text => 'Subject'
57 assert_select 'option[value=subject]', :text => 'Subject'
58 assert_select 'option[value=status]', :text => 'Status'
58 assert_select 'option[value=status]', :text => 'Status'
59 assert_select 'option[value=updated_on]', :text => 'Updated'
59 assert_select 'option[value=updated_on]', :text => 'Updated'
60 end
60 end
61
61
62 assert_select 'select[id=available_columns]' do
62 assert_select 'select[id=available_columns]' do
63 assert_select 'option[value=tracker]', 0
63 assert_select 'option[value=tracker]', 0
64 assert_select 'option[value=priority]', :text => 'Priority'
64 assert_select 'option[value=priority]', :text => 'Priority'
65 end
65 end
66 end
66 end
67
67
68 def test_get_edit_without_trackers_should_succeed
68 def test_get_edit_without_trackers_should_succeed
69 Tracker.delete_all
69 Tracker.delete_all
70
70
71 get :edit
71 get :edit
72 assert_response :success
72 assert_response :success
73 end
73 end
74
74
75 def test_post_edit_notifications
75 def test_post_edit_notifications
76 post :edit, :params => {
76 post :edit, :params => {
77 :settings => {
77 :settings => {
78 :mail_from => 'functional@test.foo',
78 :mail_from => 'functional@test.foo',
79 :bcc_recipients => '0',
79 :bcc_recipients => '0',
80 :notified_events => %w(issue_added issue_updated news_added),
80 :notified_events => %w(issue_added issue_updated news_added),
81 :emails_footer => 'Test footer'
81 :emails_footer => 'Test footer'
82 }
82 }
83 }
83 }
84 assert_redirected_to '/settings'
84 assert_redirected_to '/settings'
85 assert_equal 'functional@test.foo', Setting.mail_from
85 assert_equal 'functional@test.foo', Setting.mail_from
86 assert !Setting.bcc_recipients?
86 assert !Setting.bcc_recipients?
87 assert_equal %w(issue_added issue_updated news_added), Setting.notified_events
87 assert_equal %w(issue_added issue_updated news_added), Setting.notified_events
88 assert_equal 'Test footer', Setting.emails_footer
88 assert_equal 'Test footer', Setting.emails_footer
89 end
89 end
90
90
91 def test_edit_commit_update_keywords
91 def test_edit_commit_update_keywords
92 with_settings :commit_update_keywords => [
92 with_settings :commit_update_keywords => [
93 {"keywords" => "fixes, resolves", "status_id" => "3"},
93 {"keywords" => "fixes, resolves", "status_id" => "3"},
94 {"keywords" => "closes", "status_id" => "5", "done_ratio" => "100", "if_tracker_id" => "2"}
94 {"keywords" => "closes", "status_id" => "5", "done_ratio" => "100", "if_tracker_id" => "2"}
95 ] do
95 ] do
96 get :edit
96 get :edit
97 end
97 end
98 assert_response :success
98 assert_response :success
99 assert_select 'tr.commit-keywords', 2
99 assert_select 'tr.commit-keywords', 2
100 assert_select 'tr.commit-keywords:nth-child(1)' do
100 assert_select 'tr.commit-keywords:nth-child(1)' do
101 assert_select 'input[name=?][value=?]', 'settings[commit_update_keywords][keywords][]', 'fixes, resolves'
101 assert_select 'input[name=?][value=?]', 'settings[commit_update_keywords][keywords][]', 'fixes, resolves'
102 assert_select 'select[name=?]', 'settings[commit_update_keywords][status_id][]' do
102 assert_select 'select[name=?]', 'settings[commit_update_keywords][status_id][]' do
103 assert_select 'option[value="3"][selected=selected]'
103 assert_select 'option[value="3"][selected=selected]'
104 end
104 end
105 end
105 end
106 assert_select 'tr.commit-keywords:nth-child(2)' do
106 assert_select 'tr.commit-keywords:nth-child(2)' do
107 assert_select 'input[name=?][value=?]', 'settings[commit_update_keywords][keywords][]', 'closes'
107 assert_select 'input[name=?][value=?]', 'settings[commit_update_keywords][keywords][]', 'closes'
108 assert_select 'select[name=?]', 'settings[commit_update_keywords][status_id][]' do
108 assert_select 'select[name=?]', 'settings[commit_update_keywords][status_id][]' do
109 assert_select 'option[value="5"][selected=selected]', :text => 'Closed'
109 assert_select 'option[value="5"][selected=selected]', :text => 'Closed'
110 end
110 end
111 assert_select 'select[name=?]', 'settings[commit_update_keywords][done_ratio][]' do
111 assert_select 'select[name=?]', 'settings[commit_update_keywords][done_ratio][]' do
112 assert_select 'option[value="100"][selected=selected]', :text => '100 %'
112 assert_select 'option[value="100"][selected=selected]', :text => '100 %'
113 end
113 end
114 assert_select 'select[name=?]', 'settings[commit_update_keywords][if_tracker_id][]' do
114 assert_select 'select[name=?]', 'settings[commit_update_keywords][if_tracker_id][]' do
115 assert_select 'option[value="2"][selected=selected]', :text => 'Feature request'
115 assert_select 'option[value="2"][selected=selected]', :text => 'Feature request'
116 end
116 end
117 end
117 end
118 end
118 end
119
119
120 def test_edit_without_commit_update_keywords_should_show_blank_line
120 def test_edit_without_commit_update_keywords_should_show_blank_line
121 with_settings :commit_update_keywords => [] do
121 with_settings :commit_update_keywords => [] do
122 get :edit
122 get :edit
123 end
123 end
124 assert_response :success
124 assert_response :success
125 assert_select 'tr.commit-keywords', 1 do
125 assert_select 'tr.commit-keywords', 1 do
126 assert_select 'input[name=?]:not([value])', 'settings[commit_update_keywords][keywords][]'
126 assert_select 'input[name=?]:not([value])', 'settings[commit_update_keywords][keywords][]'
127 end
127 end
128 end
128 end
129
129
130 def test_post_edit_commit_update_keywords
130 def test_post_edit_commit_update_keywords
131 post :edit, :params => {
131 post :edit, :params => {
132 :settings => {
132 :settings => {
133 :commit_update_keywords => {
133 :commit_update_keywords => {
134 :keywords => ["resolves", "closes"],
134 :keywords => ["resolves", "closes"],
135 :status_id => ["3", "5"],
135 :status_id => ["3", "5"],
136 :done_ratio => ["", "100"],
136 :done_ratio => ["", "100"],
137 :if_tracker_id => ["", "2"]
137 :if_tracker_id => ["", "2"]
138 }
138 }
139 }
139 }
140 }
140 }
141 assert_redirected_to '/settings'
141 assert_redirected_to '/settings'
142 assert_equal([
142 assert_equal([
143 {"keywords" => "resolves", "status_id" => "3"},
143 {"keywords" => "resolves", "status_id" => "3"},
144 {"keywords" => "closes", "status_id" => "5", "done_ratio" => "100", "if_tracker_id" => "2"}
144 {"keywords" => "closes", "status_id" => "5", "done_ratio" => "100", "if_tracker_id" => "2"}
145 ], Setting.commit_update_keywords)
145 ], Setting.commit_update_keywords)
146 end
146 end
147
147
148 def test_post_edit_with_invalid_setting_should_not_error
149 post :edit, :params => {
150 :settings => {
151 :invalid_setting => '1'
152 }
153 }
154 assert_redirected_to '/settings'
155 end
156
148 def test_post_edit_should_send_security_notification_for_notified_settings
157 def test_post_edit_should_send_security_notification_for_notified_settings
149 ActionMailer::Base.deliveries.clear
158 ActionMailer::Base.deliveries.clear
150 post :edit, :params => {
159 post :edit, :params => {
151 :settings => {
160 :settings => {
152 :login_required => 1
161 :login_required => 1
153 }
162 }
154 }
163 }
155 assert_not_nil (mail = ActionMailer::Base.deliveries.last)
164 assert_not_nil (mail = ActionMailer::Base.deliveries.last)
156 assert_mail_body_match '0.0.0.0', mail
165 assert_mail_body_match '0.0.0.0', mail
157 assert_mail_body_match I18n.t(:setting_login_required), mail
166 assert_mail_body_match I18n.t(:setting_login_required), mail
158 assert_select_email do
167 assert_select_email do
159 assert_select 'a[href^=?]', 'http://localhost:3000/settings'
168 assert_select 'a[href^=?]', 'http://localhost:3000/settings'
160 end
169 end
161 # All admins should receive this
170 # All admins should receive this
162 recipients = [mail.bcc, mail.cc].flatten
171 recipients = [mail.bcc, mail.cc].flatten
163 User.active.where(admin: true).each do |admin|
172 User.active.where(admin: true).each do |admin|
164 assert_include admin.mail, recipients
173 assert_include admin.mail, recipients
165 end
174 end
166 end
175 end
167
176
168 def test_post_edit_should_not_send_security_notification_for_non_notified_settings
177 def test_post_edit_should_not_send_security_notification_for_non_notified_settings
169 ActionMailer::Base.deliveries.clear
178 ActionMailer::Base.deliveries.clear
170 post :edit, :params => {
179 post :edit, :params => {
171 :settings => {
180 :settings => {
172 :app_title => 'MineRed'
181 :app_title => 'MineRed'
173 }
182 }
174 }
183 }
175 assert_nil (mail = ActionMailer::Base.deliveries.last)
184 assert_nil (mail = ActionMailer::Base.deliveries.last)
176 end
185 end
177
186
178 def test_post_edit_should_not_send_security_notification_for_unchanged_settings
187 def test_post_edit_should_not_send_security_notification_for_unchanged_settings
179 ActionMailer::Base.deliveries.clear
188 ActionMailer::Base.deliveries.clear
180 post :edit, :params => {
189 post :edit, :params => {
181 :settings => {
190 :settings => {
182 :login_required => 0
191 :login_required => 0
183 }
192 }
184 }
193 }
185 assert_nil (mail = ActionMailer::Base.deliveries.last)
194 assert_nil (mail = ActionMailer::Base.deliveries.last)
186 end
195 end
187
196
188
197
189 def test_get_plugin_settings
198 def test_get_plugin_settings
190 ActionController::Base.append_view_path(File.join(Rails.root, "test/fixtures/plugins"))
199 ActionController::Base.append_view_path(File.join(Rails.root, "test/fixtures/plugins"))
191 Redmine::Plugin.register :foo do
200 Redmine::Plugin.register :foo do
192 settings :partial => "foo_plugin/foo_plugin_settings"
201 settings :partial => "foo_plugin/foo_plugin_settings"
193 end
202 end
194 Setting.plugin_foo = {'sample_setting' => 'Plugin setting value'}
203 Setting.plugin_foo = {'sample_setting' => 'Plugin setting value'}
195
204
196 get :plugin, :params => {:id => 'foo'}
205 get :plugin, :params => {:id => 'foo'}
197 assert_response :success
206 assert_response :success
198
207
199 assert_select 'form[action="/settings/plugin/foo"]' do
208 assert_select 'form[action="/settings/plugin/foo"]' do
200 assert_select 'input[name=?][value=?]', 'settings[sample_setting]', 'Plugin setting value'
209 assert_select 'input[name=?][value=?]', 'settings[sample_setting]', 'Plugin setting value'
201 end
210 end
202 ensure
211 ensure
203 Redmine::Plugin.unregister(:foo)
212 Redmine::Plugin.unregister(:foo)
204 end
213 end
205
214
206 def test_get_invalid_plugin_settings
215 def test_get_invalid_plugin_settings
207 get :plugin, :params => {:id => 'none'}
216 get :plugin, :params => {:id => 'none'}
208 assert_response 404
217 assert_response 404
209 end
218 end
210
219
211 def test_get_non_configurable_plugin_settings
220 def test_get_non_configurable_plugin_settings
212 Redmine::Plugin.register(:foo) {}
221 Redmine::Plugin.register(:foo) {}
213
222
214 get :plugin, :params => {:id => 'foo'}
223 get :plugin, :params => {:id => 'foo'}
215 assert_response 404
224 assert_response 404
216
225
217 ensure
226 ensure
218 Redmine::Plugin.unregister(:foo)
227 Redmine::Plugin.unregister(:foo)
219 end
228 end
220
229
221 def test_post_plugin_settings
230 def test_post_plugin_settings
222 Redmine::Plugin.register(:foo) do
231 Redmine::Plugin.register(:foo) do
223 settings :partial => 'not blank', # so that configurable? is true
232 settings :partial => 'not blank', # so that configurable? is true
224 :default => {'sample_setting' => 'Plugin setting value'}
233 :default => {'sample_setting' => 'Plugin setting value'}
225 end
234 end
226
235
227 post :plugin, :params => {
236 post :plugin, :params => {
228 :id => 'foo',
237 :id => 'foo',
229 :settings => {'sample_setting' => 'Value'}
238 :settings => {'sample_setting' => 'Value'}
230 }
239 }
231 assert_redirected_to '/settings/plugin/foo'
240 assert_redirected_to '/settings/plugin/foo'
232
241
233 assert_equal({'sample_setting' => 'Value'}, Setting.plugin_foo)
242 assert_equal({'sample_setting' => 'Value'}, Setting.plugin_foo)
234 end
243 end
235
244
236 def test_post_non_configurable_plugin_settings
245 def test_post_non_configurable_plugin_settings
237 Redmine::Plugin.register(:foo) {}
246 Redmine::Plugin.register(:foo) {}
238
247
239 post :plugin, :params => {
248 post :plugin, :params => {
240 :id => 'foo',
249 :id => 'foo',
241 :settings => {'sample_setting' => 'Value'}
250 :settings => {'sample_setting' => 'Value'}
242 }
251 }
243 assert_response 404
252 assert_response 404
244
253
245 ensure
254 ensure
246 Redmine::Plugin.unregister(:foo)
255 Redmine::Plugin.unregister(:foo)
247 end
256 end
248 end
257 end
General Comments 0
You need to be logged in to leave comments. Login now