setting.rb 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. # Copyright (C) 2012-2014 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_cache
  10. after_update :reset_cache
  11. after_destroy :reset_cache
  12. attr_accessor :state
  13. @@current = {} # rubocop:disable Style/ClassVars
  14. @@change_id = nil # rubocop:disable Style/ClassVars
  15. @@lookup_at = nil # rubocop:disable Style/ClassVars
  16. @@lookup_timeout = if ENV['ZAMMAD_SETTING_TTL'] # rubocop:disable Style/ClassVars
  17. ENV['ZAMMAD_SETTING_TTL'].to_i.seconds
  18. elsif Rails.env.production?
  19. 2.minutes
  20. else
  21. 15.seconds
  22. end
  23. =begin
  24. set config setting
  25. Setting.set('some_config_name', some_value)
  26. =end
  27. def self.set(name, value)
  28. setting = Setting.find_by(name: name)
  29. if !setting
  30. raise "Can't find config setting '#{name}'"
  31. end
  32. setting.state_current = { value: value }
  33. setting.save
  34. logger.info "Setting.set(#{name}, #{value.inspect})"
  35. end
  36. =begin
  37. get config setting
  38. value = Setting.get('some_config_name')
  39. =end
  40. def self.get(name)
  41. if load
  42. logger.debug "Setting.get(#{name.inspect}) # no cache"
  43. else
  44. logger.debug "Setting.get(#{name.inspect}) # from cache"
  45. end
  46. @@current[:settings_config][name]
  47. end
  48. =begin
  49. reset config setting to default
  50. Setting.reset('some_config_name')
  51. =end
  52. def self.reset(name)
  53. setting = Setting.find_by(name: name)
  54. if !setting
  55. raise "Can't find config setting '#{name}'"
  56. end
  57. setting.state_current = setting.state_initial
  58. setting.save
  59. logger.info "Setting.reset(#{name}, #{setting.state_current.inspect})"
  60. load
  61. @@current[:settings_config][name]
  62. end
  63. =begin
  64. reload config settings
  65. Setting.reload
  66. =end
  67. def self.reload
  68. load(true)
  69. end
  70. private
  71. # load values and cache them
  72. def self.load(force = false)
  73. # check if config is already generated
  74. if !force && @@current[:settings_config]
  75. return false if cache_valid?
  76. end
  77. # read all config settings
  78. config = {}
  79. Setting.select('name, state_current').order(:id).each { |setting|
  80. config[setting.name] = setting.state_current[:value]
  81. }
  82. # config lookups
  83. config.each { |key, value|
  84. next if value.class.to_s != 'String'
  85. config[key].gsub!(/\#\{config\.(.+?)\}/) {
  86. config[$1].to_s
  87. }
  88. }
  89. # store for class requests
  90. cache(config)
  91. true
  92. end
  93. private_class_method :load
  94. # set initial value in state_initial
  95. def set_initial
  96. self.state_initial = state_current
  97. end
  98. # set new cache
  99. def self.cache(config)
  100. @@change_id = Cache.get('Setting::ChangeId') # rubocop:disable Style/ClassVars
  101. @@current[:settings_config] = config
  102. logger.debug "Setting.cache: set cache, #{@@change_id}"
  103. @@lookup_at = Time.zone.now # rubocop:disable Style/ClassVars
  104. end
  105. private_class_method :cache
  106. # reset cache
  107. def reset_cache
  108. @@change_id = rand(999_999_999).to_s # rubocop:disable Style/ClassVars
  109. logger.debug "Setting.reset_cache: set new cache, #{@@change_id}"
  110. Cache.write('Setting::ChangeId', @@change_id, { expires_in: 24.hours })
  111. @@current[:settings_config] = nil
  112. end
  113. # check if cache is still valid
  114. def self.cache_valid?
  115. if @@lookup_at && @@lookup_at > Time.zone.now - @@lookup_timeout
  116. #logger.debug 'Setting.cache_valid?: cache_id has beed set within last 2 minutes'
  117. return true
  118. end
  119. change_id = Cache.get('Setting::ChangeId')
  120. if change_id == @@change_id
  121. @@lookup_at = Time.zone.now # rubocop:disable Style/ClassVars
  122. logger.debug "Setting.cache_valid?: cache still valid, #{@@change_id}/#{change_id}"
  123. return true
  124. end
  125. logger.debug "Setting.cache_valid?: cache has changed, #{@@change_id}/#{change_id}"
  126. false
  127. end
  128. private_class_method :cache_valid?
  129. # convert state into hash to be able to store it as store
  130. def state_check
  131. return if !state
  132. return if state && state.respond_to?('has_key?') && state.key?(:value)
  133. self.state_current = { value: state }
  134. end
  135. # notify clients about public config changes
  136. def check_broadcast
  137. return if frontend != true
  138. value = state_current
  139. if state_current.key?(:value)
  140. value = state_current[:value]
  141. end
  142. Sessions.broadcast(
  143. {
  144. event: 'config_update',
  145. data: { name: name, value: value }
  146. },
  147. 'public'
  148. )
  149. end
  150. end