You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

setting.rb 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. # Redmine - project management software
  2. # Copyright (C) 2006-2017 Jean-Philippe Lang
  3. #
  4. # This program is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU General Public License
  6. # as published by the Free Software Foundation; either version 2
  7. # of the License, or (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  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
  16. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. class Setting < ActiveRecord::Base
  18. DATE_FORMATS = [
  19. '%Y-%m-%d',
  20. '%d/%m/%Y',
  21. '%d.%m.%Y',
  22. '%d-%m-%Y',
  23. '%m/%d/%Y',
  24. '%d %b %Y',
  25. '%d %B %Y',
  26. '%b %d, %Y',
  27. '%B %d, %Y'
  28. ]
  29. TIME_FORMATS = [
  30. '%H:%M',
  31. '%I:%M %p'
  32. ]
  33. ENCODINGS = %w(US-ASCII
  34. windows-1250
  35. windows-1251
  36. windows-1252
  37. windows-1253
  38. windows-1254
  39. windows-1255
  40. windows-1256
  41. windows-1257
  42. windows-1258
  43. windows-31j
  44. ISO-2022-JP
  45. ISO-2022-KR
  46. ISO-8859-1
  47. ISO-8859-2
  48. ISO-8859-3
  49. ISO-8859-4
  50. ISO-8859-5
  51. ISO-8859-6
  52. ISO-8859-7
  53. ISO-8859-8
  54. ISO-8859-9
  55. ISO-8859-13
  56. ISO-8859-15
  57. KOI8-R
  58. UTF-8
  59. UTF-16
  60. UTF-16BE
  61. UTF-16LE
  62. EUC-JP
  63. Shift_JIS
  64. CP932
  65. GB18030
  66. GBK
  67. ISCII91
  68. EUC-KR
  69. Big5
  70. Big5-HKSCS
  71. TIS-620)
  72. cattr_accessor :available_settings
  73. self.available_settings ||= {}
  74. validates_uniqueness_of :name, :if => Proc.new {|setting| setting.new_record? || setting.name_changed?}
  75. validates_inclusion_of :name, :in => Proc.new {available_settings.keys}
  76. validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting|
  77. (s = available_settings[setting.name]) && s['format'] == 'int'
  78. }
  79. # Hash used to cache setting values
  80. @cached_settings = {}
  81. @cached_cleared_on = Time.now
  82. def value
  83. v = read_attribute(:value)
  84. # Unserialize serialized settings
  85. if available_settings[name]['serialized'] && v.is_a?(String)
  86. v = YAML::load(v)
  87. v = force_utf8_strings(v)
  88. end
  89. v = v.to_sym if available_settings[name]['format'] == 'symbol' && !v.blank?
  90. v
  91. end
  92. def value=(v)
  93. v = v.to_yaml if v && available_settings[name] && available_settings[name]['serialized']
  94. write_attribute(:value, v.to_s)
  95. end
  96. # Returns the value of the setting named name
  97. def self.[](name)
  98. v = @cached_settings[name]
  99. v ? v : (@cached_settings[name] = find_or_default(name).value)
  100. end
  101. def self.[]=(name, v)
  102. setting = find_or_default(name)
  103. setting.value = (v ? v : "")
  104. @cached_settings[name] = nil
  105. setting.save
  106. setting.value
  107. end
  108. # Updates multiple settings from params and sends a security notification if needed
  109. def self.set_all_from_params(settings)
  110. return nil unless settings.is_a?(Hash)
  111. settings = settings.dup.symbolize_keys
  112. errors = validate_all_from_params(settings)
  113. return errors if errors.present?
  114. changes = []
  115. settings.each do |name, value|
  116. next unless available_settings[name.to_s]
  117. previous_value = Setting[name]
  118. set_from_params name, value
  119. if available_settings[name.to_s]['security_notifications'] && Setting[name] != previous_value
  120. changes << name
  121. end
  122. end
  123. if changes.any?
  124. Mailer.deliver_settings_updated(User.current, changes)
  125. end
  126. nil
  127. end
  128. def self.validate_all_from_params(settings)
  129. messages = []
  130. [[:mail_handler_enable_regex_delimiters, :mail_handler_body_delimiters, /[\r\n]+/],
  131. [:mail_handler_enable_regex_excluded_filenames, :mail_handler_excluded_filenames, /\s*,\s*/]
  132. ].each do |enable_regex, regex_field, delimiter|
  133. if settings.key?(regex_field) || settings.key?(enable_regex)
  134. regexp = Setting.send("#{enable_regex}?")
  135. if settings.key?(enable_regex)
  136. regexp = settings[enable_regex].to_s != '0'
  137. end
  138. if regexp
  139. settings[regex_field].to_s.split(delimiter).each do |value|
  140. begin
  141. Regexp.new(value)
  142. rescue RegexpError => e
  143. messages << [regex_field, "#{l('activerecord.errors.messages.not_a_regexp')} (#{e.message})"]
  144. end
  145. end
  146. end
  147. end
  148. end
  149. messages
  150. end
  151. # Sets a setting value from params
  152. def self.set_from_params(name, params)
  153. params = params.dup
  154. params.delete_if {|v| v.blank? } if params.is_a?(Array)
  155. params.symbolize_keys! if params.is_a?(Hash)
  156. m = "#{name}_from_params"
  157. if respond_to? m
  158. self[name.to_sym] = send m, params
  159. else
  160. self[name.to_sym] = params
  161. end
  162. end
  163. # Returns a hash suitable for commit_update_keywords setting
  164. #
  165. # Example:
  166. # params = {:keywords => ['fixes', 'closes'], :status_id => ["3", "5"], :done_ratio => ["", "100"]}
  167. # Setting.commit_update_keywords_from_params(params)
  168. # # => [{'keywords => 'fixes', 'status_id' => "3"}, {'keywords => 'closes', 'status_id' => "5", 'done_ratio' => "100"}]
  169. def self.commit_update_keywords_from_params(params)
  170. s = []
  171. if params.is_a?(Hash) && params.key?(:keywords) && params.values.all? {|v| v.is_a? Array}
  172. attributes = params.except(:keywords).keys
  173. params[:keywords].each_with_index do |keywords, i|
  174. next if keywords.blank?
  175. s << attributes.inject({}) {|h, a|
  176. value = params[a][i].to_s
  177. h[a.to_s] = value if value.present?
  178. h
  179. }.merge('keywords' => keywords)
  180. end
  181. end
  182. s
  183. end
  184. # Helper that returns an array based on per_page_options setting
  185. def self.per_page_options_array
  186. per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort
  187. end
  188. # Helper that returns a Hash with single update keywords as keys
  189. def self.commit_update_keywords_array
  190. a = []
  191. if commit_update_keywords.is_a?(Array)
  192. commit_update_keywords.each do |rule|
  193. next unless rule.is_a?(Hash)
  194. rule = rule.dup
  195. rule.delete_if {|k, v| v.blank?}
  196. keywords = rule['keywords'].to_s.downcase.split(",").map(&:strip).reject(&:blank?)
  197. next if keywords.empty?
  198. a << rule.merge('keywords' => keywords)
  199. end
  200. end
  201. a
  202. end
  203. def self.openid?
  204. Object.const_defined?(:OpenID) && self[:openid].to_i > 0
  205. end
  206. # Checks if settings have changed since the values were read
  207. # and clears the cache hash if it's the case
  208. # Called once per request
  209. def self.check_cache
  210. settings_updated_on = Setting.maximum(:updated_on)
  211. if settings_updated_on && @cached_cleared_on <= settings_updated_on
  212. clear_cache
  213. end
  214. end
  215. # Clears the settings cache
  216. def self.clear_cache
  217. @cached_settings.clear
  218. @cached_cleared_on = Time.now
  219. logger.info "Settings cache cleared." if logger
  220. end
  221. def self.define_plugin_setting(plugin)
  222. if plugin.settings
  223. name = "plugin_#{plugin.id}"
  224. define_setting name, {'default' => plugin.settings[:default], 'serialized' => true}
  225. end
  226. end
  227. # Defines getter and setter for each setting
  228. # Then setting values can be read using: Setting.some_setting_name
  229. # or set using Setting.some_setting_name = "some value"
  230. def self.define_setting(name, options={})
  231. available_settings[name.to_s] = options
  232. src = <<-END_SRC
  233. def self.#{name}
  234. self[:#{name}]
  235. end
  236. def self.#{name}?
  237. self[:#{name}].to_i > 0
  238. end
  239. def self.#{name}=(value)
  240. self[:#{name}] = value
  241. end
  242. END_SRC
  243. class_eval src, __FILE__, __LINE__
  244. end
  245. def self.load_available_settings
  246. YAML::load(File.open("#{Rails.root}/config/settings.yml")).each do |name, options|
  247. define_setting name, options
  248. end
  249. end
  250. def self.load_plugin_settings
  251. Redmine::Plugin.all.each do |plugin|
  252. define_plugin_setting(plugin)
  253. end
  254. end
  255. load_available_settings
  256. load_plugin_settings
  257. private
  258. def force_utf8_strings(arg)
  259. if arg.is_a?(String)
  260. arg.dup.force_encoding('UTF-8')
  261. elsif arg.is_a?(Array)
  262. arg.map do |a|
  263. force_utf8_strings(a)
  264. end
  265. elsif arg.is_a?(Hash)
  266. arg = arg.dup
  267. arg.each do |k,v|
  268. arg[k] = force_utf8_strings(v)
  269. end
  270. arg
  271. else
  272. arg
  273. end
  274. end
  275. # Returns the Setting instance for the setting named name
  276. # (record found in database or new record with default value)
  277. def self.find_or_default(name)
  278. name = name.to_s
  279. raise "There's no setting named #{name}" unless available_settings.has_key?(name)
  280. setting = where(:name => name).order(:id => :desc).first
  281. unless setting
  282. setting = new
  283. setting.name = name
  284. setting.value = available_settings[name]['default']
  285. end
  286. setting
  287. end
  288. end