123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
- class Setting < ApplicationModel
- store :options
- store :state_current
- store :state_initial
- store :preferences
- before_create :state_check, :set_initial, :check_broadcast
- before_update :state_check, :check_broadcast
- after_create :reset_change_id
- after_update :reset_change_id
- attr_accessor :state
- @@current = {} # rubocop:disable Style/ClassVars
- @@raw = {} # rubocop:disable Style/ClassVars
- @@change_id = nil # rubocop:disable Style/ClassVars
- @@last_changed_at = nil # rubocop:disable Style/ClassVars
- @@lookup_at = nil # rubocop:disable Style/ClassVars
- @@lookup_timeout = if ENV['ZAMMAD_SETTING_TTL'] # rubocop:disable Style/ClassVars
- ENV['ZAMMAD_SETTING_TTL'].to_i.seconds
- else
- 15.seconds
- end
- =begin
- set config setting
- Setting.set('some_config_name', some_value)
- =end
- def self.set(name, value)
- setting = Setting.find_by(name: name)
- if !setting
- raise "Can't find config setting '#{name}'"
- end
- setting.state_current = { value: value }
- setting.save!
- logger.info "Setting.set('#{name}', #{value.inspect})"
- end
- =begin
- get config setting
- value = Setting.get('some_config_name')
- =end
- def self.get(name)
- load
- @@current[name]
- end
- =begin
- reset config setting to default
- Setting.reset('some_config_name')
- Setting.reset('some_config_name', force) # true|false - force it false per default
- =end
- def self.reset(name, force = false)
- setting = Setting.find_by(name: name)
- if !setting
- raise "Can't find config setting '#{name}'"
- end
- return true if !force && setting.state_current == setting.state_initial
- setting.state_current = setting.state_initial
- setting.save!
- logger.info "Setting.reset('#{name}', #{setting.state_current.inspect})"
- end
- =begin
- reload config settings
- Setting.reload
- =end
- def self.reload
- @@last_changed_at = nil # rubocop:disable Style/ClassVars
- load(true)
- end
- private
- # load values and cache them
- def self.load(force = false)
- # check if config is already generated
- return false if !force && @@current.present? && cache_valid?
- # read all or only changed since last read
- latest = Setting.order(updated_at: :desc).limit(1).pluck(:updated_at)
- settings = if @@last_changed_at && @@current.present?
- Setting.where('updated_at > ?', @@last_changed_at).order(:id).pluck(:name, :state_current)
- else
- Setting.order(:id).pluck(:name, :state_current)
- end
- if latest
- @@last_changed_at = latest[0] # rubocop:disable Style/ClassVars
- end
- if settings.present?
- settings.each do |setting|
- @@raw[setting[0]] = setting[1]['value']
- end
- @@raw.each do |key, value|
- if value.class != String
- @@current[key] = value
- next
- end
- @@current[key] = value.gsub(/\#\{config\.(.+?)\}/) do
- @@raw[$1].to_s
- end
- end
- end
- @@change_id = Cache.get('Setting::ChangeId') # rubocop:disable Style/ClassVars
- @@lookup_at = Time.zone.now # rubocop:disable Style/ClassVars
- true
- end
- private_class_method :load
- # set initial value in state_initial
- def set_initial
- self.state_initial = state_current
- true
- end
- def reset_change_id
- @@current[name] = state_current[:value]
- change_id = rand(999_999_999).to_s
- logger.debug { "Setting.reset_change_id: set new cache, #{change_id}" }
- Cache.write('Setting::ChangeId', change_id, { expires_in: 24.hours })
- @@lookup_at = nil # rubocop:disable Style/ClassVars
- true
- end
- # check if cache is still valid
- def self.cache_valid?
- if @@lookup_at && @@lookup_at > Time.zone.now - @@lookup_timeout
- #logger.debug "Setting.cache_valid?: cache_id has been set within last #{@@lookup_timeout} seconds"
- return true
- end
- change_id = Cache.get('Setting::ChangeId')
- if change_id == @@change_id
- @@lookup_at = Time.zone.now # rubocop:disable Style/ClassVars
- #logger.debug "Setting.cache_valid?: cache still valid, #{@@change_id}/#{change_id}"
- return true
- end
- #logger.debug "Setting.cache_valid?: cache has changed, #{@@change_id}/#{change_id}"
- false
- end
- private_class_method :cache_valid?
- # convert state into hash to be able to store it as store
- def state_check
- return true if !state
- return true if state && state.respond_to?('has_key?') && state.key?(:value)
- self.state_current = { value: state }
- true
- end
- # notify clients about public config changes
- def check_broadcast
- return true if frontend != true
- value = state_current
- if state_current.key?(:value)
- value = state_current[:value]
- end
- Sessions.broadcast(
- {
- event: 'config_update',
- data: { name: name, value: value }
- },
- 'public'
- )
- true
- end
- end
|