Refactoring: Converted StatsStore to polymorphic association.
This commit is contained in:
parent
49d104a11c
commit
c3fce714dc
9 changed files with 78 additions and 171 deletions
|
@ -7,9 +7,8 @@ module ExtraCollection
|
||||||
def session( collections, assets, user )
|
def session( collections, assets, user )
|
||||||
return [collections, assets] if !user
|
return [collections, assets] if !user
|
||||||
|
|
||||||
item = StatsStore.search(
|
item = StatsStore.find_by(
|
||||||
object: 'User',
|
stats_storable: user,
|
||||||
o_id: user.id,
|
|
||||||
key: 'dashboard',
|
key: 'dashboard',
|
||||||
)
|
)
|
||||||
return [collections, assets] if !item
|
return [collections, assets] if !item
|
||||||
|
|
|
@ -109,11 +109,16 @@ returns
|
||||||
|
|
||||||
local_object.new.attributes.each do |key, _value|
|
local_object.new.attributes.each do |key, _value|
|
||||||
attribute_name = key.to_s
|
attribute_name = key.to_s
|
||||||
attribute_ref_name = local_object.search_index_attribute_ref_name(attribute_name)
|
|
||||||
attribute_class = local_object.reflect_on_association(attribute_ref_name)&.klass
|
|
||||||
|
|
||||||
next if attribute_name.blank?
|
next if attribute_name.blank?
|
||||||
|
|
||||||
|
attribute_ref_name = local_object.search_index_attribute_ref_name(attribute_name)
|
||||||
next if attribute_ref_name.blank?
|
next if attribute_ref_name.blank?
|
||||||
|
|
||||||
|
association = local_object.reflect_on_association(attribute_ref_name)
|
||||||
|
next if association.blank?
|
||||||
|
next if association.options[:polymorphic]
|
||||||
|
|
||||||
|
attribute_class = association.klass
|
||||||
next if attribute_class.blank?
|
next if attribute_class.blank?
|
||||||
next if attribute_class != self.class
|
next if attribute_class != self.class
|
||||||
|
|
||||||
|
|
|
@ -3,60 +3,15 @@
|
||||||
class StatsStore < ApplicationModel
|
class StatsStore < ApplicationModel
|
||||||
include HasSearchIndexBackend
|
include HasSearchIndexBackend
|
||||||
include StatsStore::SearchIndex
|
include StatsStore::SearchIndex
|
||||||
belongs_to :stats_store_object, class_name: 'ObjectLookup', optional: true
|
|
||||||
belongs_to :related_stats_store_object, class_name: 'ObjectLookup', optional: true
|
belongs_to :stats_storable, polymorphic: true
|
||||||
|
|
||||||
store :data
|
store :data
|
||||||
|
|
||||||
=begin
|
|
||||||
|
|
||||||
count = StatsStore.count_by_search(
|
|
||||||
object: 'User',
|
|
||||||
o_id: ticket.owner_id,
|
|
||||||
key: 'ticket:reopen',
|
|
||||||
start: Time.zone.now - 7.days,
|
|
||||||
end: Time.zone.now,
|
|
||||||
)
|
|
||||||
|
|
||||||
=end
|
|
||||||
|
|
||||||
def self.count_by_search(data)
|
|
||||||
|
|
||||||
# lookups
|
|
||||||
if data[:object]
|
|
||||||
object_id = ObjectLookup.by_name(data[:object])
|
|
||||||
end
|
|
||||||
|
|
||||||
StatsStore.where(stats_store_object_id: object_id, o_id: data[:o_id], key: data[:key])
|
|
||||||
.where('created_at > ? AND created_at < ?', data[:start], data[:end]).count
|
|
||||||
end
|
|
||||||
|
|
||||||
=begin
|
|
||||||
|
|
||||||
item = StatsStore.search(
|
|
||||||
object: 'User',
|
|
||||||
o_id: current_user.id,
|
|
||||||
key: 'dashboard',
|
|
||||||
)
|
|
||||||
|
|
||||||
=end
|
|
||||||
|
|
||||||
def self.search(data)
|
|
||||||
|
|
||||||
# lookups
|
|
||||||
if data[:object]
|
|
||||||
data[:stats_store_object_id] = ObjectLookup.by_name(data[:object])
|
|
||||||
data.delete(:object)
|
|
||||||
end
|
|
||||||
|
|
||||||
find_by(data)
|
|
||||||
end
|
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
item = StatsStore.sync(
|
item = StatsStore.sync(
|
||||||
object: 'User',
|
stats_storable: current_user,
|
||||||
o_id: current_user.id,
|
|
||||||
key: 'dashboard',
|
key: 'dashboard',
|
||||||
data: {some data},
|
data: {some data},
|
||||||
)
|
)
|
||||||
|
@ -68,7 +23,7 @@ class StatsStore < ApplicationModel
|
||||||
data = params[:data]
|
data = params[:data]
|
||||||
params.delete(:data)
|
params.delete(:data)
|
||||||
|
|
||||||
item = search(params)
|
item = find_by(params)
|
||||||
|
|
||||||
if item
|
if item
|
||||||
item.data = data
|
item.data = data
|
||||||
|
@ -76,74 +31,11 @@ class StatsStore < ApplicationModel
|
||||||
return item
|
return item
|
||||||
end
|
end
|
||||||
|
|
||||||
# lookups
|
|
||||||
if data[:object]
|
|
||||||
data[:stats_store_object_id] = ObjectLookup.by_name(data[:object])
|
|
||||||
data.delete(:object)
|
|
||||||
end
|
|
||||||
|
|
||||||
params[:data] = data
|
params[:data] = data
|
||||||
params[:created_by_id] = 1
|
params[:created_by_id] = 1
|
||||||
create(params)
|
create(params)
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
|
||||||
|
|
||||||
StatsStore.add(
|
|
||||||
object: 'User',
|
|
||||||
o_id: ticket.owner_id,
|
|
||||||
key: 'ticket:reopen',
|
|
||||||
data: { ticket_id: ticket.id },
|
|
||||||
created_at: Time.zone.now,
|
|
||||||
)
|
|
||||||
|
|
||||||
=end
|
|
||||||
|
|
||||||
def self.add(data)
|
|
||||||
|
|
||||||
# lookups
|
|
||||||
if data[:object]
|
|
||||||
object_id = ObjectLookup.by_name(data[:object])
|
|
||||||
end
|
|
||||||
|
|
||||||
# create history
|
|
||||||
record = {
|
|
||||||
stats_store_object_id: object_id,
|
|
||||||
o_id: data[:o_id],
|
|
||||||
key: data[:key],
|
|
||||||
data: data[:data],
|
|
||||||
created_at: data[:created_at],
|
|
||||||
created_by_id: data[:created_by_id],
|
|
||||||
}
|
|
||||||
|
|
||||||
StatsStore.create(record)
|
|
||||||
end
|
|
||||||
|
|
||||||
=begin
|
|
||||||
|
|
||||||
StatsStore.remove(
|
|
||||||
object: 'User',
|
|
||||||
o_id: ticket.owner_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
=end
|
|
||||||
|
|
||||||
def self.remove(data)
|
|
||||||
|
|
||||||
# lookups
|
|
||||||
if data[:object]
|
|
||||||
object_id = ObjectLookup.by_name(data[:object])
|
|
||||||
end
|
|
||||||
|
|
||||||
# create history
|
|
||||||
record = {
|
|
||||||
stats_store_object_id: object_id,
|
|
||||||
o_id: data[:o_id],
|
|
||||||
}
|
|
||||||
|
|
||||||
StatsStore.where(record).destroy_all
|
|
||||||
end
|
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
cleanup old stats store
|
cleanup old stats store
|
||||||
|
|
|
@ -1164,10 +1164,7 @@ raise 'Minimum one user need to have admin permissions'
|
||||||
def destroy_longer_required_objects
|
def destroy_longer_required_objects
|
||||||
::Avatar.remove(self.class.to_s, id)
|
::Avatar.remove(self.class.to_s, id)
|
||||||
::UserDevice.remove(id)
|
::UserDevice.remove(id)
|
||||||
::StatsStore.remove(
|
::StatsStore.where(stats_storable: self).destroy_all
|
||||||
object: self.class.to_s,
|
|
||||||
o_id: id,
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy_move_dependency_ownership
|
def destroy_move_dependency_ownership
|
||||||
|
|
|
@ -682,17 +682,13 @@ class CreateBase < ActiveRecord::Migration[4.2]
|
||||||
add_foreign_key :cti_caller_ids, :users
|
add_foreign_key :cti_caller_ids, :users
|
||||||
|
|
||||||
create_table :stats_stores do |t|
|
create_table :stats_stores do |t|
|
||||||
t.references :stats_store_object, null: false
|
t.references :stats_storable, polymorphic: true, index: true
|
||||||
t.integer :o_id, null: false
|
|
||||||
t.string :key, limit: 250, null: true
|
t.string :key, limit: 250, null: true
|
||||||
t.integer :related_stats_store_object_id, null: true
|
|
||||||
t.string :data, limit: 5000, null: true
|
t.string :data, limit: 5000, null: true
|
||||||
t.integer :created_by_id, null: false
|
t.integer :created_by_id, null: false
|
||||||
t.timestamps limit: 3, null: false
|
t.timestamps limit: 3, null: false
|
||||||
end
|
end
|
||||||
add_index :stats_stores, [:o_id]
|
|
||||||
add_index :stats_stores, [:key]
|
add_index :stats_stores, [:key]
|
||||||
add_index :stats_stores, [:stats_store_object_id]
|
|
||||||
add_index :stats_stores, [:created_by_id]
|
add_index :stats_stores, [:created_by_id]
|
||||||
add_index :stats_stores, [:created_at]
|
add_index :stats_stores, [:created_at]
|
||||||
add_foreign_key :stats_stores, :users, column: :created_by_id
|
add_foreign_key :stats_stores, :users, column: :created_by_id
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
class StatsStorePolymorphicAssociation < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
return if !Setting.exists?(name: 'system_init_done')
|
||||||
|
|
||||||
|
# create ObjectLookup ID -> Model map
|
||||||
|
object_lookup_map = ObjectLookup.all.pluck(:id, :name)
|
||||||
|
|
||||||
|
# create empty, indexed polymorphic association columns
|
||||||
|
add_reference :stats_stores, :stats_storable, polymorphic: true, index: true
|
||||||
|
|
||||||
|
# migrate column data in the most performance way
|
||||||
|
object_lookup_map.each do |id, model|
|
||||||
|
StatsStore.where(stats_store_object_id: id)
|
||||||
|
.update_all("stats_storable_id = o_id, stats_storable_type = '#{model}'") # rubocop:disable Rails/SkipsModelValidations
|
||||||
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Rails/ReversibleMigration
|
||||||
|
# remove home made "polymorphic association" columns
|
||||||
|
remove_column :stats_stores, :o_id
|
||||||
|
remove_column :stats_stores, :stats_store_object_id
|
||||||
|
|
||||||
|
# remove unused/obsolete columns
|
||||||
|
remove_column :stats_stores, :related_stats_store_object_id
|
||||||
|
remove_column(:stats_stores, :related_o_id) if StatsStore.column_names.include?('related_o_id')
|
||||||
|
# rubocop:enable Rails/ReversibleMigration
|
||||||
|
end
|
||||||
|
end
|
15
lib/stats.rb
15
lib/stats.rb
|
@ -45,7 +45,7 @@ returns
|
||||||
|
|
||||||
data[backend] = backend.generate(user)
|
data[backend] = backend.generate(user)
|
||||||
end
|
end
|
||||||
user_result[user.id] = data
|
user_result[user] = data
|
||||||
end
|
end
|
||||||
|
|
||||||
# calculate average
|
# calculate average
|
||||||
|
@ -64,25 +64,24 @@ returns
|
||||||
# generate average param and icon state
|
# generate average param and icon state
|
||||||
backend_average_sum.each do |backend_model_average, result|
|
backend_average_sum.each do |backend_model_average, result|
|
||||||
average = ( result.to_f / agent_count ).round(1)
|
average = ( result.to_f / agent_count ).round(1)
|
||||||
user_result.each do |user_id, data|
|
user_result.each do |user, data|
|
||||||
next if !data[backend_model_average]
|
next if !data[backend_model_average]
|
||||||
next if !data[backend_model_average].key?(:used_for_average)
|
next if !data[backend_model_average].key?(:used_for_average)
|
||||||
|
|
||||||
data[backend_model_average][:average_per_agent] = average
|
data[backend_model_average][:average_per_agent] = average
|
||||||
|
|
||||||
# generate icon state
|
# generate icon state
|
||||||
backend_model_average.to_s.constantize.average_state(data[backend_model_average], user_id)
|
backend_model_average.to_s.constantize.average_state(data[backend_model_average], user.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
user_result.each do |user_id, data|
|
user_result.each do |user, data|
|
||||||
data_for_user = {}
|
data_for_user = {}
|
||||||
data.each do |backend, result|
|
data.each do |backend, result|
|
||||||
data_for_user[backend.to_app_model] = result
|
data_for_user[backend.to_app_model] = result
|
||||||
end
|
end
|
||||||
state_store = StatsStore.sync(
|
state_store = StatsStore.sync(
|
||||||
object: 'User',
|
stats_storable: user,
|
||||||
o_id: user_id,
|
|
||||||
key: 'dashboard',
|
key: 'dashboard',
|
||||||
data: data_for_user,
|
data: data_for_user,
|
||||||
)
|
)
|
||||||
|
@ -93,11 +92,11 @@ returns
|
||||||
state_store.class.to_app_model => [state_store],
|
state_store.class.to_app_model => [state_store],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Sessions.send_to(user_id, message)
|
Sessions.send_to(user.id, message)
|
||||||
event = {
|
event = {
|
||||||
event: 'dashboard_stats_rebuild',
|
event: 'dashboard_stats_rebuild',
|
||||||
}
|
}
|
||||||
Sessions.send_to(user_id, event)
|
Sessions.send_to(user.id, event)
|
||||||
end
|
end
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
|
@ -11,13 +11,10 @@ class Stats::TicketReopen
|
||||||
).count
|
).count
|
||||||
|
|
||||||
# get count of reopens
|
# get count of reopens
|
||||||
count = StatsStore.count_by_search(
|
count = StatsStore.where(
|
||||||
object: 'User',
|
stats_storable: user,
|
||||||
o_id: user.id,
|
|
||||||
key: 'ticket:reopen',
|
key: 'ticket:reopen',
|
||||||
start: Time.zone.now - 7.days,
|
).where('created_at > ? AND created_at < ?', 7.days.ago, Time.zone.now).count
|
||||||
end: Time.zone.now,
|
|
||||||
)
|
|
||||||
|
|
||||||
if count > total
|
if count > total
|
||||||
total = count
|
total = count
|
||||||
|
@ -89,14 +86,12 @@ class Stats::TicketReopen
|
||||||
state_type_now = Ticket::StateType.lookup(id: state_now.state_type_id)
|
state_type_now = Ticket::StateType.lookup(id: state_now.state_type_id)
|
||||||
return if state_type_now.name == 'closed'
|
return if state_type_now.name == 'closed'
|
||||||
|
|
||||||
StatsStore.add(
|
StatsStore.create(
|
||||||
object: 'User',
|
stats_storable: ticket.owner,
|
||||||
o_id: ticket.owner_id,
|
|
||||||
key: 'ticket:reopen',
|
key: 'ticket:reopen',
|
||||||
data: { ticket_id: ticket.id },
|
data: { ticket_id: ticket.id },
|
||||||
created_at: Time.zone.now,
|
created_at: Time.zone.now,
|
||||||
created_by_id: updated_by_id,
|
created_by_id: updated_by_id,
|
||||||
updated_by_id: updated_by_id,
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1257,17 +1257,15 @@ class UserTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
Token.create!(action: 'api', user_id: agent1_id)
|
Token.create!(action: 'api', user_id: agent1_id)
|
||||||
|
|
||||||
StatsStore.add(
|
StatsStore.create(
|
||||||
object: 'User',
|
stats_storable: agent1,
|
||||||
o_id: agent1_id,
|
|
||||||
key: 'some_key',
|
key: 'some_key',
|
||||||
data: { A: 1, B: 2 },
|
data: { A: 1, B: 2 },
|
||||||
created_at: Time.zone.now,
|
created_at: Time.zone.now,
|
||||||
created_by_id: 1,
|
created_by_id: 1,
|
||||||
)
|
)
|
||||||
item = StatsStore.search(
|
item = StatsStore.find_by(
|
||||||
object: 'User',
|
stats_storable: agent1,
|
||||||
o_id: agent1_id,
|
|
||||||
key: 'some_key',
|
key: 'some_key',
|
||||||
)
|
)
|
||||||
assert(item)
|
assert(item)
|
||||||
|
@ -1284,9 +1282,8 @@ class UserTest < ActiveSupport::TestCase
|
||||||
assert_equal(0, RecentView.where(created_by_id: agent1_id).count)
|
assert_equal(0, RecentView.where(created_by_id: agent1_id).count)
|
||||||
assert_equal(0, Token.where(user_id: agent1_id).count)
|
assert_equal(0, Token.where(user_id: agent1_id).count)
|
||||||
assert_equal(0, Token.where(user_id: agent1_id).count)
|
assert_equal(0, Token.where(user_id: agent1_id).count)
|
||||||
item = StatsStore.search(
|
item = StatsStore.find_by(
|
||||||
object: 'User',
|
stats_storable: agent1,
|
||||||
o_id: agent1_id,
|
|
||||||
key: 'some_key',
|
key: 'some_key',
|
||||||
)
|
)
|
||||||
assert_nil(item)
|
assert_nil(item)
|
||||||
|
|
Loading…
Reference in a new issue