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.

10-patches.rb 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. # frozen_string_literal: true
  2. module ActiveRecord
  3. class Base
  4. # Translate attribute names for validation errors display
  5. def self.human_attribute_name(attr, options = {})
  6. prepared_attr = attr.to_s.sub(/_id$/, '').sub(/^.+\./, '')
  7. class_prefix = name.underscore.tr('/', '_')
  8. redmine_default = [
  9. :"field_#{class_prefix}_#{prepared_attr}",
  10. :"field_#{prepared_attr}"
  11. ]
  12. options[:default] = redmine_default + Array(options[:default])
  13. super
  14. end
  15. end
  16. # Undefines private Kernel#open method to allow using `open` scopes in models.
  17. # See Defect #11545 (http://www.redmine.org/issues/11545) for details.
  18. class Base
  19. class << self
  20. undef open
  21. end
  22. end
  23. class Relation ; undef open ; end
  24. end
  25. module ActionView
  26. module Helpers
  27. module DateHelper
  28. # distance_of_time_in_words breaks when difference is greater than 30 years
  29. def distance_of_date_in_words(from_date, to_date = 0, options = {})
  30. from_date = from_date.to_date if from_date.respond_to?(:to_date)
  31. to_date = to_date.to_date if to_date.respond_to?(:to_date)
  32. distance_in_days = (to_date - from_date).abs
  33. I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
  34. case distance_in_days
  35. when 0..60 then locale.t :x_days, :count => distance_in_days.round
  36. when 61..720 then locale.t :about_x_months, :count => (distance_in_days / 30).round
  37. else locale.t :over_x_years, :count => (distance_in_days / 365).floor
  38. end
  39. end
  40. end
  41. end
  42. end
  43. class Resolver
  44. def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[])
  45. locals = locals.map(&:to_s).sort!.freeze
  46. cached(key, [name, prefix, partial], details, locals) do
  47. if (details[:formats] & [:xml, :json]).any?
  48. details = details.dup
  49. details[:formats] = details[:formats].dup + [:api]
  50. end
  51. _find_all(name, prefix, partial, details, key, locals)
  52. end
  53. end
  54. end
  55. end
  56. ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| html_tag || ''.html_safe }
  57. # HTML5: <option value=""></option> is invalid, use <option value="">&nbsp;</option> instead
  58. module ActionView
  59. module Helpers
  60. module Tags
  61. class Base
  62. private
  63. alias :add_options_without_non_empty_blank_option :add_options
  64. def add_options(option_tags, options, value = nil)
  65. if options[:include_blank] == true
  66. options = options.dup
  67. options[:include_blank] = '&nbsp;'.html_safe
  68. end
  69. add_options_without_non_empty_blank_option(option_tags, options, value)
  70. end
  71. end
  72. end
  73. module FormTagHelper
  74. alias :select_tag_without_non_empty_blank_option :select_tag
  75. def select_tag(name, option_tags = nil, options = {})
  76. if options.delete(:include_blank)
  77. options[:prompt] = '&nbsp;'.html_safe
  78. end
  79. select_tag_without_non_empty_blank_option(name, option_tags, options)
  80. end
  81. end
  82. module FormOptionsHelper
  83. alias :options_for_select_without_non_empty_blank_option :options_for_select
  84. def options_for_select(container, selected = nil)
  85. if container.is_a?(Array)
  86. container = container.map {|element| element.presence || ["&nbsp;".html_safe, ""]}
  87. end
  88. options_for_select_without_non_empty_blank_option(container, selected)
  89. end
  90. end
  91. end
  92. end
  93. require 'mail'
  94. module DeliveryMethods
  95. class TmpFile
  96. def initialize(*args); end
  97. def deliver!(mail)
  98. dest_dir = File.join(Rails.root, 'tmp', 'emails')
  99. Dir.mkdir(dest_dir) unless File.directory?(dest_dir)
  100. filename = "#{Time.now.to_i}_#{mail.message_id.gsub(/[<>]/, '')}.eml"
  101. File.open(File.join(dest_dir, filename), 'wb') {|f| f.write(mail.encoded) }
  102. end
  103. end
  104. end
  105. ActionMailer::Base.add_delivery_method :tmp_file, DeliveryMethods::TmpFile
  106. module ActionController
  107. module MimeResponds
  108. class Collector
  109. def api(&block)
  110. any(:xml, :json, &block)
  111. end
  112. end
  113. end
  114. end
  115. module ActionController
  116. class Base
  117. # Displays an explicit message instead of a NoMethodError exception
  118. # when trying to start Redmine with an old session_store.rb
  119. # TODO: remove it in a later version
  120. def self.session=(*args)
  121. $stderr.puts "Please remove config/initializers/session_store.rb and run `rake generate_secret_token`.\n" +
  122. "Setting the session secret with ActionController.session= is no longer supported."
  123. exit 1
  124. end
  125. end
  126. end
  127. # Adds asset_id parameters to assets like Rails 3 to invalidate caches in browser
  128. module ActionView
  129. module Helpers
  130. module AssetUrlHelper
  131. @@cache_asset_timestamps = Rails.env.production?
  132. @@asset_timestamps_cache = {}
  133. @@asset_timestamps_cache_guard = Mutex.new
  134. def asset_path_with_asset_id(source, options = {})
  135. asset_id = rails_asset_id(source, options)
  136. unless asset_id.blank?
  137. source += "?#{asset_id}"
  138. end
  139. asset_path(source, options.merge(skip_pipeline: true))
  140. end
  141. alias :path_to_asset :asset_path_with_asset_id
  142. def rails_asset_id(source, options = {})
  143. if asset_id = ENV["RAILS_ASSET_ID"]
  144. asset_id
  145. else
  146. if @@cache_asset_timestamps && (asset_id = @@asset_timestamps_cache[source])
  147. asset_id
  148. else
  149. extname = compute_asset_extname(source, options)
  150. path = File.join(Rails.public_path, "#{source}#{extname}")
  151. exist = false
  152. if File.exist? path
  153. exist = true
  154. else
  155. path = File.join(Rails.public_path, public_compute_asset_path("#{source}#{extname}", options))
  156. if File.exist? path
  157. exist = true
  158. end
  159. end
  160. asset_id = exist ? File.mtime(path).to_i.to_s : ''
  161. if @@cache_asset_timestamps
  162. @@asset_timestamps_cache_guard.synchronize do
  163. @@asset_timestamps_cache[source] = asset_id
  164. end
  165. end
  166. asset_id
  167. end
  168. end
  169. end
  170. end
  171. end
  172. end
  173. # https://github.com/rack/rack/pull/1703
  174. # TODO: remove this when Rack is updated to 3.0.0
  175. require 'rack'
  176. module Rack
  177. class RewindableInput
  178. unless method_defined?(:size)
  179. def size
  180. make_rewindable unless @rewindable_io
  181. @rewindable_io.size
  182. end
  183. end
  184. end
  185. end