diff --git a/app/models/application_model.rb b/app/models/application_model.rb index d6a2d54b1..1ccc18a31 100644 --- a/app/models/application_model.rb +++ b/app/models/application_model.rb @@ -237,44 +237,45 @@ returns def cache_delete # delete id caches - key = self.class.to_s + '::' + id.to_s - Cache.delete( key.to_s ) + key = "#{self.class}::#{id}" + Cache.delete(key) # delete old name / login caches if self.changed? if changes.key?('name') - name = changes['name'][0].to_s - key = self.class.to_s + '::' + name + name = changes['name'][0] + key = "#{self.class}::#{name}" Cache.delete( key.to_s ) end if changes.key?('login') - name = changes['login'][0].to_s - key = self.class.to_s + '::' + name - Cache.delete( key.to_s ) + name = changes['login'][0] + key = "#{self.class}::#{name}" + Cache.delete(key) end end # delete name caches if self[:name] - key = self.class.to_s + '::' + self.name.to_s - Cache.delete( key.to_s ) + key = "#{self.class}::#{self.name}" + Cache.delete(key) end - return if !self[:login] - # delete login caches - key = self.class.to_s + '::' + login.to_s - Cache.delete( key.to_s ) + if self[:login] + key = "#{self.class}::#{login}" + Cache.delete(key) + end + end def self.cache_set(data_id, data) - key = to_s + '::' + data_id.to_s - Cache.write( key.to_s, data ) + key = "#{self}::#{data_id}" + Cache.write(key, data) end def self.cache_get(data_id) - key = to_s + '::' + data_id.to_s - Cache.get( key.to_s ) + key = "#{self}::#{data_id}" + Cache.get(key) end =begin diff --git a/app/models/organization.rb b/app/models/organization.rb index 5895939fb..9b4909841 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -16,4 +16,15 @@ class Organization < ApplicationModel search_index_support notify_clients_support latest_change_support + + + private + + def cache_delete + super + + # delete asset caches + key = "Organization::member_ids::#{id}" + Cache.delete(key) + end end diff --git a/app/models/organization/assets.rb b/app/models/organization/assets.rb index 2f48e771a..cba3d76e6 100644 --- a/app/models/organization/assets.rb +++ b/app/models/organization/assets.rb @@ -30,15 +30,26 @@ returns data[ User.to_app_model ] = {} end if !data[ Organization.to_app_model ][ id ] - data[ Organization.to_app_model ][ id ] = attributes_with_associations - if data[ Organization.to_app_model ][ id ]['member_ids'] - data[ Organization.to_app_model ][ id ]['member_ids'].each {|local_user_id| + local_attributes = attributes + + # get organizations + key = "Organization::member_ids::#{id}" + local_member_ids = Cache.get(key) + if !local_member_ids + local_member_ids = member_ids + Cache.write(key, local_member_ids) + end + local_attributes['member_ids'] = local_member_ids + if local_member_ids + local_member_ids.each {|local_user_id| if !data[ User.to_app_model ][ local_user_id ] user = User.lookup( id: local_user_id ) data = user.assets( data ) end } end + + data[ Organization.to_app_model ][ id ] = local_attributes end %w(created_by_id updated_by_id).each {|local_user_id| next if !self[ local_user_id ] diff --git a/app/models/user.rb b/app/models/user.rb index 1b97c6335..a85d38173 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -412,6 +412,20 @@ returns private + def cache_delete + super + + # delete asset caches + key = "User::authorizations::#{id}" + Cache.delete(key) + key = "User::role_ids::#{id}" + Cache.delete(key) + key = "User::group_ids::#{id}" + Cache.delete(key) + key = "User::organization_ids::#{id}" + Cache.delete(key) + end + def check_name if ( firstname && !firstname.empty? ) && ( !lastname || lastname.empty? ) diff --git a/app/models/user/assets.rb b/app/models/user/assets.rb index 8309f55b1..7801168a4 100644 --- a/app/models/user/assets.rb +++ b/app/models/user/assets.rb @@ -27,47 +27,77 @@ returns data[ User.to_app_model ] = {} end if !data[ User.to_app_model ][ id ] - attributes = attributes_with_associations + local_attributes = attributes # do not transfer crypted pw - attributes['password'] = '' + local_attributes['password'] = '' # get linked accounts - attributes['accounts'] = {} - authorizations = self.authorizations() - authorizations.each do |authorization| - attributes['accounts'][authorization.provider] = { - uid: authorization[:uid], - username: authorization[:username] - } + local_attributes['accounts'] = {} + key = "User::authorizations::#{id}" + local_accounts = Cache.get(key) + if !local_accounts + local_accounts = {} + authorizations = self.authorizations() + authorizations.each do |authorization| + local_accounts[authorization.provider] = { + uid: authorization[:uid], + username: authorization[:username] + } + end + Cache.write(key, local_accounts) end - - data[ User.to_app_model ][ id ] = attributes + local_attributes['accounts'] = local_accounts # get roles - if attributes['role_ids'] - attributes['role_ids'].each {|role_id| + key = "User::role_ids::#{id}" + local_role_ids = Cache.get(key) + if !local_role_ids + local_role_ids = role_ids + Cache.write(key, local_role_ids) + end + local_attributes['role_ids'] = local_role_ids + if local_role_ids + local_role_ids.each {|role_id| role = Role.lookup( id: role_id ) data = role.assets( data ) } end # get groups - if attributes['group_ids'] - attributes['group_ids'].each {|group_id| + key = "User::group_ids::#{id}" + local_group_ids = Cache.get(key) + if !local_group_ids + local_group_ids = group_ids + Cache.write(key, local_group_ids) + end + local_attributes['group_ids'] = local_group_ids + if local_group_ids + local_group_ids.each {|group_id| group = Group.lookup( id: group_id ) data = group.assets( data ) } end - # get groups - if attributes['organization_ids'] - attributes['organization_ids'].each {|organization_id| + # get organizations + key = "User::organization_ids::#{id}" + local_organization_ids = Cache.get(key) + if !local_organization_ids + local_organization_ids = organization_ids + Cache.write(key, local_organization_ids) + end + local_attributes['organization_ids'] = local_organization_ids + if local_organization_ids + local_organization_ids.each {|organization_id| organization = Organization.lookup( id: organization_id ) data = organization.assets( data ) } end + + data[ User.to_app_model ][ id ] = local_attributes end + + # add organization if self.organization_id if !data[ Organization.to_app_model ] || !data[ Organization.to_app_model ][ self.organization_id ] organization = Organization.lookup( id: self.organization_id ) diff --git a/test/unit/assets_test.rb b/test/unit/assets_test.rb index ea7426c6d..46dd6eaa9 100644 --- a/test/unit/assets_test.rb +++ b/test/unit/assets_test.rb @@ -7,7 +7,7 @@ class AssetsTest < ActiveSupport::TestCase roles = Role.where( name: %w(Agent Admin) ) groups = Group.all org = Organization.create_or_update( - name: 'some org', + name: 'some user org', updated_by_id: 1, created_by_id: 1, ) @@ -25,7 +25,6 @@ class AssetsTest < ActiveSupport::TestCase roles: roles, groups: groups, ) - user1.save user2 = User.create_or_update( login: 'assets2@example.org', @@ -39,7 +38,6 @@ class AssetsTest < ActiveSupport::TestCase roles: roles, groups: groups, ) - user2.save user3 = User.create_or_update( login: 'assets3@example.org', @@ -53,29 +51,229 @@ class AssetsTest < ActiveSupport::TestCase roles: roles, groups: groups, ) - user3.save + user3 = User.find(user3.id) assets = user3.assets({}) + org = Organization.find(org.id) + attributes = org.attributes_with_associations + attributes.delete('user_ids') + assert( diff(attributes, assets[:Organization][org.id]), 'check assets') + + user1 = User.find(user1.id) attributes = user1.attributes_with_associations attributes['accounts'] = {} attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') assert( diff(attributes, assets[:User][user1.id]), 'check assets' ) - assert( diff(org.attributes_with_associations, assets[:Organization][org.id]), 'check assets' ) + user2 = User.find(user2.id) attributes = user2.attributes_with_associations attributes['accounts'] = {} attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') assert( diff(attributes, assets[:User][user2.id]), 'check assets' ) + user3 = User.find(user3.id) attributes = user3.attributes_with_associations attributes['accounts'] = {} attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') + assert( diff(attributes, assets[:User][user3.id]), 'check assets' ) + + # touch org, check if user1 has changed + sleep 2 + org2 = Organization.find(org.id) + org2.note = "some note...#{rand(9999999999999)}" + org2.save + + attributes = org2.attributes_with_associations + attributes.delete('user_ids') + assert( !diff(attributes, assets[:Organization][org2.id]), 'check assets' ) + + user1_new = User.find(user1.id) + attributes = user1_new.attributes_with_associations + attributes['accounts'] = {} + attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') + assert( !diff(attributes, assets[:User][user1_new.id]), 'check assets' ) + + # check new assets lookup + assets = user3.assets({}) + attributes = org2.attributes_with_associations + attributes.delete('user_ids') + assert( diff(attributes, assets[:Organization][org.id]), 'check assets') + + user1 = User.find(user1.id) + attributes = user1.attributes_with_associations + attributes['accounts'] = {} + attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') + assert( diff(attributes, assets[:User][user1.id]), 'check assets' ) + + user2 = User.find(user2.id) + attributes = user2.attributes_with_associations + attributes['accounts'] = {} + attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') + assert( diff(attributes, assets[:User][user2.id]), 'check assets' ) + + user3 = User.find(user3.id) + attributes = user3.attributes_with_associations + attributes['accounts'] = {} + attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') assert( diff(attributes, assets[:User][user3.id]), 'check assets' ) end + test 'organization' do + + roles = Role.where( name: %w(Agent Admin) ) + admin1 = User.create_or_update( + login: 'admin1@example.org', + firstname: 'admin1', + lastname: 'admin1', + email: 'admin1@example.org', + password: 'some_pass', + active: true, + updated_by_id: 1, + created_by_id: 1, + roles: roles, + ) + + roles = Role.where( name: %w(Customer) ) + org = Organization.create_or_update( + name: 'some customer org', + updated_by_id: admin1.id, + created_by_id: 1, + ) + + user1 = User.create_or_update( + login: 'assets1@example.org', + firstname: 'assets1', + lastname: 'assets1', + email: 'assets1@example.org', + password: 'some_pass', + active: true, + updated_by_id: 1, + created_by_id: 1, + organization_id: org.id, + roles: roles, + ) + + user2 = User.create_or_update( + login: 'assets2@example.org', + firstname: 'assets2', + lastname: 'assets2', + email: 'assets2@example.org', + password: 'some_pass', + active: true, + updated_by_id: 1, + created_by_id: 1, + organization_id: org.id, + roles: roles, + ) + + user3 = User.create_or_update( + login: 'assets3@example.org', + firstname: 'assets3', + lastname: 'assets3', + email: 'assets3@example.org', + password: 'some_pass', + active: true, + updated_by_id: user1.id, + created_by_id: user2.id, + roles: roles, + ) + + org = Organization.find(org.id) + assets = org.assets({}) + attributes = org.attributes_with_associations + attributes.delete('user_ids') + assert( diff(attributes, assets[:Organization][org.id]), 'check assets' ) + + admin1 = User.find(admin1.id) + attributes = admin1.attributes_with_associations + attributes['accounts'] = {} + attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') + assert( diff(attributes, assets[:User][admin1.id]), 'check assets' ) + + user1 = User.find(user1.id) + attributes = user1.attributes_with_associations + attributes['accounts'] = {} + attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') + assert( diff(attributes, assets[:User][user1.id]), 'check assets' ) + + user2 = User.find(user2.id) + attributes = user2.attributes_with_associations + attributes['accounts'] = {} + attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') + assert( diff(attributes, assets[:User][user2.id]), 'check assets' ) + + user3 = User.find(user3.id) + attributes = user3.attributes_with_associations + attributes['accounts'] = {} + attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') + assert_nil( assets[:User][user3.id], 'check assets' ) + + # touch user 2, check if org has changed + sleep 2 + user_new_2 = User.find(user2.id) + user_new_2.lastname = 'assets2' + user_new_2.save + + org_new = Organization.find(org.id) + attributes = org_new.attributes_with_associations + attributes.delete('user_ids') + assert( !diff(attributes, assets[:Organization][org_new.id]), 'check assets' ) + + attributes = user_new_2.attributes_with_associations + attributes['accounts'] = {} + attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') + assert( !diff(attributes, assets[:User][user_new_2.id]), 'check assets' ) + + # check new assets lookup + assets = org_new.assets({}) + attributes = org_new.attributes_with_associations + attributes.delete('user_ids') + assert( diff(attributes, assets[:Organization][org_new.id]), 'check assets' ) + + attributes = user_new_2.attributes_with_associations + attributes['accounts'] = {} + attributes['password'] = '' + attributes.delete('token_ids') + attributes.delete('authorization_ids') + assert( diff(attributes, assets[:User][user_new_2.id]), 'check assets' ) + + end + def diff(o1, o2) - return true if o1 #== o2 - fail "ERROR: difference #{o1.inspect}, #{o2.inspect}" + return true if o1 == o2 + if o1['updated_at'] + o1['updated_at'] = o1['updated_at'].to_s + end + if o2['updated_at'] + o2['updated_at'] = o2['updated_at'].to_s + end + return true if (o1.to_a - o2.to_a).empty? + puts "ERROR: difference \n1: #{o1.inspect}\n2: #{o2.inspect}\ndiff: #{(o1.to_a - o2.to_a).inspect}" + false end end diff --git a/test/unit/object_cache_test.rb b/test/unit/object_cache_test.rb index 2ed7d6d46..6af04c1fc 100644 --- a/test/unit/object_cache_test.rb +++ b/test/unit/object_cache_test.rb @@ -2,7 +2,91 @@ require 'test_helper' class ObjectCacheTest < ActiveSupport::TestCase - test 'object cache' do + test 'organization cache' do + org = Organization.create_or_update( + name: 'some org cache member', + updated_by_id: 1, + created_by_id: 1, + ) + + roles = Role.where( name: %w(Agent Admin) ) + groups = Group.all + user1 = User.create_or_update( + login: 'object_cache1@example.org', + firstname: 'object_cache1', + lastname: 'object_cache1', + email: 'object_cache1@example.org', + password: 'some_pass', + active: true, + updated_by_id: 1, + created_by_id: 1, + organization_id: org.id, + roles: roles, + groups: groups, + ) + assets = org.assets({}) + assert_equal( org.member_ids, assets[:Organization][org.id]['member_ids'] ) + + user1.organization_id = nil + user1.save + + assets = org.assets({}) + assert_equal( org.member_ids, assets[:Organization][org.id]['member_ids'] ) + end + + test 'user cache' do + roles = Role.where( name: %w(Agent Admin) ) + groups = Group.all + user1 = User.create_or_update( + login: 'object_cache1@example.org', + firstname: 'object_cache1', + lastname: 'object_cache1', + email: 'object_cache1@example.org', + password: 'some_pass', + active: true, + updated_by_id: 1, + created_by_id: 1, + roles: roles, + groups: groups, + ) + assets = user1.assets({}) + assert_equal( user1.group_ids, assets[:User][user1.id]['group_ids'] ) + + # update group + group1 = groups.first + group1.note = "some note #{rand(9999999999)}" + group1.save + + assets = user1.assets({}) + assert_equal( group1.note, assets[:Group][group1.id]['note'] ) + + # update group + assert_equal( user1.group_ids, assets[:User][user1.id]['group_ids'] ) + user1.group_ids = [] + user1.save + + assets = user1.assets({}) + assert_equal( user1.group_ids, assets[:User][user1.id]['group_ids'] ) + + # update role + assert_equal( user1.role_ids, assets[:User][user1.id]['role_ids'] ) + user1.role_ids = [] + user1.save + + assets = user1.assets({}) + assert_equal( user1.role_ids, assets[:User][user1.id]['role_ids'] ) + + # update groups + assert_equal( user1.organization_ids, assets[:User][user1.id]['organization_ids'] ) + user1.organization_ids = [1] + user1.save + + assets = user1.assets({}) + assert_equal( user1.organization_ids, assets[:User][user1.id]['organization_ids'] ) + + end + + test 'group cache' do name = 'object cache test ' + rand(9_999_999).to_s group = Group.create( @@ -10,50 +94,76 @@ class ObjectCacheTest < ActiveSupport::TestCase updated_by_id: 1, created_by_id: 1, ) - group_where = Group.where( name: name ).first - assert_equal( name, group_where[:name], 'verify by where' ) + group_new = Group.where( name: name ).first + assert_equal( name, group_new[:name], 'verify by where' ) - group_lookup_name = Group.lookup( name: name ) - assert_equal( name, group_lookup_name[:name], 'verify by lookup.name' ) + # lookup by name + cache_key = "#{group_new.name}" + assert_nil( Group.cache_get(cache_key) ) + + group_lookup_name = Group.lookup( name: group_new.name ) + assert_equal( group_new.name, group_lookup_name[:name], 'verify by lookup.name' ) + assert( Group.cache_get(cache_key) ) + + # lookup by id + cache_key = "#{group_new.id}" + assert_nil( Group.cache_get(cache_key) ) group_lookup_id = Group.lookup( id: group.id ) - assert_equal( name, group_lookup_id[:name], 'verify by lookup.id' ) + assert_equal( group_new.name, group_lookup_id[:name], 'verify by lookup.id' ) + assert( Group.cache_get(cache_key) ) + # update / check if old name caches are deleted name_new = name + ' next' group.name = name_new group.save - group_where = Group.where( name: name ).first - assert_equal( nil, group_where, 'verify by where name_old' ) + # lookup by name + cache_key = "#{group.name}" + assert_nil( Group.cache_get(cache_key) ) - group_where = Group.where( name: name_new ).first - assert_equal( name_new, group_where[:name], 'verify by where name_new' ) + group_lookup = Group.where( name: group_new.name ).first + assert_nil( group_lookup, 'verify by where name_old' ) + assert_nil( Group.cache_get(cache_key) ) - group_lookup_name = Group.lookup( name: name ) - assert_equal( nil, group_lookup_name, 'verify by lookup.name name_old' ) + group_lookup = Group.where( name: group.name ).first + assert_equal( name_new, group_lookup[:name], 'verify by where name_new' ) + assert_nil( Group.cache_get(cache_key) ) - group_lookup_name = Group.lookup( name: name_new ) + group_lookup_name = Group.lookup( name: group_new.name ) + assert_nil( group_lookup_name, 'verify by lookup.name name_old' ) + assert_nil( Group.cache_get(cache_key) ) + + group_lookup_name = Group.lookup( name: group.name ) assert_equal( name_new, group_lookup_name[:name], 'verify by lookup.name name_new' ) + assert( Group.cache_get(cache_key) ) + + # lookup by id + cache_key = "#{group_new.id}" + assert_nil( Group.cache_get(cache_key) ) group_lookup_id = Group.lookup( id: group.id ) assert_equal( name_new, group_lookup_id[:name], 'verify by lookup.id' ) + assert( Group.cache_get(cache_key) ) group.destroy - group_where = Group.where( name: name ).first - assert_equal( nil, group_where, 'verify by where name_old' ) + # lookup by name + group_lookup = Group.where( name: group_new.name ).first + assert_nil( group_lookup, 'verify by where name_old' ) - group_where = Group.where( name: name_new ).first - assert_equal( nil, group_where, 'verify by where name_new' ) + group_lookup = Group.where( name: group.name ).first + assert_nil( group_lookup, 'verify by where name_new' ) - group_lookup_name = Group.lookup( name: name ) - assert_equal( nil, group_lookup_name, 'verify by lookup.name name_old' ) + group_lookup_name = Group.lookup( name: group_new.name ) + assert_nil( group_lookup_name, 'verify by lookup.name name_old' ) - group_lookup_name = Group.lookup( name: name_new ) - assert_equal( nil, group_lookup_name, 'verify by lookup.name name_new' ) + group_lookup_name = Group.lookup( name: group.name ) + assert_nil( group_lookup_name, 'verify by lookup.name name_new' ) + # lookup by id group_lookup_id = Group.lookup( id: group.id ) - assert_equal( nil, group_lookup_id, 'verify by lookup.id' ) + assert_nil( group_lookup_id, 'verify by lookup.id' ) end end