Skip to content

Commit

Permalink
Import delegations by CSV
Browse files Browse the repository at this point in the history
commit 7131e603549f0a19208332dac57aa8cbf2b35e6b
Author: Laura Jaime <laura.jv@coditramuntana.com>
Date:   Mon May 15 13:45:00 2023 +0200

    fix conflit
  • Loading branch information
laurajaime authored and microstudi committed May 15, 2023
1 parent 1718cf5 commit 0ff204e
Show file tree
Hide file tree
Showing 27 changed files with 757 additions and 239 deletions.
1 change: 1 addition & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ GEM
mime-types-data (3.2022.0105)
mini_magick (4.11.0)
mini_mime (1.1.2)
mini_portile2 (2.8.1)
minitest (5.16.3)
mixlib-cli (2.1.8)
mixlib-config (3.0.27)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# frozen_string_literal: true

module Decidim
module ActionDelegator
module Admin
class ManageDelegationsController < ActionDelegator::Admin::ApplicationController
include NeedsPermission
include Decidim::Paginable

helper ::Decidim::ActionDelegator::Admin::DelegationHelper
helper_method :organization_settings, :current_setting

layout "decidim/admin/users"

def new
enforce_permission_to :create, :delegation

@errors = []
end

def create
enforce_permission_to :create, :delegation

@csv_file = params[:csv_file]
redirect_to seting_manage_delegations_path && return if @csv_file.blank?

importer_type = "DelegationsCsvImporter"
csv_file = @csv_file.read.force_encoding("utf-8").encode("utf-8")
@import_summary = Decidim::ActionDelegator::Admin::ImportCsvJob.perform_now(importer_type, csv_file, current_user, current_setting)

flash[:notice] = t(".success")

redirect_to decidim_admin_action_delegator.setting_delegations_path(current_setting)
end

private

def current_setting
@current_setting ||= organization_settings.find_by(id: params[:setting_id])
end

def organization_settings
Decidim::ActionDelegator::OrganizationSettings.new(current_organization).query
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@ def create
@csv_file = params[:csv_file]
redirect_to seting_manage_participants_path && return if @csv_file.blank?

@import_summary = Decidim::ActionDelegator::Admin::ImportParticipantsCsvJob.perform_later(
current_user,
@csv_file.read.force_encoding("utf-8").encode("utf-8"),
current_setting
)
importer_type = "ParticipantsCsvImporter"
csv_file = @csv_file.read.force_encoding("utf-8").encode("utf-8")
@import_summary = Decidim::ActionDelegator::Admin::ImportCsvJob.perform_later(importer_type, csv_file, current_user, current_setting)

flash[:notice] = t(".success")

Expand Down
27 changes: 27 additions & 0 deletions app/jobs/decidim/action_delegator/admin/import_csv_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

module Decidim
module ActionDelegator
module Admin
class ImportCsvJob < ApplicationJob
queue_as :exports

def perform(importer_type, csv_file, current_user, current_setting)
importer = if importer_type == "DelegationsCsvImporter"
Decidim::ActionDelegator::DelegationsCsvImporter.new(csv_file, current_user, current_setting)
else
Decidim::ActionDelegator::ParticipantsCsvImporter.new(csv_file, current_user, current_setting)
end

import_summary = importer.import!

Decidim::ActionDelegator::ImportMailer
.import(current_user, import_summary, import_summary[:details_csv_path])
.deliver_later

import_summary
end
end
end
end
end

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Decidim
module ActionDelegator
# This mailer sends a notification email containing the result of importing a
# CSV of results.
class ImportParticipantsMailer < Decidim::ApplicationMailer
class ImportMailer < Decidim::ApplicationMailer
# Public: Sends a notification email with the result of a CSV import
# of results.
#
Expand All @@ -23,7 +23,7 @@ def import(user, import_summary, csv_file_path)
attachments["details.csv"] = File.read(@csv_file_path) if @csv_file_path.present? && File.exist?(@csv_file_path)

with_user(user) do
mail(to: "#{user.name} <#{user.email}>", subject: I18n.t("decidim.action_delegator.import_participants_mailer.import.subject"))
mail(to: "#{user.name} <#{user.email}>", subject: I18n.t("decidim.action_delegator.import_mailer.import.subject"))
end
end
end
Expand Down
86 changes: 86 additions & 0 deletions app/services/decidim/action_delegator/csv_importer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# frozen_string_literal: true

module Decidim
module ActionDelegator
class CsvImporter
include Decidim::FormFactory

def initialize(csv_file, current_user, current_setting)
@csv_file = csv_file
@current_user = current_user
@current_setting = current_setting
end

def import!
import_summary = {
total_rows: 0,
imported_rows: 0,
error_rows: [],
skipped_rows: [],
details_csv_path: nil
}

details_csv_file = File.join(File.dirname(@csv_file), "details.csv")

i = 1
csv = CSV.new(@csv_file, headers: true, col_sep: ",")

CSV.open(details_csv_file, "wb") do |details_csv|
while (row = csv.shift).present?
i += 1

params = extract_params(row)

next if row&.empty?

handle_form_validity(row, details_csv, import_summary, i) if process(row, params, details_csv, import_summary, i)
end
end

import_summary[:total_rows] = i - 1
import_summary[:details_csv_path] = details_csv_file

import_summary
end

def handle_skipped_row(row, details_csv, import_summary, row_number, reason)
import_summary[:skipped_rows] << { row_number: row_number - 1 }
row["reason"] = reason
details_csv << row
end

def handle_import_error(row, details_csv, import_summary, row_number, error_messages)
import_summary[:error_rows] << { row_number: row_number - 1, error_messages: error_messages }
row["reason"] = error_messages
details_csv << row
end

def handle_form_validity(row, details_csv, import_summary, row_number)
raise NotImplementedError
end

def generate_info_message(mismatch_fields)
with_mismatched_fields = mismatch_fields.present? ? I18n.t("decidim.action_delegator.participants_csv_importer.import.with_mismatched_fields", fields: mismatch_fields) : ""
I18n.t("decidim.action_delegator.participants_csv_importer.import.skip_import_info", with_mismatched_fields: with_mismatched_fields)
end

def headers(csv, details_csv)
headers = csv.first.headers
headers << I18n.t("decidim.action_delegator.participants_csv_importer.import.error_field")
details_csv << headers
end

def invalid_email?(email)
email.blank? || !email.match?(::Devise.email_regexp)
end

def process(row)
raise NotImplementedError
end

def extract_params
raise NotImplementedError
end
end
end
end
74 changes: 74 additions & 0 deletions app/services/decidim/action_delegator/delegations_csv_importer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# frozen_string_literal: true

module Decidim
module ActionDelegator
class DelegationsCsvImporter < CsvImporter
def process(row, params, details_csv, import_summary, iterator)
if delegation_exists?(params)
message = generate_info_message(row)

handle_skipped_row(row, details_csv, import_summary, iterator, message)

false
else
true
end
end

private

def extract_params(row)
granter, grantee = extract_details(row)

params = {
granter_id: granter,
grantee_id: grantee
}

@form = form(Decidim::ActionDelegator::Admin::DelegationForm).from_params(params, setting: @current_setting)

params
end

def extract_details(row)
granter_email = row["from"].to_s.strip.downcase
grantee_email = row["to"].to_s.strip.downcase

granter = user_id(granter_email)
grantee = user_id(grantee_email)

granter = nil if invalid_email?(granter_email) && granter.nil?
grantee = nil if invalid_email?(grantee_email) && grantee.nil?

[granter, grantee]
end

def user_id(email)
Decidim::User.find_by(email: email)&.id
end

def process_delegation(form)
create_new_delegation(form)
end

def delegation_exists?(params)
@delegation = Delegation.find_by(granter_id: params[:granter_id], grantee_id: params[:grantee_id])

@delegation.present?
end

def create_new_delegation(form)
Decidim::ActionDelegator::Admin::CreateDelegation.call(form, @current_user, @current_setting)
end

def handle_form_validity(row, details_csv, import_summary, row_number)
if @form.valid?
process_delegation(@form)
import_summary[:imported_rows] += 1
else
handle_import_error(row, details_csv, import_summary, row_number, @form.errors.full_messages.join(", "))
end
end
end
end
end
Loading

0 comments on commit 0ff204e

Please sign in to comment.