2021-06-01 12:20:20 +00:00
|
|
|
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
2013-06-12 15:59:58 +00:00
|
|
|
|
2012-09-20 12:08:02 +00:00
|
|
|
class Setting < ApplicationModel
|
2012-04-13 13:51:10 +00:00
|
|
|
store :options
|
2015-09-25 14:37:55 +00:00
|
|
|
store :state_current
|
2012-04-13 13:51:10 +00:00
|
|
|
store :state_initial
|
2015-07-12 02:12:27 +00:00
|
|
|
store :preferences
|
2016-05-25 07:19:45 +00:00
|
|
|
before_create :state_check, :set_initial, :check_broadcast
|
2018-10-30 16:00:33 +00:00
|
|
|
after_create :reset_change_id, :reset_cache
|
2020-09-30 09:07:01 +00:00
|
|
|
before_update :state_check, :check_broadcast
|
2018-10-30 16:00:33 +00:00
|
|
|
after_update :reset_change_id, :reset_cache
|
2012-04-10 14:06:46 +00:00
|
|
|
|
2015-09-25 14:37:55 +00:00
|
|
|
attr_accessor :state
|
|
|
|
|
2017-06-08 04:49:25 +00:00
|
|
|
@@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
|
2013-03-19 00:46:49 +00:00
|
|
|
|
2015-08-31 12:36:57 +00:00
|
|
|
=begin
|
2012-07-28 16:37:18 +00:00
|
|
|
|
2015-08-31 12:36:57 +00:00
|
|
|
set config setting
|
2012-07-28 16:37:18 +00:00
|
|
|
|
2015-08-31 12:36:57 +00:00
|
|
|
Setting.set('some_config_name', some_value)
|
2015-05-07 09:49:46 +00:00
|
|
|
|
2015-08-31 12:36:57 +00:00
|
|
|
=end
|
2012-04-10 14:06:46 +00:00
|
|
|
|
2012-12-24 13:55:43 +00:00
|
|
|
def self.set(name, value)
|
2016-03-25 09:27:52 +00:00
|
|
|
setting = Setting.find_by(name: name)
|
2012-12-24 13:55:43 +00:00
|
|
|
if !setting
|
2016-03-01 14:26:46 +00:00
|
|
|
raise "Can't find config setting '#{name}'"
|
2012-12-24 13:55:43 +00:00
|
|
|
end
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2015-09-25 18:35:36 +00:00
|
|
|
setting.state_current = { value: value }
|
2017-06-08 04:49:25 +00:00
|
|
|
setting.save!
|
2017-10-20 13:32:01 +00:00
|
|
|
logger.info "Setting.set('#{name}', #{value.inspect})"
|
2018-10-30 16:00:33 +00:00
|
|
|
true
|
2012-12-24 13:55:43 +00:00
|
|
|
end
|
|
|
|
|
2015-08-31 12:36:57 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
get config setting
|
|
|
|
|
|
|
|
value = Setting.get('some_config_name')
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
2012-04-10 14:06:46 +00:00
|
|
|
def self.get(name)
|
2016-11-28 14:57:20 +00:00
|
|
|
load
|
2018-09-11 09:21:09 +00:00
|
|
|
@@current[name].deep_dup # prevents accidental modification of settings in console
|
2012-04-10 14:06:46 +00:00
|
|
|
end
|
2012-07-28 16:37:18 +00:00
|
|
|
|
2015-08-31 12:36:57 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
reset config setting to default
|
|
|
|
|
|
|
|
Setting.reset('some_config_name')
|
|
|
|
|
2017-06-14 15:25:45 +00:00
|
|
|
Setting.reset('some_config_name', force) # true|false - force it false per default
|
|
|
|
|
2015-08-31 12:36:57 +00:00
|
|
|
=end
|
|
|
|
|
2017-06-14 15:25:45 +00:00
|
|
|
def self.reset(name, force = false)
|
2016-03-25 09:27:52 +00:00
|
|
|
setting = Setting.find_by(name: name)
|
2015-07-07 05:56:31 +00:00
|
|
|
if !setting
|
2016-03-01 14:26:46 +00:00
|
|
|
raise "Can't find config setting '#{name}'"
|
2015-07-07 05:56:31 +00:00
|
|
|
end
|
2017-06-14 15:25:45 +00:00
|
|
|
return true if !force && setting.state_current == setting.state_initial
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2015-09-25 18:35:36 +00:00
|
|
|
setting.state_current = setting.state_initial
|
2017-06-08 04:49:25 +00:00
|
|
|
setting.save!
|
2017-10-20 13:32:01 +00:00
|
|
|
logger.info "Setting.reset('#{name}', #{setting.state_current.inspect})"
|
2018-10-30 16:00:33 +00:00
|
|
|
true
|
2015-07-07 05:56:31 +00:00
|
|
|
end
|
|
|
|
|
2016-01-13 19:45:51 +00:00
|
|
|
=begin
|
|
|
|
|
|
|
|
reload config settings
|
|
|
|
|
|
|
|
Setting.reload
|
|
|
|
|
|
|
|
=end
|
|
|
|
|
|
|
|
def self.reload
|
2017-06-08 04:49:25 +00:00
|
|
|
@@last_changed_at = nil # rubocop:disable Style/ClassVars
|
2016-01-13 19:45:51 +00:00
|
|
|
load(true)
|
|
|
|
end
|
|
|
|
|
2012-04-10 14:06:46 +00:00
|
|
|
private
|
2015-05-01 12:31:46 +00:00
|
|
|
|
2015-08-31 12:36:57 +00:00
|
|
|
# load values and cache them
|
2016-01-13 19:45:51 +00:00
|
|
|
def self.load(force = false)
|
2015-08-31 12:36:57 +00:00
|
|
|
|
|
|
|
# check if config is already generated
|
2017-06-08 04:49:25 +00:00
|
|
|
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
|
2015-08-31 12:36:57 +00:00
|
|
|
end
|
|
|
|
|
2017-06-08 04:49:25 +00:00
|
|
|
if settings.present?
|
2017-10-01 12:25:52 +00:00
|
|
|
settings.each do |setting|
|
2017-06-08 04:49:25 +00:00
|
|
|
@@raw[setting[0]] = setting[1]['value']
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
|
|
|
@@raw.each do |key, value|
|
2017-06-08 04:49:25 +00:00
|
|
|
if value.class != String
|
|
|
|
@@current[key] = value
|
|
|
|
next
|
|
|
|
end
|
2021-05-12 11:37:44 +00:00
|
|
|
@@current[key] = value.gsub(%r{\#\{config\.(.+?)\}}) do
|
2017-06-08 04:49:25 +00:00
|
|
|
@@raw[$1].to_s
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
|
|
|
end
|
2017-06-08 04:49:25 +00:00
|
|
|
end
|
2015-08-31 12:36:57 +00:00
|
|
|
|
2021-05-31 13:05:54 +00:00
|
|
|
@@change_id = Cache.read('Setting::ChangeId') # rubocop:disable Style/ClassVars
|
2018-11-26 14:51:23 +00:00
|
|
|
@@lookup_at = Time.now.to_i # rubocop:disable Style/ClassVars
|
2015-09-06 11:41:31 +00:00
|
|
|
true
|
2013-06-12 15:59:58 +00:00
|
|
|
end
|
2016-01-15 17:22:57 +00:00
|
|
|
private_class_method :load
|
2015-05-07 10:27:12 +00:00
|
|
|
|
2015-08-31 12:36:57 +00:00
|
|
|
# set initial value in state_initial
|
2013-06-12 15:59:58 +00:00
|
|
|
def set_initial
|
2015-09-25 18:35:36 +00:00
|
|
|
self.state_initial = state_current
|
2017-06-16 22:53:20 +00:00
|
|
|
true
|
2013-06-12 15:59:58 +00:00
|
|
|
end
|
2015-05-07 10:27:12 +00:00
|
|
|
|
2017-06-08 04:49:25 +00:00
|
|
|
def reset_change_id
|
|
|
|
@@current[name] = state_current[:value]
|
2021-09-20 10:47:05 +00:00
|
|
|
change_id = SecureRandom.uuid
|
2018-03-20 17:47:49 +00:00
|
|
|
logger.debug { "Setting.reset_change_id: set new cache, #{change_id}" }
|
2017-06-08 04:49:25 +00:00
|
|
|
Cache.write('Setting::ChangeId', change_id, { expires_in: 24.hours })
|
|
|
|
@@lookup_at = nil # rubocop:disable Style/ClassVars
|
2017-06-16 22:53:20 +00:00
|
|
|
true
|
2015-08-31 12:36:57 +00:00
|
|
|
end
|
|
|
|
|
2018-10-30 16:00:33 +00:00
|
|
|
def reset_cache
|
|
|
|
return true if preferences[:cache].blank?
|
|
|
|
|
|
|
|
preferences[:cache].each do |key|
|
|
|
|
Cache.delete(key)
|
|
|
|
end
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2015-08-31 12:36:57 +00:00
|
|
|
# check if cache is still valid
|
|
|
|
def self.cache_valid?
|
2018-11-26 14:51:23 +00:00
|
|
|
if @@lookup_at && @@lookup_at > Time.now.to_i - @@lookup_timeout
|
2021-07-16 13:44:10 +00:00
|
|
|
# logger.debug "Setting.cache_valid?: cache_id has been set within last #{@@lookup_timeout} seconds"
|
2015-08-31 12:36:57 +00:00
|
|
|
return true
|
|
|
|
end
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2021-05-31 13:05:54 +00:00
|
|
|
change_id = Cache.read('Setting::ChangeId')
|
2018-09-28 12:16:50 +00:00
|
|
|
if @@change_id && change_id == @@change_id
|
2018-11-26 14:51:23 +00:00
|
|
|
@@lookup_at = Time.now.to_i # rubocop:disable Style/ClassVars
|
2021-07-16 13:44:10 +00:00
|
|
|
# logger.debug "Setting.cache_valid?: cache still valid, #{@@change_id}/#{change_id}"
|
2015-08-31 12:36:57 +00:00
|
|
|
return true
|
|
|
|
end
|
2021-07-16 13:44:10 +00:00
|
|
|
# logger.debug "Setting.cache_valid?: cache has changed, #{@@change_id}/#{change_id}"
|
2015-08-31 12:36:57 +00:00
|
|
|
false
|
|
|
|
end
|
2016-01-15 17:22:57 +00:00
|
|
|
private_class_method :cache_valid?
|
2015-08-31 12:36:57 +00:00
|
|
|
|
2015-09-25 21:35:17 +00:00
|
|
|
# convert state into hash to be able to store it as store
|
2013-06-12 15:59:58 +00:00
|
|
|
def state_check
|
2020-06-22 09:57:45 +00:00
|
|
|
return true if state.nil? # allow false value
|
2018-04-12 14:57:37 +00:00
|
|
|
return true if state.try(:key?, :value)
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2015-09-25 18:35:36 +00:00
|
|
|
self.state_current = { value: state }
|
2017-06-16 22:53:20 +00:00
|
|
|
true
|
2013-06-12 15:59:58 +00:00
|
|
|
end
|
2016-05-25 07:19:45 +00:00
|
|
|
|
|
|
|
# notify clients about public config changes
|
|
|
|
def check_broadcast
|
2017-06-16 22:53:20 +00:00
|
|
|
return true if frontend != true
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-05-25 07:19:45 +00:00
|
|
|
value = state_current
|
|
|
|
if state_current.key?(:value)
|
|
|
|
value = state_current[:value]
|
|
|
|
end
|
|
|
|
Sessions.broadcast(
|
|
|
|
{
|
|
|
|
event: 'config_update',
|
2018-12-19 17:31:51 +00:00
|
|
|
data: { name: name, value: value }
|
2016-05-25 07:19:45 +00:00
|
|
|
},
|
|
|
|
'public'
|
|
|
|
)
|
2017-06-16 22:53:20 +00:00
|
|
|
true
|
2016-05-25 07:19:45 +00:00
|
|
|
end
|
2012-04-10 14:06:46 +00:00
|
|
|
end
|