diff --git a/app/models/application_model.rb b/app/models/application_model.rb index 43fc17679..0d4ba0e14 100644 --- a/app/models/application_model.rb +++ b/app/models/application_model.rb @@ -288,12 +288,30 @@ returns do name/login/email based lookup for associations + params = { + login: 'some login', + firstname: 'some firstname', + lastname: 'some lastname', + email: 'some email', + organization: 'some organization', + roles: ['Agent', 'Admin'], + } + attributes = Model.param_association_lookup(params) returns attributes = params # params with possible lookups + attributes = { + login: 'some login', + firstname: 'some firstname', + lastname: 'some lastname', + email: 'some email', + organization_id: 123, + role_ids: [2,1], + } + =end def self.param_association_lookup(params) @@ -309,33 +327,84 @@ returns value = data[assoc.name.to_sym] next if !value # next if we do not have a value ref_name = "#{assoc.name}_id" - next if !available_attributes.include?(ref_name) # next if we do not have an _id attribute - next if data[ref_name.to_sym] # next if we have already the id filled + + # handle _id values + if available_attributes.include?(ref_name) # if we do have an _id attribute + next if data[ref_name.to_sym] # next if we have already the _id filled + + # get association class and do lookup + class_object = assoc.klass + lookup = nil + if class_object == User + if value.class == String + if !lookup + lookup = class_object.lookup(login: value) + end + if !lookup + lookup = class_object.lookup(email: value) + end + else + raise "String is needed as ref value #{value.inspect} for '#{assoc.name}'" + end + else + lookup = class_object.lookup(name: value) + end + + # complain if we found no reference + if !lookup + raise "No lookup value found for '#{assoc.name}': #{value.inspect}" + end + + # release data value + data.delete(assoc.name.to_sym) + + # remember id reference + data[ref_name.to_sym] = lookup.id + next + end + + next if value.class != Array + next if value.empty? + next if value[0].class != String + + # handle _ids values + ref_names = "#{assoc.name[0, assoc.name.length - 1]}_ids" + generic_object_tmp = new + next unless generic_object_tmp.respond_to?(ref_names) # if we do have an _ids attribute + next if data[ref_names.to_sym] # next if we have already the _ids filled # get association class and do lookup class_object = assoc.klass - lookup = nil - if class_object == User - if !lookup - lookup = class_object.lookup(login: value) + lookup_ids = [] + value.each {|item| + lookup = nil + if class_object == User + if item.class == String + if !lookup + lookup = class_object.lookup(login: item) + end + if !lookup + lookup = class_object.lookup(email: item) + end + else + raise "String is needed in array ref as ref value #{value.inspect} for '#{assoc.name}'" + end + else + lookup = class_object.lookup(name: item) end - if !lookup - lookup = class_object.lookup(email: value) - end - else - lookup = class_object.lookup(name: value) - end - # complain if we found no reference - if !lookup - raise "No lookup value found for '#{assoc.name}': #{value.inspect}" - end + # complain if we found no reference + if !lookup + raise "No lookup value found for '#{assoc.name}': #{item.inspect}" + end + lookup_ids.push lookup.id + } # release data value data.delete(assoc.name.to_sym) # remember id reference - data[ref_name.to_sym] = lookup.id + data[ref_names.to_sym] = lookup_ids } data @@ -613,6 +682,23 @@ returns =begin +Model.create_if_not_exists with ref lookups + + result = Model.create_if_not_exists_with_ref(attributes) + +returns + + result = model # with all attributes + +=end + + def self.create_if_not_exists_with_ref(data) + data = param_association_lookup(data) + create_or_update(data) + end + +=begin + create or update model (check exists based on id, name, login, email or locale) result = Model.create_or_update(attributes) @@ -708,6 +794,23 @@ returns =begin +Model.create_or_update with ref lookups + + result = Model.create_or_update(attributes) + +returns + + result = model # with all attributes + +=end + + def self.create_or_update_with_ref(data) + data = param_association_lookup(data) + create_or_update(data) + end + +=begin + activate latest change on create, update, touch and destroy class Model < ApplicationModel diff --git a/contrib/auto_wizard_test.json b/contrib/auto_wizard_test.json index b0f384d89..dc76492a8 100644 --- a/contrib/auto_wizard_test.json +++ b/contrib/auto_wizard_test.json @@ -12,7 +12,14 @@ "firstname": "Agent 1", "lastname": "Test", "email": "agent1@example.com", - "password": "test" + "password": "test", + "roles": ["Agent"] + } + ], + "Groups": [ + { + "name": "some group1", + "users": ["master@example.com","agent1@example.com"] } ], "Settings": [ diff --git a/lib/auto_wizard.rb b/lib/auto_wizard.rb index 8830b5705..8fc56f413 100644 --- a/lib/auto_wizard.rb +++ b/lib/auto_wizard.rb @@ -33,7 +33,7 @@ returns def self.data auto_wizard_file_location = file_location raise "So such file #{auto_wizard_file_location}" if !File.file?(auto_wizard_file_location) - JSON.parse( File.read(auto_wizard_file_location) ) + JSON.parse(File.read(auto_wizard_file_location)) end =begin @@ -77,38 +77,34 @@ returns } end - # create Organizations - if auto_wizard_hash['Organizations'] - auto_wizard_hash['Organizations'].each { |organization_data| - Organization.create_or_update(organization_data.symbolize_keys) + # create EmailAddresses/Channels/Signatures + model_map = { + 'Organizations' => 'Organization', + } + model_map.each {|map_name, model| + next if !auto_wizard_hash[map_name] + auto_wizard_hash[map_name].each {|data| + generic_object = Kernel.const_get(model) + data.symbolize_keys! + generic_object.create_or_update_with_ref(data) } - end + } # create Users if auto_wizard_hash['Users'] - - roles = Role.where( name: %w(Agent Admin) ) - groups = Group.all - auto_wizard_hash['Users'].each { |user_data| + user_data.symbolize_keys! - # lookup organization - if user_data['organization'] && !user_data['organization'].empty? - organization = Organization.find_by(name: user_data['organization']) - if organization - user_data['organization_id'] = organization.id + if admin_user.id == 1 + if !user_data[:roles] && !user_data[:role_ids] + user_data[:roles] = Role.where(name: %w(Agent Admin)) + end + if !user_data[:groups] && !user_data[:group_ids] + user_data[:groups] = Group.all end end - user_data.delete('organization') - user_data_symbolized = user_data.symbolize_keys.merge( - { - active: true, - roles: roles, - groups: groups, - } - ) - created_user = User.create_or_update(user_data_symbolized) + created_user = User.create_or_update_with_ref(user_data) # use first created user as admin next if admin_user.id != 1 @@ -133,11 +129,9 @@ returns model_map.each {|map_name, model| next if !auto_wizard_hash[map_name] auto_wizard_hash[map_name].each {|data| - if data['id'] || data['name'] - Kernel.const_get(model).create_or_update(data.symbolize_keys) - else - Kernel.const_get(model).create(data.symbolize_keys) - end + generic_object = Kernel.const_get(model) + data.symbolize_keys! + generic_object.create_or_update_with_ref(data) } } diff --git a/test/unit/auto_wizard_test.rb b/test/unit/auto_wizard_test.rb new file mode 100644 index 000000000..2be85c674 --- /dev/null +++ b/test/unit/auto_wizard_test.rb @@ -0,0 +1,170 @@ +# encoding: utf-8 +require 'test_helper' + +class AutoWizardTest < ActiveSupport::TestCase + + test 'simple' do + auto_wizard_data = { + Users: [ + { + login: 'master_unit_test01@example.com', + firstname: 'Test Master', + lastname: 'Agent', + email: 'master_unit_test01@example.com', + password: 'test', + }, + { + login: 'agent1_unit_test01@example.com', + firstname: 'Agent 1', + lastname: 'Test', + email: 'agent1_unit_test01@example.com', + password: 'test', + roles: ['Agent'], + } + ], + Groups: [ + { + name: 'some group1', + users: ['master_unit_test01@example.com', 'agent1_unit_test01@example.com'] + } + ], + Settings: [ + { + name: 'developer_mode', + value: true + }, + { + name: 'product_name', + value: 'Zammad UnitTest01 System' + }, + ] + } + assert_equal(false, AutoWizard.enabled?) + auto_wizard_file_write(auto_wizard_data) + assert_equal(true, AutoWizard.enabled?) + AutoWizard.setup + assert_equal(false, AutoWizard.enabled?) + + # check first user roles + auto_wizard_data[:Users][0][:roles] = %w(Agent Admin) + + auto_wizard_data[:Users].each {|local_user| + user = User.find_by(login: local_user[:login]) + assert_equal(local_user[:login], user.login) + assert_equal(local_user[:firstname], user.firstname) + assert_equal(local_user[:lastname], user.lastname) + assert_equal(local_user[:email], user.email) + assert_equal(local_user[:roles].count, user.role_ids.count) + next unless local_user[:roles] + local_user[:roles].each {|local_role_name| + local_role = Role.find_by(name: local_role_name) + assert(user.role_ids.include?(local_role.id)) + } + } + auto_wizard_data[:Groups].each {|local_group| + group = Group.find_by(name: local_group[:name]) + assert_equal(local_group[:name], group.name) + next unless local_group[:users] + local_group[:users].each {|local_user_login| + local_user = User.find_by(login: local_user_login) + assert(group.user_ids.include?(local_user.id)) + } + } + auto_wizard_data[:Settings].each {|local_setting| + setting_value = Setting.get(local_setting[:name]) + assert_equal(local_setting[:value], setting_value) + } + end + + test 'complex' do + auto_wizard_data = { + Organizations: [ + { + name: 'Auto Wizard Test Org', + shared: false, + } + ], + Users: [ + { + login: 'master_unit_test01@example.com', + firstname: 'Test Master', + lastname: 'Agent', + email: 'master_unit_test01@example.com', + password: 'test', + organization: 'Auto Wizard Test Org', + roles: ['Admin'], + }, + { + login: 'agent1_unit_test01@example.com', + firstname: 'Agent 1', + lastname: 'Test', + email: 'agent1_unit_test01@example.com', + password: 'test', + roles: ['Agent'], + } + ], + Groups: [ + { + name: 'some group1', + users: ['master_unit_test01@example.com', 'agent1_unit_test01@example.com'] + } + ], + Settings: [ + { + name: 'developer_mode', + value: false, + }, + { + name: 'product_name', + value: 'Zammad UnitTest02 System' + }, + ] + } + assert_equal(false, AutoWizard.enabled?) + auto_wizard_file_write(auto_wizard_data) + assert_equal(true, AutoWizard.enabled?) + AutoWizard.setup + assert_equal(false, AutoWizard.enabled?) + + auto_wizard_data[:Users].each {|local_user| + user = User.find_by(login: local_user[:login]) + assert_equal(local_user[:login], user.login) + assert_equal(local_user[:firstname], user.firstname) + assert_equal(local_user[:lastname], user.lastname) + assert_equal(local_user[:email], user.email) + next unless local_user[:roles] + assert_equal(local_user[:roles].count, user.role_ids.count) + local_user[:roles].each {|local_role_name| + local_role = Role.find_by(name: local_role_name) + assert(user.role_ids.include?(local_role.id)) + } + } + auto_wizard_data[:Groups].each {|local_group| + group = Group.find_by(name: local_group[:name]) + assert_equal(local_group[:name], group.name) + next unless local_group[:users] + local_group[:users].each {|local_user_login| + local_user = User.find_by(login: local_user_login) + assert(group.user_ids.include?(local_user.id)) + } + } + auto_wizard_data[:Settings].each {|local_setting| + setting_value = Setting.get(local_setting[:name]) + assert_equal(local_setting[:value], setting_value) + } + end + + def auto_wizard_file_write(data) + location = "#{Rails.root}/auto_wizard.json" + file = File.new(location, 'wb') + file.write(data.to_json) + file.close + end + + def auto_wizard_file_exists? + location = "#{Rails.root}/auto_wizard.json" + return false if File.exist?(location) + true + end + +end diff --git a/test/unit/object_create_update_with_ref_name_test.rb b/test/unit/object_create_update_with_ref_name_test.rb new file mode 100644 index 000000000..a17bc2e9a --- /dev/null +++ b/test/unit/object_create_update_with_ref_name_test.rb @@ -0,0 +1,169 @@ +# encoding: utf-8 +require 'test_helper' + +class ObjectCreateUpdateWithRefNameTest < ActiveSupport::TestCase + test 'organization' do + roles = Role.where(name: %w(Agent Admin)) + groups = Group.all + user1 = User.create_or_update( + login: 'object_ref_name1@example.org', + firstname: 'object_ref_name1', + lastname: 'object_ref_name1', + email: 'object_ref_name1@example.org', + password: 'some_pass', + active: true, + updated_by_id: 1, + created_by_id: 1, + roles: roles, + groups: groups, + ) + user2 = User.create_or_update( + login: 'object_ref_name2@example.org', + firstname: 'object_ref_name2', + lastname: 'object_ref_name2', + email: 'object_ref_name2@example.org', + password: 'some_pass', + active: true, + updated_by_id: 1, + created_by_id: 1, + roles: roles, + groups: groups, + ) + + org1 = Organization.create_if_not_exists_with_ref( + name: 'some org update_with_ref member', + members: ['object_ref_name1@example.org'], + updated_by_id: 1, + created_by_id: 1, + ) + + assert(org1.member_ids.sort.include?(user1.id)) + assert_not(org1.member_ids.sort.include?(user2.id)) + + org2 = Organization.create_or_update_with_ref( + name: 'some org update_with_ref member', + members: ['object_ref_name2@example.org'], + updated_by_id: 1, + created_by_id: 1, + ) + + assert_not(org2.member_ids.sort.include?(user1.id)) + assert(org2.member_ids.sort.include?(user2.id)) + assert_equal(org1.id, org2.id) + + org3 = Organization.create_or_update_with_ref( + name: 'some org update_with_ref member2', + members: ['object_ref_name2@example.org'], + updated_by_id: 1, + created_by_id: 1, + ) + + assert_not(org3.member_ids.sort.include?(user1.id)) + assert(org3.member_ids.sort.include?(user2.id)) + assert_not_equal(org2.id, org3.id) + + assert_raises( ActiveRecord::AssociationTypeMismatch ) { + Organization.create_or_update_with_ref( + name: 'some org update_with_ref member2', + members: ['object_ref_name2@example.org'], + member_ids: [2], + updated_by_id: 1, + created_by_id: 1, + ) + } + + end + + test 'user' do + org1 = Organization.create_if_not_exists_with_ref( + name: 'some org update_with_ref user', + updated_by_id: 1, + created_by_id: 1, + ) + user1 = User.create_or_update_with_ref( + login: 'object_ref_name1@example.org', + firstname: 'object_ref_name1', + lastname: 'object_ref_name1', + email: 'object_ref_name1@example.org', + password: 'some_pass', + active: true, + organization: 'some org update_with_ref user', + updated_by_id: 1, + created_by_id: 1, + roles: %w(Agent Admin), + groups: ['Users'], + ) + user2 = User.create_or_update_with_ref( + login: 'object_ref_name2@example.org', + firstname: 'object_ref_name2', + lastname: 'object_ref_name2', + email: 'object_ref_name2@example.org', + password: 'some_pass', + organization_id: nil, + active: true, + updated_by_id: 1, + created_by_id: 1, + roles: ['Customer'], + groups: [], + ) + admin_role = Role.lookup(name: 'Admin') + agent_role = Role.lookup(name: 'Agent') + customer_role = Role.lookup(name: 'Customer') + + users_group = Group.lookup(name: 'Users') + + assert(user1.organization.name, 'some org update_with_ref user') + assert(user1.group_ids.include?(users_group.id)) + assert(user1.role_ids.include?(admin_role.id)) + assert(user1.role_ids.include?(agent_role.id)) + assert_not(user1.role_ids.include?(customer_role.id)) + + assert_equal(nil, user2.organization_id) + assert_not(user2.group_ids.include?(users_group.id)) + assert_not(user2.role_ids.include?(admin_role.id)) + assert_not(user2.role_ids.include?(agent_role.id)) + assert(user2.role_ids.include?(customer_role.id)) + + end + + test 'group' do + user1 = User.create_or_update_with_ref( + login: 'object_ref_name1@example.org', + firstname: 'object_ref_name1', + lastname: 'object_ref_name1', + email: 'object_ref_name1@example.org', + password: 'some_pass', + active: true, + organization_id: nil, + updated_by_id: 1, + created_by_id: 1, + roles: %w(Agent Admin), + groups: [], + ) + user2 = User.create_or_update_with_ref( + login: 'object_ref_name2@example.org', + firstname: 'object_ref_name2', + lastname: 'object_ref_name2', + email: 'object_ref_name2@example.org', + password: 'some_pass', + organization_id: nil, + active: true, + updated_by_id: 1, + created_by_id: 1, + roles: ['Customer'], + groups: [], + ) + + group1 = Group.create_if_not_exists_with_ref( + name: 'some group update_with_ref', + users: ['object_ref_name1@example.org'], + updated_by_id: 1, + created_by_id: 1, + ) + + assert(group1.name, 'some group update_with_ref') + assert(group1.user_ids.include?(user1.id)) + assert_not(group1.user_ids.include?(user2.id)) + + end +end