diff --git a/app/assets/javascripts/controllers/admin/members.js.erb b/app/assets/javascripts/controllers/admin/members.js.erb
index a70b9f6a6..023f53dfe 100644
--- a/app/assets/javascripts/controllers/admin/members.js.erb
+++ b/app/assets/javascripts/controllers/admin/members.js.erb
@@ -635,7 +635,7 @@ Application.Controllers.controller('ImportMembersController', ['$scope', '$state
if (content.id) {
$state.go('app.admin.members_import_result', { id: content.id });
} else {
- growl.error(content);
+ growl.error(JSON.stringify(content));
}
}
@@ -647,17 +647,40 @@ Application.Controllers.controller('ImportMembersController', ['$scope', '$state
/**
* Controller used in the member's import results page (admin view)
*/
-Application.Controllers.controller('ImportMembersResultController', ['$scope', '$state', 'importItem',
- function ($scope, $state, importItem) {
+Application.Controllers.controller('ImportMembersResultController', ['$scope', '$state', 'Import', 'importItem',
+ function ($scope, $state, Import, importItem) {
/* PUBLIC SCOPE */
// Current import as saved in database
$scope.import = importItem;
+ // Current import results
+ $scope.results = null;
+
/**
* Changes the admin's view to the members import page
*/
$scope.cancel = function () { $state.go('app.admin.members_import'); };
+
+ /* PRIVATE SCOPE */
+
+ /**
+ * Kind of constructor: these actions will be realized first when the controller is loaded
+ */
+ const initialize = function () {
+ $scope.results = JSON.parse($scope.import.results);
+ if (!$scope.results) {
+ setTimeout(function() {
+ Import.get({ id: $scope.import.id }, function(data) {
+ $scope.import = data;
+ initialize();
+ });
+ }, 5000);
+ }
+ };
+
+ // !!! MUST BE CALLED AT THE END of the controller
+ initialize();
}
]);
diff --git a/app/assets/templates/admin/members/import_result.html b/app/assets/templates/admin/members/import_result.html
index 7802a834e..447444d06 100644
--- a/app/assets/templates/admin/members/import_result.html
+++ b/app/assets/templates/admin/members/import_result.html
@@ -20,9 +20,39 @@
-
+
-
{{import}}
+
{{ 'members_import_result.import_details' | translate:{DATE:(import.created_at | amDateFormat:'L'), USER:import.user.full_name, ID:import.id} }}
+
+
{{ 'members_import_result.pending' }}
+
+
{{ 'members_import_result.results' }}
+
+
+
+
+
+ {{ 'members_import_result.status_' + resultRow.status | translate:{ID:resultRow.user} }}
+
+
+
+
+
+
+
+ {{ 'members_import_result.error_details' }}{{resultRow}}
+
+
+
diff --git a/app/models/import.rb b/app/models/import.rb
index b5034d057..eab704afc 100644
--- a/app/models/import.rb
+++ b/app/models/import.rb
@@ -10,10 +10,14 @@ class Import < ActiveRecord::Base
belongs_to :user
validates :attachment, file_size: { maximum: Rails.application.secrets.max_import_size&.to_i || 5.megabytes.to_i }
- validates :attachment, file_mime_type: { content_type: ['text/csv'] }
+ validates :attachment, file_mime_type: { content_type: %w[text/csv text/comma-separated-values application/vnd.ms-excel] }
after_commit :proceed_import, on: [:create]
+ def results_hash
+ YAML.safe_load(results, [Symbol]) if results
+ end
+
private
def proceed_import
diff --git a/app/services/members/import_service.rb b/app/services/members/import_service.rb
index 7f3086b2e..970e64e56 100644
--- a/app/services/members/import_service.rb
+++ b/app/services/members/import_service.rb
@@ -5,40 +5,75 @@ class Members::ImportService
class << self
def import(import)
require 'csv'
+ log = []
CSV.foreach(import.attachment.url, headers: true, col_sep: ';') do |row|
- # try to find member based on import.update_field
- user = User.find_by(import.update_field.to_sym => import.update_field)
- if user
- service = Members::MembersService.new(user)
- service.update(row_to_params(row))
- else
- user = User.new(row)
- service = Members::MembersService.new(user)
- service.create(import.user, row_to_params(row))
+ begin
+ log << { row: row.to_hash }
+
+ # try to find member based on import.update_field
+ user = User.find_by(import.update_field.to_sym => row[import.update_field])
+ params = row_to_params(row, user)
+ if user
+ service = Members::MembersService.new(user)
+ res = service.update(params)
+ log << { user: user.id, status: 'update', result: res }
+ else
+ user = User.new(params)
+ service = Members::MembersService.new(user)
+ res = service.create(import.user, params)
+ log << { user: nil, status: 'create', result: res }
+ end
+ log << user.errors.to_hash unless user.errors.to_hash.empty?
+ rescue StandardError => e
+ log << e.to_s
+ puts e
+ puts e.backtrace
end
end
+ log
end
private
- def row_to_params(row)
- {
+ def row_to_params(row, user)
+ res = {
+ id: row['id'],
username: row['username'],
email: row['email'],
password: row['password'],
password_confirmation: row['password'],
- is_allow_contact: row['allow_contact'],
- is_allow_newsletter: row['allow_newsletter'],
- group_id: Group.friendly.find(row['group'])&.id,
- tag_ids: Tag.where(id: row['tags'].split(',')).map(&:id),
- profile_attributes: profile_attributes(row),
- invoicing_profile_attributes: invoicing_profile_attributes(row),
- statistic_profile_attributes: statistic_profile_attributes(row)
+ is_allow_contact: row['allow_contact'] == 'yes',
+ is_allow_newsletter: row['allow_newsletter'] == 'yes',
+ group_id: group_id(row),
+ tag_ids: tag_ids(row)
}
+
+ profile_attributes = profile(row, user)
+ res[:profile_attributes] = profile_attributes if profile_attributes
+
+ invoicing_profile_attributes = invoicing_profile(row, user)
+ res[:invoicing_profile_attributes] = invoicing_profile_attributes if invoicing_profile_attributes
+
+ statistic_profile_attributes = statistic_profile(row, user)
+ res[:statistic_profile_attributes] = statistic_profile_attributes if statistic_profile_attributes
+
+ res
end
- def profile_attributes(row)
- {
+ def group_id(row)
+ return unless row['group']
+
+ Group.friendly.find(row['group'])&.id
+ end
+
+ def tag_ids(row)
+ return unless row['tags']
+
+ Tag.where(id: row['tags'].split(',')).map(&:id)
+ end
+
+ def profile(row, user)
+ res = {
first_name: row['first_name'],
last_name: row['last_name'],
phone: row['phone'],
@@ -61,28 +96,79 @@ class Members::ImportService
lastfm: row['lastfm'],
flickr: row['flickr']
}
+
+ res[:id] = user.profile.id if user&.profile
+
+ res
end
- def invoicing_profile_attributes(row)
- {
- address_attributes: {
- address: row['address']
- },
- organization_attributes: {
- name: row['organization_name'],
- address_attributes: {
- address: row['organization_address']
- }
- }
- }
+ def invoicing_profile(row, user)
+ res = {}
+
+ res[:id] = user.invoicing_profile.id if user&.invoicing_profile
+
+ address_attributes = address(row, user)
+ res[:address_attributes] = address_attributes if address_attributes
+
+ organization_attributes = organization(row, user)
+ res[:organization_attributes] = organization_attributes if organization_attributes
+
+ res
end
- def statistic_profile_attributes(row)
- {
+ def statistic_profile(row, user)
+ res = {
gender: row['gender'] == 'male',
- birthday: row['birthdate'],
- training_ids: Training.where(id: row['trainings'].split(',')).map(&:id)
+ birthday: row['birthdate']
}
+
+ res[:id] = user.statistic_profile.id if user&.statistic_profile
+
+ training_ids = training_ids(row)
+ res[:training_ids] = training_ids if training_ids
+
+ res
+ end
+
+ def address(row, user)
+ return unless row['address']
+
+ res = { address: row['address'] }
+
+ res[:id] = user.invoicing_profile.address.id if user&.invoicing_profile&.address
+
+ res
+ end
+
+ def organization(row, user)
+ return unless row['organization_name']
+
+ res = {
+ name: row['organization_name']
+ }
+
+ res[:id] = user.invoicing_profile.organization.id if user&.invoicing_profile&.organization
+
+ address_attributes = organization_address(row, user)
+ res[:address_attributes] = address_attributes if address_attributes
+
+ res
+ end
+
+ def organization_address(row, user)
+ return unless row['organization_address']
+
+ res = { address: row['organization_address'] }
+
+ res[:id] = user.invoicing_profile.organization.address.id if user&.invoicing_profile&.organization&.address
+
+ res
+ end
+
+ def training_ids(row)
+ return unless row['trainings']
+
+ Training.where(id: row['trainings'].split(',')).map(&:id)
end
end
end
diff --git a/app/views/api/imports/show.json.jbuilder b/app/views/api/imports/show.json.jbuilder
index 8303a79de..8dfd650b7 100644
--- a/app/views/api/imports/show.json.jbuilder
+++ b/app/views/api/imports/show.json.jbuilder
@@ -1,6 +1,7 @@
# frozen_string_literal: true
-json.extract! @import, :id, :category, :user_id, :update_field, :created_at, :updated_at, :results
+json.extract! @import, :id, :category, :user_id, :update_field, :created_at, :updated_at
+json.results @import.results_hash.to_json
json.user do
json.full_name @import.user&.profile&.full_name
end
diff --git a/app/workers/members_import_worker.rb b/app/workers/members_import_worker.rb
index 533094c40..81fdb3853 100644
--- a/app/workers/members_import_worker.rb
+++ b/app/workers/members_import_worker.rb
@@ -11,7 +11,10 @@ class MembersImportWorker
raise SecurityError, 'Not allowed to import' unless import.user.admin?
raise KeyError, 'Wrong worker called' unless import.category == 'members'
- Members::ImportService.import(import)
+ res = Members::ImportService.import(import)
+
+ import.results = res.to_yaml
+ import.save!
NotificationCenter.call type: :notify_admin_import_complete,
receiver: import.user,
diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb
index bb3a62d1c..cec1cb810 100644
--- a/config/initializers/mime_types.rb
+++ b/config/initializers/mime_types.rb
@@ -1,7 +1,9 @@
+# frozen_string_literal: true
+
# Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
# Mime::Type.register_alias "text/html", :iphone
-Mime::Type.register "application/vnd.ms-excel", :xls
\ No newline at end of file
+Mime::Type.register 'application/vnd.ms-excel', :xls
\ No newline at end of file
diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml
index 605c5bf62..a09a6abe0 100644
--- a/config/locales/app.admin.en.yml
+++ b/config/locales/app.admin.en.yml
@@ -600,6 +600,12 @@ en:
# import results
members_import_result:
import_results: "Import results"
+ import_details: "Import #{{ID}}, of {{DATE}}, initiated by {{USER}}" # angular interpolation
+ results: "Results"
+ pending: "Pending..."
+ status_create: "Creating a new user"
+ status_update: "Updating user {{ID}}" # angular interpolation
+ error_details: "Error's details:"
members_edit:
# edit a member
diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml
index 837a4fb53..61193f92b 100644
--- a/config/locales/app.admin.es.yml
+++ b/config/locales/app.admin.es.yml
@@ -600,6 +600,12 @@ es:
# import results
members_import_result:
import_results: "Import results" # translation_missing
+ import_details: "Import #{{ID}}, of {{DATE}}, initiated by {{USER}}" # angular interpolation # translation_missing
+ results: "Results" # translation_missing
+ pending: "Pending..." # translation_missing
+ status_create: "Creating a new user" # translation_missing
+ status_update: "Updating user {{ID}}" # angular interpolation # translation_missing
+ error_details: "Error's details:" # translation_missing
members_edit:
# edit a member
diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml
index 460d995be..5b29a9c1a 100644
--- a/config/locales/app.admin.fr.yml
+++ b/config/locales/app.admin.fr.yml
@@ -600,6 +600,12 @@ fr:
# résultats de l'import
members_import_result:
import_results: "Résultats de l'import"
+ import_details: "Import n°{{ID}}, du {{DATE}}, initié par {{USER}}" # angular interpolation
+ results: "Résultats"
+ pending: "En cours..."
+ status_create: "Création d'un nouvel utilisateur"
+ status_update: "Mise à jour de l'utilisateur {{ID}}" # angular interpolation
+ error_details: "Détails de l'erreur :"
members_edit:
# modifier un membre
diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml
index fd4520abb..ae2107ae8 100755
--- a/config/locales/app.admin.pt.yml
+++ b/config/locales/app.admin.pt.yml
@@ -600,6 +600,12 @@ pt:
# import results
members_import_result:
import_results: "Import results" # translation_missing
+ import_details: "Import #{{ID}}, of {{DATE}}, initiated by {{USER}}" # angular interpolation # translation_missing
+ results: "Results" # translation_missing
+ pending: "Pending..." # translation_missing
+ status_create: "Creating a new user" # translation_missing
+ status_update: "Updating user {{ID}}" # angular interpolation # translation_missing
+ error_details: "Error's details:" # translation_missing
members_edit:
# edit a member