Initial generic csv based import of text modules, users, organizations and tickets for model and controller.

This commit is contained in:
Martin Edenhofer 2018-02-20 05:29:30 +01:00
parent 4537a281a3
commit 6a0f5d4c25
30 changed files with 1882 additions and 38 deletions

View file

@ -323,4 +323,43 @@ curl http://localhost/api/v1/organization/{id} -v -u #{login}:#{password} -H "Co
render json: history
end
# @path [GET] /organizations/import_example
#
# @summary Download of example CSV file.
# @notes The requester have 'admin.organization' permissions to be able to download it.
# @example curl -u 'me@example.com:test' http://localhost:3000/api/v1/organizations/import_example
#
# @response_message 200 File download.
# @response_message 401 Invalid session.
def import_example
permission_check('admin.organization')
send_data(
Organization.csv_example,
filename: 'organization-example.csv',
type: 'text/csv',
disposition: 'attachment'
)
end
# @path [POST] /organizations/import
#
# @summary Starts import.
# @notes The requester have 'admin.text_module' permissions to be create a new import.
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/organizations.csv' 'https://your.zammad/api/v1/organizations/import?try=true'
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/organizations.csv' 'https://your.zammad/api/v1/organizations/import'
#
# @response_message 201 Import started.
# @response_message 401 Invalid session.
def import_start
permission_check('admin.user')
result = Organization.csv_import(
string: params[:file].read.force_encoding('utf-8'),
parse_params: {
col_sep: ';',
},
try: params[:try],
)
render json: result, status: :ok
end
end

View file

@ -152,4 +152,48 @@ curl http://localhost/api/v1/text_modules.json -v -u #{login}:#{password} -H "Co
permission_check('admin.text_module')
model_destroy_render(TextModule, params)
end
# @path [GET] /text_modules/import_example
#
# @summary Download of example CSV file.
# @notes The requester have 'admin.text_module' permissions to be able to download it.
# @example curl -u 'me@example.com:test' http://localhost:3000/api/v1/text_modules/import_example
#
# @response_message 200 File download.
# @response_message 401 Invalid session.
def import_example
permission_check('admin.text_module')
csv_string = TextModule.csv_example(
col_sep: ',',
)
send_data(
csv_string,
filename: 'example.csv',
type: 'text/csv',
disposition: 'attachment'
)
end
# @path [POST] /text_modules/import
#
# @summary Starts import.
# @notes The requester have 'admin.text_module' permissions to be create a new import.
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/Textbausteine_final2.csv' 'https://your.zammad/api/v1/text_modules/import?try=true'
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/Textbausteine_final2.csv' 'https://your.zammad/api/v1/text_modules/import'
#
# @response_message 201 Import started.
# @response_message 401 Invalid session.
def import_start
permission_check('admin.text_module')
result = TextModule.csv_import(
string: params[:file].read.force_encoding('utf-8'),
parse_params: {
col_sep: ';',
},
try: params[:try],
)
render json: result, status: :ok
end
end

View file

@ -276,6 +276,52 @@ class TicketArticlesController < ApplicationController
)
end
# @path [GET] /ticket_articles/import_example
#
# @summary Download of example CSV file.
# @notes The requester have 'admin' permissions to be able to download it.
# @example curl -u 'me@example.com:test' http://localhost:3000/api/v1/ticket_articles/import_example
#
# @response_message 200 File download.
# @response_message 401 Invalid session.
def import_example
permission_check('admin')
csv_string = Ticket::Article.csv_example(
col_sep: ',',
)
send_data(
csv_string,
filename: 'example.csv',
type: 'text/csv',
disposition: 'attachment'
)
end
# @path [POST] /ticket_articles/import
#
# @summary Starts import.
# @notes The requester have 'admin' permissions to be create a new import.
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/ticket_articles.csv' 'https://your.zammad/api/v1/ticket_articles/import?try=true'
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/ticket_articles.csv' 'https://your.zammad/api/v1/ticket_articles/import'
#
# @response_message 201 Import started.
# @response_message 401 Invalid session.
def import_start
permission_check('admin')
if Setting.get('import_mode') != true
raise 'Only can import tickets if system is in import mode.'
end
result = Ticket::Article.csv_import(
string: params[:file].read.force_encoding('utf-8'),
parse_params: {
col_sep: ';',
},
try: params[:try],
)
render json: result, status: :ok
end
private
def sanitized_disposition

View file

@ -598,6 +598,52 @@ class TicketsController < ApplicationController
}
end
# @path [GET] /tickets/import_example
#
# @summary Download of example CSV file.
# @notes The requester have 'admin' permissions to be able to download it.
# @example curl -u 'me@example.com:test' http://localhost:3000/api/v1/tickets/import_example
#
# @response_message 200 File download.
# @response_message 401 Invalid session.
def import_example
permission_check('admin')
csv_string = Ticket.csv_example(
col_sep: ',',
)
send_data(
csv_string,
filename: 'example.csv',
type: 'text/csv',
disposition: 'attachment'
)
end
# @path [POST] /tickets/import
#
# @summary Starts import.
# @notes The requester have 'admin' permissions to be create a new import.
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/tickets.csv' 'https://your.zammad/api/v1/tickets/import?try=true'
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/tickets.csv' 'https://your.zammad/api/v1/tickets/import'
#
# @response_message 201 Import started.
# @response_message 401 Invalid session.
def import_start
permission_check('admin')
if Setting.get('import_mode') != true
raise 'Only can import tickets if system is in import mode.'
end
result = Ticket.csv_import(
string: params[:file].read.force_encoding('utf-8'),
parse_params: {
col_sep: ';',
},
try: params[:try],
)
render json: result, status: :ok
end
private
def follow_up_possible_check

View file

@ -1061,6 +1061,45 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content
render json: { avatars: result }, status: :ok
end
# @path [GET] /users/import_example
#
# @summary Download of example CSV file.
# @notes The requester have 'admin.user' permissions to be able to download it.
# @example curl -u 'me@example.com:test' http://localhost:3000/api/v1/users/import_example
#
# @response_message 200 File download.
# @response_message 401 Invalid session.
def import_example
permission_check('admin.user')
send_data(
User.csv_example,
filename: 'user-example.csv',
type: 'text/csv',
disposition: 'attachment'
)
end
# @path [POST] /users/import
#
# @summary Starts import.
# @notes The requester have 'admin.text_module' permissions to be create a new import.
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/users.csv' 'https://your.zammad/api/v1/users/import?try=true'
# @example curl -u 'me@example.com:test' -F 'file=@/path/to/file/users.csv' 'https://your.zammad/api/v1/users/import'
#
# @response_message 201 Import started.
# @response_message 401 Invalid session.
def import_start
permission_check('admin.user')
result = User.csv_import(
string: params[:file].read.force_encoding('utf-8'),
parse_params: {
col_sep: ';',
},
try: params[:try],
)
render json: result, status: :ok
end
private
def password_policy(password)

View file

@ -63,6 +63,9 @@ returns
real_values = real_values.to_sym
next if !respond_to?(real_values)
next if !params[real_values]
if params[real_values].instance_of?(String) || params[real_values].instance_of?(Integer) || params[real_values].instance_of?(Float)
params[real_values] = [params[real_values]]
end
next if !params[real_values].instance_of?(Array)
list = []
class_object = assoc.klass

View file

@ -39,11 +39,10 @@ returns
where(name: data[:name])
end
records.each do |loop_record|
if loop_record.name == data[:name]
next if loop_record.name != data[:name]
cache_set(data[:name], loop_record)
return loop_record
end
end
return
elsif data[:login]
cache = cache_get(data[:login])
@ -56,11 +55,10 @@ returns
where(login: data[:login])
end
records.each do |loop_record|
if loop_record.login == data[:login]
next if loop_record.login != data[:login]
cache_set(data[:login], loop_record)
return loop_record
end
end
return
elsif data[:email]
cache = cache_get(data[:email])
@ -73,15 +71,27 @@ returns
where(email: data[:email])
end
records.each do |loop_record|
if loop_record.email == data[:email]
next if loop_record.email != data[:email]
cache_set(data[:email], loop_record)
return loop_record
end
return
elsif data[:number]
# do lookup with == to handle case insensitive databases
records = if Rails.application.config.db_case_sensitive
where('LOWER(number) = LOWER(?)', data[:number])
else
where(number: data[:number])
end
records.each do |loop_record|
next if loop_record.number != data[:number]
return loop_record
end
return
end
raise ArgumentError, 'Need name, id, login or email for lookup()'
raise ArgumentError, 'Need name, id, number, login or email for lookup()'
end
end
end

View file

@ -0,0 +1,351 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
require 'csv'
module CanCsvImport
extend ActiveSupport::Concern
# methods defined here are going to extend the class, not the instance of it
class_methods do
=begin
result = Model.csv_import(
string: csv_string,
parse_params: {
col_sep: ',',
},
try: true,
)
result = Model.csv_import(
file: '/file/location/of/file.csv',
parse_params: {
col_sep: ',',
},
try: true,
)
result = TextModule.csv_import(
file: '/Users/me/Downloads/Textbausteine_final.csv',
parse_params: {
col_sep: ',',
},
try: false,
)
returns
{
records: [record1, ...]
try: true, # true|false
success: true, # true|false
}
=end
def csv_import(data)
if data[:file].present?
raise Exceptions::UnprocessableEntity, "No such file '#{data[:file]}'" if !File.exist?(data[:file])
begin
file = File.open(data[:file], 'r:UTF-8')
data[:string] = file.read
rescue => e
raise Exceptions::UnprocessableEntity, "Unable to read file '#{data[:file]}': #{e.inspect}"
end
end
if data[:string].blank?
raise Exceptions::UnprocessableEntity, 'Unable to parse empty file/string!'
end
rows = CSV.parse(data[:string], data[:parse_params])
header = rows.shift
if header.blank?
raise Exceptions::UnprocessableEntity, 'Unable to parse file/string without header!'
end
header.each do |item|
if item.respond_to?(:strip!)
item.strip!
end
next if !item.respond_to?(:downcase!)
item.downcase!
end
# get payload based on csv
payload = []
rows.each do |row|
if row[0].blank? && row[1].blank?
payload_last = payload.last
row.each_with_index do |item, count|
next if item.blank?
if payload_last[header[count].to_sym].class != Array
payload_last[header[count].to_sym] = [payload_last[header[count].to_sym]]
end
payload_last[header[count].to_sym].push item.strip
end
next
end
attributes = {}
row.each_with_index do |item, count|
next if !item
next if header[count].blank?
next if @csv_attributes_ignored&.include?(header[count].to_sym)
attributes[header[count].to_sym] = if item.respond_to?(:strip)
item.strip
else
item
end
end
data[:fixed_params]&.each do |key, value|
attributes[key] = value
end
payload.push attributes
end
# create or update records
csv_object_ids_ignored = @csv_object_ids_ignored || []
records = []
stats = {
created: 0,
updated: 0,
}
errors = []
line_count = 0
payload.each do |attributes|
line_count += 1
record = nil
%i[id number name login email].each do |lookup_by|
next if !attributes[lookup_by]
params = {}
params[lookup_by] = attributes[lookup_by]
record = lookup(params)
break if record
end
if attributes[:id].present? && !record
errors.push "Line #{line_count}: unknown record with id '#{attributes[:id]}' for #{new.class}."
next
end
if record && csv_object_ids_ignored.include?(record.id)
errors.push "Line #{line_count}: unable to update record with id '#{attributes[:id]}' for #{new.class}."
next
end
begin
clean_params = association_name_to_id_convert(attributes)
rescue => e
errors.push "Line #{line_count}: #{e.message}"
next
end
# create object
Transaction.execute(disable_notification: true, reset_user_id: true) do
UserInfo.current_user_id = clean_params[:updated_by_id] || clean_params[:created_by_id]
if !record
stats[:created] += 1
begin
csv_verify_attributes(clean_params)
clean_params = param_cleanup(clean_params)
if !UserInfo.current_user_id
clean_params[:created_by_id] = 1
clean_params[:updated_by_id] = 1
end
record = new(clean_params)
next if data[:try] == 'true' || data[:try] == true
record.associations_from_param(attributes)
record.save!
rescue => e
errors.push "Line #{line_count}: #{e.message}"
next
end
else
stats[:updated] += 1
next if data[:try] == 'true' || data[:try] == true
begin
csv_verify_attributes(clean_params)
clean_params = param_cleanup(clean_params)
if !UserInfo.current_user_id
clean_params[:updated_by_id] = 1
end
record.with_lock do
record.associations_from_param(attributes)
record.update_attributes!(clean_params)
end
rescue => e
errors.push "Line #{line_count}: #{e.message}"
next
end
end
end
records.push record
end
result = 'success'
if errors.present?
result = 'failed'
end
{
stats: stats,
records: records,
errors: errors,
try: data[:try],
result: result,
}
end
=begin
verify if attributes are valid, will raise an ArgumentError with "unknown attribute '#{key}' for #{new.class}."
Model.csv_verify_attributes({'attribute': 'some value'})
=end
def csv_verify_attributes(clean_params)
all_clean_attributes = {}
new.attributes.each_key do |attribute|
all_clean_attributes[attribute.to_sym] = true
end
reflect_on_all_associations.map do |assoc|
all_clean_attributes[assoc.name.to_sym] = true
ref = if assoc.name.to_s.end_with?('_id')
"#{assoc.name}_id"
else
"#{assoc.name.to_s.chop}_ids"
end
all_clean_attributes[ref.to_sym] = true
end
clean_params.each_key do |key|
next if all_clean_attributes.key?(key.to_sym)
raise ArgumentError, "unknown attribute '#{key}' for #{new.class}."
end
true
end
=begin
csv_string = Model.csv_example(
col_sep: ',',
)
returns
csv_string
=end
def csv_example(params = {})
header = []
csv_object_ids_ignored = @csv_object_ids_ignored || []
records = where.not(id: csv_object_ids_ignored).offset(1).limit(23).to_a
if records.count < 20
record_ids = records.pluck(:id).concat(csv_object_ids_ignored)
local_records = where.not(id: record_ids).limit(20 - records.count)
records = records.concat(local_records)
end
records_attributes_with_association_names = []
records.each do |record|
record_attributes_with_association_names = record.attributes_with_association_names
records_attributes_with_association_names.push record_attributes_with_association_names
record_attributes_with_association_names.each do |key, value|
next if value.class == ActiveSupport::HashWithIndifferentAccess
next if value.class == Hash
next if @csv_attributes_ignored&.include?(key.to_sym)
next if key.match?(/_id$/)
next if key.match?(/_ids$/)
next if key == 'created_by'
next if key == 'updated_by'
next if key == 'created_at'
next if key == 'updated_at'
next if header.include?(key)
header.push key
end
end
rows = []
records_attributes_with_association_names.each do |record|
row = []
rows_to_add = []
position = -1
header.each do |key|
position += 1
if record[key].class == ActiveSupport::TimeWithZone
row.push record[key].iso8601
next
end
if record[key].class == Array
entry_count = -2
record[key].each do |entry|
entry_count += 1
next if entry_count == -1
if !rows_to_add[entry_count]
rows_to_add[entry_count] = Array.new(header.count + 1) { '' }
end
rows_to_add[entry_count][position] = entry
end
record[key] = record[key][0]
end
row.push record[key]
end
rows.push row
next unless rows_to_add.count.positive?
rows_to_add.each do |item|
rows.push item
end
rows_to_add = []
end
CSV.generate(params) do |csv|
csv << header
rows.each do |row|
csv << row
end
end
end
=begin
serve methode to ignore model based on id
class Model < ApplicationModel
include CanCsvImport
csv_object_ids_ignored(1, 2, 3)
end
=end
def csv_object_ids_ignored(*object_ids)
@csv_object_ids_ignored = object_ids
end
=begin
serve methode to ignore model attributes
class Model < ApplicationModel
include CanCsvImport
csv_attributes_ignored :password,
:image_source,
:login_failed,
:source,
:image_source,
:image,
:authorizations,
:organizations
end
=end
def csv_attributes_ignored(*attributes)
@csv_attributes_ignored = attributes
end
end
end

View file

@ -6,6 +6,7 @@ class Organization < ApplicationModel
include ChecksLatestChangeObserved
include HasHistory
include HasSearchIndexBackend
include CanCsvImport
include Organization::ChecksAccess
load 'organization/assets.rb'

View file

@ -3,10 +3,14 @@
class TextModule < ApplicationModel
include ChecksClientNotification
include ChecksHtmlSanitized
include CanCsvImport
validates :name, presence: true
validates :content, presence: true
before_create :validate_content
before_update :validate_content
sanitized_html :content
=begin
@ -97,4 +101,14 @@ push text_modules to online
true
end
private
def validate_content
return true if content.blank?
return true if content.match?(/<.+?>/)
content.gsub!(/(\r\n|\n\r|\r)/, "\n")
self.content = content.text2html
true
end
end

View file

@ -4,6 +4,7 @@ class Ticket < ApplicationModel
include HasActivityStreamLog
include ChecksClientNotification
include ChecksLatestChangeObserved
include CanCsvImport
include HasHistory
include HasTags
include HasSearchIndexBackend

View file

@ -4,6 +4,7 @@ class Ticket::Article < ApplicationModel
include ChecksClientNotification
include HasHistory
include ChecksHtmlSanitized
include CanCsvImport
include Ticket::Article::ChecksAccess
load 'ticket/article/assets.rb'

View file

@ -28,6 +28,7 @@ class User < ApplicationModel
include ChecksClientNotification
include HasHistory
include HasSearchIndexBackend
include CanCsvImport
include HasGroups
include HasRoles
include User::ChecksAccess
@ -74,6 +75,18 @@ class User < ApplicationModel
:source,
:login_failed
csv_object_ids_ignored 1
csv_attributes_ignored :password,
:login_failed,
:source,
:image_source,
:image,
:authorizations,
:organizations,
:groups,
:user_groups
def ignore_search_indexing?(_action)
# ignore internal user
return true if id == 1

View file

@ -2,6 +2,8 @@ Zammad::Application.routes.draw do
api_path = Rails.configuration.api_path
# organizations
match api_path + '/organizations/import_example', to: 'organizations#import_example', via: :get
match api_path + '/organizations/import', to: 'organizations#import_start', via: :post
match api_path + '/organizations/search', to: 'organizations#search', via: %i[get post]
match api_path + '/organizations', to: 'organizations#index', via: :get
match api_path + '/organizations/:id', to: 'organizations#show', via: :get

View file

@ -2,6 +2,8 @@ Zammad::Application.routes.draw do
api_path = Rails.configuration.api_path
# text_modules
match api_path + '/text_modules/import_example', to: 'text_modules#import_example', via: :get
match api_path + '/text_modules/import', to: 'text_modules#import_start', via: :post
match api_path + '/text_modules', to: 'text_modules#index', via: :get
match api_path + '/text_modules/:id', to: 'text_modules#show', via: :get
match api_path + '/text_modules', to: 'text_modules#create', via: :post

View file

@ -2,7 +2,7 @@ Zammad::Application.routes.draw do
api_path = Rails.configuration.api_path
# users
match api_path + '/users/search', to: 'users#search', via: %i[get post]
match api_path + '/users/search', to: 'users#search', via: %i[get post option]
match api_path + '/users/recent', to: 'users#recent', via: %i[get post]
match api_path + '/users/password_reset', to: 'users#password_reset_send', via: :post
match api_path + '/users/password_reset_verify', to: 'users#password_reset_verify', via: :post
@ -11,6 +11,9 @@ Zammad::Application.routes.draw do
match api_path + '/users/out_of_office', to: 'users#out_of_office', via: :put
match api_path + '/users/account', to: 'users#account_remove', via: :delete
match api_path + '/users/import_example', to: 'users#import_example', via: :get
match api_path + '/users/import', to: 'users#import_start', via: :post
match api_path + '/users/avatar', to: 'users#avatar_new', via: :post
match api_path + '/users/avatar', to: 'users#avatar_list', via: :get
match api_path + '/users/avatar', to: 'users#avatar_destroy', via: :delete

View file

@ -14,17 +14,6 @@ class OrganizationControllerTest < ActionDispatch::IntegrationTest
UserInfo.current_user_id = 1
@backup_admin = User.create_or_update(
login: 'backup-admin',
firstname: 'Backup',
lastname: 'Agent',
email: 'backup-admin@example.com',
password: 'adminpw',
active: true,
roles: roles,
groups: groups,
)
@admin = User.create_or_update(
login: 'rest-admin',
firstname: 'Rest',
@ -510,4 +499,110 @@ class OrganizationControllerTest < ActionDispatch::IntegrationTest
end
test '05.01 csv example - customer no access' do
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-customer1@example.com', 'customer1pw')
get '/api/v1/organizations/import_example', params: {}, headers: @headers.merge('Authorization' => credentials)
assert_response(401)
result = JSON.parse(@response.body)
assert_equal('Not authorized (user)!', result['error'])
end
test '05.02 csv example - admin access' do
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'adminpw')
get '/api/v1/organizations/import_example', params: {}, headers: @headers.merge('Authorization' => credentials)
assert_response(200)
rows = CSV.parse(@response.body)
header = rows.shift
assert_equal('id', header[0])
assert_equal('name', header[1])
assert_equal('shared', header[2])
assert_equal('domain', header[3])
assert_equal('domain_assignment', header[4])
assert_equal('active', header[5])
assert_equal('note', header[6])
assert(header.include?('members'))
end
test '05.03 csv import - admin access' do
UserInfo.current_user_id = 1
customer1 = User.create_or_update(
login: 'customer1-members@example.com',
firstname: 'Member',
lastname: 'Customer',
email: 'customer1-members@example.com',
password: 'customerpw',
active: true,
)
customer2 = User.create_or_update(
login: 'customer2-members@example.com',
firstname: 'Member',
lastname: 'Customer',
email: 'customer2-members@example.com',
password: 'customerpw',
active: true,
)
UserInfo.current_user_id = nil
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'adminpw')
# invalid file
csv_file = ::Rack::Test::UploadedFile.new(Rails.root.join('test', 'fixtures', 'csv', 'organization_simple_col_not_existing.csv'), 'text/csv')
post '/api/v1/organizations/import?try=true', params: { file: csv_file }, headers: { 'Authorization' => credentials }
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('true', result['try'])
assert_equal(2, result['records'].count)
assert_equal('failed', result['result'])
assert_equal(2, result['errors'].count)
assert_equal("Line 1: unknown attribute 'name2' for Organization.", result['errors'][0])
assert_equal("Line 2: unknown attribute 'name2' for Organization.", result['errors'][1])
# valid file try
csv_file = ::Rack::Test::UploadedFile.new(Rails.root.join('test', 'fixtures', 'csv', 'organization_simple.csv'), 'text/csv')
post '/api/v1/organizations/import?try=true', params: { file: csv_file }, headers: { 'Authorization' => credentials }
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('true', result['try'])
assert_equal(2, result['records'].count)
assert_equal('success', result['result'])
assert_nil(Organization.find_by(name: 'organization-member-import1'))
assert_nil(Organization.find_by(name: 'organization-member-import2'))
# valid file
csv_file = ::Rack::Test::UploadedFile.new(Rails.root.join('test', 'fixtures', 'csv', 'organization_simple.csv'), 'text/csv')
post '/api/v1/organizations/import', params: { file: csv_file }, headers: { 'Authorization' => credentials }
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_nil(result['try'])
assert_equal(2, result['records'].count)
assert_equal('success', result['result'])
organization1 = Organization.find_by(name: 'organization-member-import1')
assert(organization1)
assert_equal(organization1.name, 'organization-member-import1')
assert_equal(organization1.members.count, 1)
assert_equal(organization1.members.first.login, customer1.login)
assert_equal(organization1.active, true)
organization2 = Organization.find_by(name: 'organization-member-import2')
assert(organization2)
assert_equal(organization2.name, 'organization-member-import2')
assert_equal(organization2.members.count, 1)
assert_equal(organization2.members.first.login, customer2.login)
assert_equal(organization2.active, false)
end
end

View file

@ -0,0 +1,157 @@
require 'test_helper'
require 'rake'
class TextModuleControllerTest < ActionDispatch::IntegrationTest
setup do
# set accept header
@headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
# create agent
roles = Role.where(name: %w[Admin Agent])
groups = Group.all
UserInfo.current_user_id = 1
@admin = User.create_or_update(
login: 'rest-admin',
firstname: 'Rest',
lastname: 'Agent',
email: 'rest-admin@example.com',
password: 'adminpw',
active: true,
roles: roles,
groups: groups,
)
# create agent
roles = Role.where(name: 'Agent')
@agent = User.create_or_update(
login: 'rest-agent@example.com',
firstname: 'Rest',
lastname: 'Agent',
email: 'rest-agent@example.com',
password: 'agentpw',
active: true,
roles: roles,
groups: groups,
)
# create customer without org
roles = Role.where(name: 'Customer')
@customer_without_org = User.create_or_update(
login: 'rest-customer1@example.com',
firstname: 'Rest',
lastname: 'Customer1',
email: 'rest-customer1@example.com',
password: 'customer1pw',
active: true,
roles: roles,
)
# create customer
@customer_with_org = User.create_or_update(
login: 'rest-customer2@example.com',
firstname: 'Rest',
lastname: 'Customer2',
email: 'rest-customer2@example.com',
password: 'customer2pw',
active: true,
roles: roles,
)
UserInfo.current_user_id = nil
end
test '05.01 csv example - customer no access' do
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-customer1@example.com', 'customer1pw')
get '/api/v1/text_modules/import_example', params: {}, headers: @headers.merge('Authorization' => credentials)
assert_response(401)
result = JSON.parse(@response.body)
assert_equal('Not authorized (user)!', result['error'])
end
test '05.02 csv example - admin access' do
TextModule.load('en-en')
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'adminpw')
get '/api/v1/text_modules/import_example', params: {}, headers: @headers.merge('Authorization' => credentials)
assert_response(200)
rows = CSV.parse(@response.body)
header = rows.shift
assert_equal('id', header[0])
assert_equal('name', header[1])
assert_equal('keywords', header[2])
assert_equal('content', header[3])
assert_equal('note', header[4])
assert_equal('active', header[5])
assert_not(header.include?('organization'))
assert_not(header.include?('priority'))
assert_not(header.include?('state'))
assert_not(header.include?('owner'))
assert_not(header.include?('customer'))
end
test '05.03 csv import - admin access' do
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'adminpw')
# invalid file
csv_file = ::Rack::Test::UploadedFile.new(Rails.root.join('test', 'fixtures', 'csv', 'text_module_simple_col_not_existing.csv'), 'text/csv')
post '/api/v1/text_modules/import?try=true', params: { file: csv_file }, headers: { 'Authorization' => credentials }
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('true', result['try'])
assert_equal(2, result['records'].count)
assert_equal('failed', result['result'])
assert_equal(2, result['errors'].count)
assert_equal("Line 1: unknown attribute 'keywords2' for TextModule.", result['errors'][0])
assert_equal("Line 2: unknown attribute 'keywords2' for TextModule.", result['errors'][1])
# valid file try
csv_file = ::Rack::Test::UploadedFile.new(Rails.root.join('test', 'fixtures', 'csv', 'text_module_simple.csv'), 'text/csv')
post '/api/v1/text_modules/import?try=true', params: { file: csv_file }, headers: { 'Authorization' => credentials }
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('true', result['try'])
assert_equal(2, result['records'].count)
assert_equal('success', result['result'])
assert_nil(TextModule.find_by(name: 'some name1'))
assert_nil(TextModule.find_by(name: 'some name2'))
# valid file
csv_file = ::Rack::Test::UploadedFile.new(Rails.root.join('test', 'fixtures', 'csv', 'text_module_simple.csv'), 'text/csv')
post '/api/v1/text_modules/import', params: { file: csv_file }, headers: { 'Authorization' => credentials }
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_nil(result['try'])
assert_equal(2, result['records'].count)
assert_equal('success', result['result'])
text_module1 = TextModule.find_by(name: 'some name1')
assert(text_module1)
assert_equal(text_module1.name, 'some name1')
assert_equal(text_module1.keywords, 'keyword1')
assert_equal(text_module1.content, 'some<br>content1')
assert_equal(text_module1.active, true)
text_module2 = TextModule.find_by(name: 'some name2')
assert(text_module2)
assert_equal(text_module2.name, 'some name2')
assert_equal(text_module2.keywords, 'keyword2')
assert_equal(text_module2.content, 'some content<br>test123')
assert_equal(text_module2.active, true)
end
end

View file

@ -957,4 +957,93 @@ class UserControllerTest < ActionDispatch::IntegrationTest
end
test '05.01 csv example - customer no access' do
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-customer1@example.com', 'customer1pw')
get '/api/v1/users/import_example', params: {}, headers: @headers.merge('Authorization' => credentials)
assert_response(401)
result = JSON.parse(@response.body)
assert_equal('Not authorized (user)!', result['error'])
end
test '05.02 csv example - admin access' do
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'adminpw')
get '/api/v1/users/import_example', params: {}, headers: @headers.merge('Authorization' => credentials)
assert_response(200)
rows = CSV.parse(@response.body)
header = rows.shift
assert_equal('id', header[0])
assert_equal('login', header[1])
assert_equal('firstname', header[2])
assert_equal('lastname', header[3])
assert_equal('email', header[4])
assert(header.include?('organization'))
end
test '05.03 csv import - admin access' do
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'adminpw')
# invalid file
csv_file = ::Rack::Test::UploadedFile.new(Rails.root.join('test', 'fixtures', 'csv', 'user_simple_col_not_existing.csv'), 'text/csv')
post '/api/v1/users/import?try=true', params: { file: csv_file }, headers: { 'Authorization' => credentials }
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('true', result['try'])
assert_equal(2, result['records'].count)
assert_equal('failed', result['result'])
assert_equal(2, result['errors'].count)
assert_equal("Line 1: unknown attribute 'firstname2' for User.", result['errors'][0])
assert_equal("Line 2: unknown attribute 'firstname2' for User.", result['errors'][1])
# valid file try
csv_file = ::Rack::Test::UploadedFile.new(Rails.root.join('test', 'fixtures', 'csv', 'user_simple.csv'), 'text/csv')
post '/api/v1/users/import?try=true', params: { file: csv_file }, headers: { 'Authorization' => credentials }
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('true', result['try'])
assert_equal(2, result['records'].count)
assert_equal('success', result['result'])
assert_nil(User.find_by(login: 'user-simple-import1'))
assert_nil(User.find_by(login: 'user-simple-import2'))
# valid file
csv_file = ::Rack::Test::UploadedFile.new(Rails.root.join('test', 'fixtures', 'csv', 'user_simple.csv'), 'text/csv')
post '/api/v1/users/import', params: { file: csv_file }, headers: { 'Authorization' => credentials }
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_nil(result['try'])
assert_equal(2, result['records'].count)
assert_equal('success', result['result'])
user1 = User.find_by(login: 'user-simple-import1')
assert(user1)
assert_equal(user1.login, 'user-simple-import1')
assert_equal(user1.firstname, 'firstname-simple-import1')
assert_equal(user1.lastname, 'lastname-simple-import1')
assert_equal(user1.email, 'user-simple-import1@example.com')
assert_equal(user1.active, true)
user2 = User.find_by(login: 'user-simple-import2')
assert(user2)
assert_equal(user2.login, 'user-simple-import2')
assert_equal(user2.firstname, 'firstname-simple-import2')
assert_equal(user2.lastname, 'lastname-simple-import2')
assert_equal(user2.email, 'user-simple-import2@example.com')
assert_equal(user2.active, false)
user1.destroy!
user2.destroy!
end
end

View file

@ -0,0 +1,4 @@
id;name;members;active
;organization-member-import1;customer1-members@example.com
;organization-member-import2;customer2-members@example.com;false
1 id;name;members;active
2 ;organization-member-import1;customer1-members@example.com
3 ;organization-member-import2;customer2-members@example.com;false

View file

@ -0,0 +1,3 @@
id;name2;shared;domain;domain_assignment;active;note
;org-simple-import1;true;org-simple-import1.example.com;false;true;some note1
;org-simple-import2;true;org-simple-import2.example.com;false;false;some note2
1 id name2 shared domain domain_assignment active note
2 org-simple-import1 true org-simple-import1.example.com false true some note1
3 org-simple-import2 true org-simple-import2.example.com false false some note2

View file

@ -0,0 +1,4 @@
name;keywords;content;note;active;
some name1;keyword1;"some
content1";-;
some name2;keyword2;some content<br>test123
Can't render this file because it has a wrong number of fields in line 2.

View file

@ -0,0 +1,3 @@
name;keywords2;content;note;active;
some name1;keyword1;"some content1";-;
some name2;keyword2;some content<br>test123
Can't render this file because it has a wrong number of fields in line 2.

3
test/fixtures/csv/user_simple.csv vendored Normal file
View file

@ -0,0 +1,3 @@
login;firstname;lastname;email;active;
user-simple-import1;firstname-simple-import1;lastname-simple-import1;user-simple-import1@example.com;true
user-simple-import2;firstname-simple-import2;lastname-simple-import2;user-simple-import2@example.com;false
1 login;firstname;lastname;email;active;
2 user-simple-import1;firstname-simple-import1;lastname-simple-import1;user-simple-import1@example.com;true
3 user-simple-import2;firstname-simple-import2;lastname-simple-import2;user-simple-import2@example.com;false

View file

@ -0,0 +1,3 @@
login;firstname2;lastname;email;active;
user-simple-import1;firstname-simple-import1;lastname-simple-import1;user-simple-import1@example.com;true
user-simple-import2;firstname-simple-import2;lastname-simple-import2;user-simple-import2@example.com;false
1 login;firstname2;lastname;email;active;
2 user-simple-import1;firstname-simple-import1;lastname-simple-import1;user-simple-import1@example.com;true
3 user-simple-import2;firstname-simple-import2;lastname-simple-import2;user-simple-import2@example.com;false

View file

@ -0,0 +1,209 @@
require 'test_helper'
class OrganizationCsvImportTest < ActiveSupport::TestCase
test 'import example verify' do
csv_string = Organization.csv_example
rows = CSV.parse(csv_string)
header = rows.shift
assert_equal('id', header[0])
assert_equal('name', header[1])
assert_equal('shared', header[2])
assert_equal('domain', header[3])
assert_equal('domain_assignment', header[4])
assert_equal('active', header[5])
assert_equal('note', header[6])
assert(header.include?('members'))
end
test 'simple import' do
csv_string = "id;name;shared;domain;domain_assignment;active;note\n;org-simple-import1;true;org-simple-import1.example.com;false;true;some note1\n;org-simple-import2;true;org-simple-import2.example.com;false;false;some note2\n"
result = Organization.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
assert_nil(Organization.find_by(name: 'org-simple-import1'))
assert_nil(Organization.find_by(name: 'org-simple-import2'))
result = Organization.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
organization1 = Organization.find_by(name: 'org-simple-import1')
assert(organization1)
assert_equal(organization1.name, 'org-simple-import1')
assert_equal(organization1.shared, true)
assert_equal(organization1.domain, 'org-simple-import1.example.com')
assert_equal(organization1.domain_assignment, false)
assert_equal(organization1.note, 'some note1')
assert_equal(organization1.active, true)
organization2 = Organization.find_by(name: 'org-simple-import2')
assert(organization2)
assert_equal(organization2.name, 'org-simple-import2')
assert_equal(organization2.shared, true)
assert_equal(organization2.domain, 'org-simple-import2.example.com')
assert_equal(organization2.domain_assignment, false)
assert_equal(organization2.note, 'some note2')
assert_equal(organization2.active, false)
organization1.destroy!
organization2.destroy!
end
test 'simple import with invalid id' do
csv_string = "id;name;shared;domain;domain_assignment;active;note;\n999999999;organization-simple-invalid_id-import1;\n;organization-simple-invalid_id-import2;\n"
result = Organization.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(1, result[:errors].count)
assert_equal('failed', result[:result])
assert_equal("Line 1: unknown record with id '999999999' for Organization.", result[:errors][0])
assert_nil(Organization.find_by(name: 'organization-simple-invalid_id-import1'))
assert_nil(Organization.find_by(name: 'organization-simple-invalid_id-import2'))
result = Organization.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(1, result[:records].count)
assert_equal('failed', result[:result])
assert_nil(Organization.find_by(name: 'organization-simple-invalid_id-import1'))
organization2 = Organization.find_by(name: 'organization-simple-invalid_id-import2')
assert(organization2)
assert_equal(organization2.name, 'organization-simple-invalid_id-import2')
assert_equal(organization2.active, true)
organization2.destroy!
end
test 'simple import with members' do
UserInfo.current_user_id = 1
name = rand(999_999_999)
customer1 = User.create_or_update(
login: "customer1-members#{name}@example.com",
firstname: 'Member',
lastname: "Customer#{name}",
email: "customer1-members#{name}@example.com",
password: 'customerpw',
active: true,
)
customer2 = User.create_or_update(
login: "customer2-members#{name}@example.com",
firstname: 'Member',
lastname: "Customer#{name}",
email: "customer2-members#{name}@example.com",
password: 'customerpw',
active: true,
)
csv_string = "id;name;members;\n;organization-member-import1;\n;organization-member-import2;#{customer1.email}\n;;#{customer2.email}"
result = Organization.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
assert_nil(Organization.find_by(name: 'organization-member-import1'))
assert_nil(Organization.find_by(name: 'organization-member-import2'))
result = Organization.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
organization1 = Organization.find_by(name: 'organization-member-import1')
assert(organization1)
assert_equal(organization1.name, 'organization-member-import1')
assert_equal(organization1.members.count, 0)
organization2 = Organization.find_by(name: 'organization-member-import2')
assert(organization2)
assert_equal(organization2.name, 'organization-member-import2')
assert_equal(organization2.members.count, 2)
customer1.destroy!
customer2.destroy!
organization1.destroy!
organization2.destroy!
end
test 'invalid attributes' do
csv_string = "name;note;not existing\norganization-invalid-import1;some note;abc\norganization-invalid-import2;some other note;123; with not exsiting header\n"
result = Organization.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(2, result[:errors].count)
assert_equal('failed', result[:result])
assert_equal("Line 1: unknown attribute 'not existing' for Organization.", result[:errors][0])
assert_equal("Line 2: unknown attribute 'not existing' for Organization.", result[:errors][1])
assert_nil(Organization.find_by(name: 'organization-invalid-import1'))
assert_nil(Organization.find_by(name: 'organization-invalid-import2'))
result = Organization.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(2, result[:errors].count)
assert_equal('failed', result[:result])
assert_equal("Line 1: unknown attribute 'not existing' for Organization.", result[:errors][0])
assert_equal("Line 2: unknown attribute 'not existing' for Organization.", result[:errors][1])
assert_nil(Organization.find_by(name: 'organization-invalid-import1'))
assert_nil(Organization.find_by(name: 'organization-invalid-import2'))
end
end

View file

@ -0,0 +1,72 @@
require 'test_helper'
class TextModuleCsvImportTest < ActiveSupport::TestCase
test 'import example verify' do
TextModule.load('en-en')
csv_string = TextModule.csv_example
rows = CSV.parse(csv_string)
header = rows.shift
assert_equal('id', header[0])
assert_equal('name', header[1])
assert_equal('keywords', header[2])
assert_equal('content', header[3])
assert_equal('note', header[4])
assert_equal('active', header[5])
assert_not(header.include?('organization'))
assert_not(header.include?('priority'))
assert_not(header.include?('state'))
assert_not(header.include?('owner'))
assert_not(header.include?('customer'))
end
test 'simple import' do
csv_string = "name;keywords;content;note;active;\nsome name1;keyword1;\"some\ncontent1\";-;\nsome name2;keyword2;some content<br>test123\n"
result = TextModule.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
assert_nil(TextModule.find_by(name: 'some name1'))
assert_nil(TextModule.find_by(name: 'some name2'))
result = TextModule.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
text_module1 = TextModule.find_by(name: 'some name1')
assert(text_module1)
assert_equal(text_module1.name, 'some name1')
assert_equal(text_module1.keywords, 'keyword1')
assert_equal(text_module1.content, 'some<br>content1')
assert_equal(text_module1.active, true)
text_module2 = TextModule.find_by(name: 'some name2')
assert(text_module2)
assert_equal(text_module2.name, 'some name2')
assert_equal(text_module2.keywords, 'keyword2')
assert_equal(text_module2.content, 'some content<br>test123')
assert_equal(text_module2.active, true)
text_module1.destroy!
text_module2.destroy!
end
end

View file

@ -0,0 +1,172 @@
require 'test_helper'
class TicketCsvImportTest < ActiveSupport::TestCase
test 'import example verify' do
csv_string = Ticket.csv_example
rows = CSV.parse(csv_string)
header = rows.shift
assert_equal('id', header[0])
assert_equal('number', header[1])
assert_equal('title', header[2])
assert_equal('note', header[3])
assert_equal('first_response_at', header[4])
assert_equal('first_response_escalation_at', header[5])
assert(header.include?('organization'))
assert(header.include?('priority'))
assert(header.include?('state'))
assert(header.include?('owner'))
assert(header.include?('customer'))
end
test 'simple import' do
csv_string = "id;number;title;state;priority;owner;customer;group;note\n;123456;some title1;new;2 normal;-;nicole.braun@zammad.org;Users;some note1\n;123457;some title2;closed;1 low;admin@example.com;nicole.braun@zammad.org;Users;some note2\n"
result = Ticket.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
assert_nil(Ticket.find_by(number: '123456'))
assert_nil(Ticket.find_by(number: '123457'))
result = Ticket.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
ticket1 = Ticket.find_by(number: '123456')
assert(ticket1)
assert_equal(ticket1.number, '123456')
assert_equal(ticket1.title, 'some title1')
assert_equal(ticket1.state.name, 'new')
assert_equal(ticket1.priority.name, '2 normal')
assert_equal(ticket1.owner.login, '-')
assert_equal(ticket1.customer.login, 'nicole.braun@zammad.org')
assert_equal(ticket1.note, 'some note1')
ticket2 = Ticket.find_by(number: '123457')
assert(ticket2)
assert_equal(ticket2.number, '123457')
assert_equal(ticket2.title, 'some title2')
assert_equal(ticket2.state.name, 'closed')
assert_equal(ticket2.priority.name, '1 low')
assert_equal(ticket2.owner.login, 'admin@example.com')
assert_equal(ticket2.customer.login, 'nicole.braun@zammad.org')
assert_equal(ticket2.note, 'some note2')
ticket1.destroy!
ticket2.destroy!
end
test 'simple import with invalid id' do
csv_string = "id;number;title;state;priority;owner;customer;group;note\n999999999;123456;some title1;new;2 normal;-;nicole.braun@zammad.org;Users;some note1\n;123457;some title2;closed;1 low;admin@example.com;nicole.braun@zammad.org;Users;some note2\n"
result = Ticket.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(1, result[:errors].count)
assert_equal('failed', result[:result])
assert_equal("Line 1: unknown record with id '999999999' for Ticket.", result[:errors][0])
assert_nil(Ticket.find_by(number: '123456'))
assert_nil(Ticket.find_by(number: '123457'))
result = Ticket.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(1, result[:records].count)
assert_equal('failed', result[:result])
assert_nil(Ticket.find_by(number: '123456'))
ticket2 = Ticket.find_by(number: '123457')
assert(ticket2)
assert_equal(ticket2.title, 'some title2')
assert_equal(ticket2.note, 'some note2')
csv_string = "id;number;title;state;priority;owner;customer;group;note\n999999999;123456;some title1;new;2 normal;-;nicole.braun@zammad.org;Users;some note1\n;123457;some title22;closed;1 low;admin@example.com;nicole.braun@zammad.org;Users;some note22\n"
result = Ticket.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(1, result[:records].count)
assert_equal('failed', result[:result])
assert_nil(Ticket.find_by(number: '123456'))
ticket2 = Ticket.find_by(number: '123457')
assert(ticket2)
assert_equal(ticket2.title, 'some title22')
assert_equal(ticket2.note, 'some note22')
ticket2.destroy!
end
test 'invalid attributes' do
csv_string = "id;number;not_existing;state;priority;owner;customer;group;note\n;123456;some title1;new;2 normal;-;nicole.braun@zammad.org;Users;some note1\n;123457;some title2;closed;1 low;admin@example.com;nicole.braun@zammad.org;Users;some note2\n"
result = Ticket.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(2, result[:errors].count)
assert_equal('failed', result[:result])
assert_equal("Line 1: unknown attribute 'not_existing' for Ticket.", result[:errors][0])
assert_equal("Line 2: unknown attribute 'not_existing' for Ticket.", result[:errors][1])
assert_nil(Ticket.find_by(number: '123456'))
assert_nil(Ticket.find_by(number: '123457'))
result = Ticket.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(2, result[:errors].count)
assert_equal('failed', result[:result])
assert_equal("Line 1: unknown attribute 'not_existing' for Ticket.", result[:errors][0])
assert_equal("Line 2: unknown attribute 'not_existing' for Ticket.", result[:errors][1])
assert_nil(Ticket.find_by(number: '123456'))
assert_nil(Ticket.find_by(number: '123457'))
end
end

View file

@ -0,0 +1,416 @@
require 'test_helper'
class UserCsvImportTest < ActiveSupport::TestCase
test 'import example verify' do
csv_string = User.csv_example
rows = CSV.parse(csv_string)
header = rows.shift
assert_equal('id', header[0])
assert_equal('login', header[1])
assert_equal('firstname', header[2])
assert_equal('lastname', header[3])
assert_equal('email', header[4])
assert(header.include?('organization'))
end
test 'simple import' do
csv_string = "login;firstname;lastname;email;active;\nuser-simple-import1;firstname-simple-import1;lastname-simple-import1;user-simple-import1@example.com;true\nuser-simple-import2;firstname-simple-import2;lastname-simple-import2;user-simple-import2@example.com;false\n"
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
assert_nil(User.find_by(login: 'user-simple-import1'))
assert_nil(User.find_by(login: 'user-simple-import2'))
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
user1 = User.find_by(login: 'user-simple-import1')
assert(user1)
assert_equal(user1.login, 'user-simple-import1')
assert_equal(user1.firstname, 'firstname-simple-import1')
assert_equal(user1.lastname, 'lastname-simple-import1')
assert_equal(user1.email, 'user-simple-import1@example.com')
assert_equal(user1.active, true)
user2 = User.find_by(login: 'user-simple-import2')
assert(user2)
assert_equal(user2.login, 'user-simple-import2')
assert_equal(user2.firstname, 'firstname-simple-import2')
assert_equal(user2.lastname, 'lastname-simple-import2')
assert_equal(user2.email, 'user-simple-import2@example.com')
assert_equal(user2.active, false)
user1.destroy!
user2.destroy!
end
test 'simple import with invalid id' do
csv_string = "id;login;firstname;lastname;email;active;\n999999999;user-simple-invalid_id-import1;firstname-simple-import1;lastname-simple-import1;user-simple-invalid_id-import1@example.com;true\n;user-simple-invalid_id-import2;firstname-simple-import2;lastname-simple-import2;user-simple-invalid_id-import2@example.com;false\n"
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(1, result[:errors].count)
assert_equal('failed', result[:result])
assert_equal("Line 1: unknown record with id '999999999' for User.", result[:errors][0])
assert_nil(User.find_by(login: 'user-simple-invalid_id-import1'))
assert_nil(User.find_by(login: 'user-simple-invalid_id-import2'))
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(1, result[:records].count)
assert_equal('failed', result[:result])
assert_nil(User.find_by(login: 'user-simple-invalid_id-import1'))
user2 = User.find_by(login: 'user-simple-invalid_id-import2')
assert(user2)
assert_equal(user2.login, 'user-simple-invalid_id-import2')
assert_equal(user2.firstname, 'firstname-simple-import2')
assert_equal(user2.lastname, 'lastname-simple-import2')
assert_equal(user2.email, 'user-simple-invalid_id-import2@example.com')
assert_equal(user2.active, false)
user2.destroy!
end
test 'simple import with read only id' do
csv_string = "id;login;firstname;lastname;email;active;\n1;user-simple-readonly_id-import1;firstname-simple-import1;lastname-simple-import1;user-simple-readonly_id-import1@example.com;true\n;user-simple-readonly_id-import2;firstname-simple-import2;lastname-simple-import2;user-simple-readonly_id-import2@example.com;false\n"
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(1, result[:errors].count)
assert_equal('failed', result[:result])
assert_equal("Line 1: unable to update record with id '1' for User.", result[:errors][0])
assert_nil(User.find_by(login: 'user-simple-readonly_id-import1'))
assert_nil(User.find_by(login: 'user-simple-readonly_id-import2'))
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(1, result[:records].count)
assert_equal('failed', result[:result])
assert_nil(User.find_by(login: 'user-simple-readonly_id-import1'))
user2 = User.find_by(login: 'user-simple-readonly_id-import2')
assert(user2)
assert_equal(user2.login, 'user-simple-readonly_id-import2')
assert_equal(user2.firstname, 'firstname-simple-import2')
assert_equal(user2.lastname, 'lastname-simple-import2')
assert_equal(user2.email, 'user-simple-readonly_id-import2@example.com')
assert_equal(user2.active, false)
user2.destroy!
end
test 'simple import with roles' do
UserInfo.current_user_id = 1
admin = User.create_or_update(
login: 'admin1@example.com',
firstname: 'Admin',
lastname: '1',
email: 'admin1@example.com',
password: 'agentpw',
active: true,
roles: Role.where(name: 'Admin'),
)
csv_string = "login;firstname;lastname;email;roles;\nuser-role-import1;firstname-role-import1;lastname-role-import1;user-role-import1@example.com;Customer;\nuser-role-import2;firstname-role-import2;lastname-role-import2;user-role-import2@example.com;Agent\n;;;;Admin"
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
assert_nil(User.find_by(login: 'user-role-import1'))
assert_nil(User.find_by(login: 'user-role-import2'))
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
user1 = User.find_by(login: 'user-role-import1')
assert(user1)
assert_equal(user1.login, 'user-role-import1')
assert_equal(user1.firstname, 'firstname-role-import1')
assert_equal(user1.lastname, 'lastname-role-import1')
assert_equal(user1.email, 'user-role-import1@example.com')
assert_equal(user1.roles.count, 1)
user2 = User.find_by(login: 'user-role-import2')
assert(user2)
assert_equal(user2.login, 'user-role-import2')
assert_equal(user2.firstname, 'firstname-role-import2')
assert_equal(user2.lastname, 'lastname-role-import2')
assert_equal(user2.email, 'user-role-import2@example.com')
assert_equal(user2.roles.count, 2)
user1.destroy!
user2.destroy!
admin.destroy!
end
test 'simple import + fixed params' do
csv_string = "login;firstname;lastname;email\nuser-simple-import-fixed1;firstname-simple-import-fixed1;lastname-simple-import-fixed1;user-simple-import-fixed1@example.com\nuser-simple-import-fixed2;firstname-simple-import-fixed2;lastname-simple-import-fixed2;user-simple-import-fixed2@example.com\n"
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
fixed_params: {
note: 'some note',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
assert_nil(User.find_by(login: 'user-simple-import-fixed1'))
assert_nil(User.find_by(login: 'user-simple-import-fixed2'))
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
fixed_params: {
note: 'some note',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(2, result[:records].count)
assert_equal('success', result[:result])
user1 = User.find_by(login: 'user-simple-import-fixed1')
user2 = User.find_by(login: 'user-simple-import-fixed2')
assert(user1)
assert_equal('some note', user1.note)
assert_equal('user-simple-import-fixed1', user1.login)
assert_equal('firstname-simple-import-fixed1', user1.firstname)
assert_equal('lastname-simple-import-fixed1', user1.lastname)
assert_equal('user-simple-import-fixed1@example.com', user1.email)
assert(user2)
assert_equal('some note', user2.note)
assert_equal('user-simple-import-fixed2', user2.login)
assert_equal('firstname-simple-import-fixed2', user2.firstname)
assert_equal('lastname-simple-import-fixed2', user2.lastname)
assert_equal('user-simple-import-fixed2@example.com', user2.email)
user1.destroy!
user2.destroy!
end
test 'duplicate import' do
csv_string = "login;firstname;lastname;email\nuser-duplicate-import1;firstname-duplicate-import1;firstname-duplicate-import1;user-duplicate-import1@example.com\nuser-duplicate-import2;firstname-duplicate-import2;firstname-duplicate-import2;user-duplicate-import2@example.com\nuser-duplicate-import2;firstname-duplicate-import3;firstname-duplicate-import3;user-duplicate-import3@example.com"
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(3, result[:records].count)
assert_equal('success', result[:result])
assert_nil(User.find_by(login: 'user-duplicate-import1'))
assert_nil(User.find_by(login: 'user-duplicate-import2'))
assert_nil(User.find_by(login: 'user-duplicate-import3'))
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(3, result[:records].count)
assert_equal('success', result[:result])
assert(User.find_by(login: 'user-duplicate-import1'))
assert(User.find_by(login: 'user-duplicate-import2'))
assert_nil(User.find_by(login: 'user-duplicate-import3'))
User.find_by(login: 'user-duplicate-import1').destroy!
User.find_by(login: 'user-duplicate-import2').destroy!
end
test 'invalid attributes' do
csv_string = "login;firstname2;lastname;email\nuser-invalid-import1;firstname-invalid-import1;firstname-invalid-import1;user-invalid-import1@example.com\nuser-invalid-import2;firstname-invalid-import2;firstname-invalid-import2;user-invalid-import2@example.com\n"
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(2, result[:errors].count)
assert_equal('failed', result[:result])
assert_equal("Line 1: unknown attribute 'firstname2' for User.", result[:errors][0])
assert_equal("Line 2: unknown attribute 'firstname2' for User.", result[:errors][1])
assert_nil(User.find_by(login: 'user-invalid-import1'))
assert_nil(User.find_by(login: 'user-invalid-import2'))
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(2, result[:errors].count)
assert_equal('failed', result[:result])
assert_equal("Line 1: unknown attribute 'firstname2' for User.", result[:errors][0])
assert_equal("Line 2: unknown attribute 'firstname2' for User.", result[:errors][1])
assert_nil(User.find_by(login: 'user-invalid-import1'))
assert_nil(User.find_by(login: 'user-invalid-import2'))
end
test 'reference import' do
csv_string = "login;firstname;lastname;email;organization\nuser-reference-import1;firstname-reference-import1;firstname-reference-import1;user-reference-import1@example.com;organization-reference-import1\nuser-reference-import2;firstname-reference-import2;firstname-reference-import2;user-reference-import2@example.com;organization-reference-import2\nuser-reference-import3;firstname-reference-import3;firstname-reference-import3;user-reference-import3@example.com;Zammad Foundation\n"
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(2, result[:errors].count)
assert_equal('failed', result[:result])
assert_nil(User.find_by(login: 'user-reference-import1'))
assert_nil(User.find_by(login: 'user-reference-import2'))
assert_nil(User.find_by(login: 'user-reference-import3'))
assert_equal("Line 1: No lookup value found for 'organization': \"organization-reference-import1\"", result[:errors][0])
assert_equal("Line 2: No lookup value found for 'organization': \"organization-reference-import2\"", result[:errors][1])
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(2, result[:errors].count)
assert_equal('failed', result[:result])
assert_nil(User.find_by(login: 'user-reference-import1'))
assert_nil(User.find_by(login: 'user-reference-import2'))
assert(User.find_by(login: 'user-reference-import3'))
assert_equal("Line 1: No lookup value found for 'organization': \"organization-reference-import1\"", result[:errors][0])
assert_equal("Line 2: No lookup value found for 'organization': \"organization-reference-import2\"", result[:errors][1])
UserInfo.current_user_id = 1
orgaization1 = Organization.create_if_not_exists(name: 'organization-reference-import1')
orgaization2 = Organization.create_if_not_exists(name: 'organization-reference-import2')
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: true,
)
assert_equal(true, result[:try])
assert_equal(0, result[:errors].count)
assert_equal('success', result[:result])
assert_nil(User.find_by(login: 'user-reference-import1'))
assert_nil(User.find_by(login: 'user-reference-import2'))
assert(User.find_by(login: 'user-reference-import3'))
result = User.csv_import(
string: csv_string,
parse_params: {
col_sep: ';',
},
try: false,
)
assert_equal(false, result[:try])
assert_equal(0, result[:errors].count)
assert_equal('success', result[:result])
assert(User.find_by(login: 'user-reference-import1'))
assert(User.find_by(login: 'user-reference-import2'))
assert(User.find_by(login: 'user-reference-import3'))
User.find_by(login: 'user-reference-import1').destroy!
User.find_by(login: 'user-reference-import2').destroy!
User.find_by(login: 'user-reference-import3').destroy!
orgaization1.destroy!
orgaization2.destroy!
end
end

View file

@ -570,7 +570,6 @@ class UserTest < ActiveSupport::TestCase
test 'ensure roles' do
name = rand(999_999_999)
admin = User.create_or_update(
login: "admin-role#{name}@example.com",
firstname: 'Role',