setting.rb 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
  2. class Setting < ApplicationModel
  3. store :options
  4. store :state_current
  5. store :state_initial
  6. store :preferences
  7. before_create :state_check, :set_initial, :check_broadcast
  8. before_update :state_check, :check_broadcast
  9. after_create :reset_change_id, :reset_cache
  10. after_update :reset_change_id, :reset_cache
  11. attr_accessor :state
  12. @@current = {} # rubocop:disable Style/ClassVars
  13. @@raw = {} # rubocop:disable Style/ClassVars
  14. @@change_id = nil # rubocop:disable Style/ClassVars
  15. @@last_changed_at = nil # rubocop:disable Style/ClassVars
  16. @@lookup_at = nil # rubocop:disable Style/ClassVars
  17. @@lookup_timeout = if ENV['ZAMMAD_SETTING_TTL'] # rubocop:disable Style/ClassVars
  18. ENV['ZAMMAD_SETTING_TTL'].to_i.seconds
  19. else
  20. 15.seconds
  21. end
  22. =begin
  23. set config setting
  24. Setting.set('some_config_name', some_value)
  25. =end
  26. def self.set(name, value)
  27. setting = Setting.find_by(name: name)
  28. if !setting
  29. raise "Can't find config setting '#{name}'"
  30. end
  31. setting.state_current = { value: value }
  32. setting.save!
  33. logger.info "Setting.set('#{name}', #{value.inspect})"
  34. true
  35. end
  36. =begin
  37. get config setting
  38. value = Setting.get('some_config_name')
  39. =end
  40. def self.get(name)
  41. load
  42. @@current[name].deep_dup # prevents accidental modification of settings in console
  43. end
  44. =begin
  45. reset config setting to default
  46. Setting.reset('some_config_name')
  47. Setting.reset('some_config_name', force) # true|false - force it false per default
  48. =end
  49. def self.reset(name, force = false)
  50. setting = Setting.find_by(name: name)
  51. if !setting
  52. raise "Can't find config setting '#{name}'"
  53. end
  54. return true if !force && setting.state_current == setting.state_initial
  55. setting.state_current = setting.state_initial
  56. setting.save!
  57. logger.info "Setting.reset('#{name}', #{setting.state_current.inspect})"
  58. true
  59. end
  60. =begin
  61. reload config settings
  62. Setting.reload
  63. =end
  64. def self.reload
  65. @@last_changed_at = nil # rubocop:disable Style/ClassVars
  66. load(true)
  67. end
  68. private
  69. # load values and cache them
  70. def self.load(force = false)
  71. # check if config is already generated
  72. return false if !force && @@current.present? && cache_valid?
  73. # read all or only changed since last read
  74. latest = Setting.order(updated_at: :desc).limit(1).pluck(:updated_at)
  75. settings = if @@last_changed_at && @@current.present?
  76. Setting.where('updated_at > ?', @@last_changed_at).order(:id).pluck(:name, :state_current)
  77. else
  78. Setting.order(:id).pluck(:name, :state_current)
  79. end
  80. if latest
  81. @@last_changed_at = latest[0] # rubocop:disable Style/ClassVars
  82. end
  83. if settings.present?
  84. settings.each do |setting|
  85. @@raw[setting[0]] = setting[1]['value']
  86. end
  87. @@raw.each do |key, value|
  88. if value.class != String
  89. @@current[key] = value
  90. next
  91. end
  92. @@current[key] = value.gsub(/\#\{config\.(.+?)\}/) do
  93. @@raw[$1].to_s
  94. end
  95. end
  96. end
  97. @@change_id = Cache.get('Setting::ChangeId') # rubocop:disable Style/ClassVars
  98. @@lookup_at = Time.now.to_i # rubocop:disable Style/ClassVars
  99. true
  100. end
  101. private_class_method :load
  102. # set initial value in state_initial
  103. def set_initial
  104. self.state_initial = state_current
  105. true
  106. end
  107. def reset_change_id
  108. @@current[name] = state_current[:value]
  109. change_id = rand(999_999_999).to_s
  110. logger.debug { "Setting.reset_change_id: set new cache, #{change_id}" }
  111. Cache.write('Setting::ChangeId', change_id, { expires_in: 24.hours })
  112. @@lookup_at = nil # rubocop:disable Style/ClassVars
  113. true
  114. end
  115. def reset_cache
  116. return true if preferences[:cache].blank?
  117. preferences[:cache].each do |key|
  118. Cache.delete(key)
  119. end
  120. true
  121. end
  122. # check if cache is still valid
  123. def self.cache_valid?
  124. if @@lookup_at && @@lookup_at > Time.now.to_i - @@lookup_timeout
  125. #logger.debug "Setting.cache_valid?: cache_id has been set within last #{@@lookup_timeout} seconds"
  126. return true
  127. end
  128. change_id = Cache.get('Setting::ChangeId')
  129. if @@change_id && change_id == @@change_id
  130. @@lookup_at = Time.now.to_i # rubocop:disable Style/ClassVars
  131. #logger.debug "Setting.cache_valid?: cache still valid, #{@@change_id}/#{change_id}"
  132. return true
  133. end
  134. #logger.debug "Setting.cache_valid?: cache has changed, #{@@change_id}/#{change_id}"
  135. false
  136. end
  137. private_class_method :cache_valid?
  138. # convert state into hash to be able to store it as store
  139. def state_check
  140. return true if state.nil? # allow false value
  141. return true if state.try(:key?, :value)
  142. self.state_current = { value: state }
  143. true
  144. end
  145. # notify clients about public config changes
  146. def check_broadcast
  147. return true if frontend != true
  148. value = state_current
  149. if state_current.key?(:value)
  150. value = state_current[:value]
  151. end
  152. Sessions.broadcast(
  153. {
  154. event: 'config_update',
  155. data: { name: name, value: value }
  156. },
  157. 'public'
  158. )
  159. true
  160. end
  161. end