refactoring
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing

This commit is contained in:
carla 2026-02-02 16:52:35 +01:00
parent aef3aa299f
commit 960506d16a
6 changed files with 57 additions and 31 deletions

View file

@ -191,8 +191,10 @@ defmodule Mv.Membership.Import.MemberCSV do
normalized != "" && not member_field?(normalized)
end)
|> Enum.map(fn header ->
"Unknown column '#{header}' will be ignored. " <>
"If this is a custom field, create it in Mila before importing."
gettext(
"Unknown column '%{header}' will be ignored. If this is a custom field, create it in Mila before importing.",
header: header
)
end)
{:ok, %{member: member_map, custom: custom_map}, warnings}
@ -311,7 +313,7 @@ defmodule Mv.Membership.Import.MemberCSV do
custom_field_lookup = Keyword.get(opts, :custom_field_lookup, %{})
existing_error_count = Keyword.get(opts, :existing_error_count, 0)
max_errors = Keyword.get(opts, :max_errors, @default_max_errors)
actor = Keyword.fetch!(opts, :actor)
actor = Keyword.get(opts, :actor, SystemActor.get_system_actor())
{inserted, failed, errors, _collected_error_count, truncated?} =
Enum.reduce(chunk_rows_with_lines, {0, 0, [], 0, false}, fn {line_number, row_map},
@ -607,13 +609,38 @@ defmodule Mv.Membership.Import.MemberCSV do
acc_values,
acc_errors
) do
# Trim value early and skip if empty
trimmed_value = if is_binary(value), do: String.trim(value), else: value
# Skip empty values (after trimming) - don't create CFV
if trimmed_value == "" or trimmed_value == nil do
{acc_values, acc_errors}
else
process_non_empty_custom_field(
custom_field_id_str,
trimmed_value,
custom_field_lookup,
acc_values,
acc_errors
)
end
end
# Processes a non-empty custom field value
defp process_non_empty_custom_field(
custom_field_id_str,
trimmed_value,
custom_field_lookup,
acc_values,
acc_errors
) do
case Map.get(custom_field_lookup, custom_field_id_str) do
nil ->
# Custom field not found, skip
{acc_values, acc_errors}
%{id: custom_field_id, value_type: value_type, name: custom_field_name} ->
case format_custom_field_value(value, value_type, custom_field_name) do
case format_custom_field_value(trimmed_value, value_type, custom_field_name) do
{:ok, formatted_value} ->
value_map = %{
"custom_field_id" => to_string(custom_field_id),
@ -691,20 +718,19 @@ defmodule Mv.Membership.Import.MemberCSV do
defp format_custom_field_value(value, :email, custom_field_name) when is_binary(value) do
trimmed = String.trim(value)
# Use simple validation: must contain @ and have valid format
# For CSV import, we use a simpler check than EctoCommons.EmailValidator
# to avoid dependencies and keep it fast
if String.contains?(trimmed, "@") and String.length(trimmed) >= 5 and
String.length(trimmed) <= 254 do
# Basic format check: username@domain.tld
if Regex.match?(~r/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/, trimmed) do
# Use EctoCommons.EmailValidator for consistency with Member email validation
changeset =
{%{}, %{email: :string}}
|> Ecto.Changeset.cast(%{email: trimmed}, [:email])
|> EctoCommons.EmailValidator.validate_email(:email,
checks: Mv.Constants.email_validator_checks()
)
if changeset.valid? do
{:ok, %{"_union_type" => "email", "_union_value" => trimmed}}
else
{:error, format_custom_field_error(custom_field_name, :email, trimmed)}
end
else
{:error, format_custom_field_error(custom_field_name, :email, trimmed)}
end
end
defp format_custom_field_value(value, _type, _custom_field_name) when is_binary(value) do

View file

@ -2293,6 +2293,11 @@ msgstr "Mitgliederdaten verwalten"
msgid "Use the data field name as the CSV column header in your file. Data fields must exist in Mila before importing, so they must be listed in the list of memberdate (like e-mail or first name). Unknown data field columns will be ignored with a warning."
msgstr "Verwende die Namen der Datenfelder als Spaltennamen in der CSV Datei. Datenfelder müssen in Mila bereits angelegt sein, damit sie importiert werden können. Sie müssen in der Liste der Mitgliederdaten als Datenfeld enthalten sein (z.B. E-Mail). Spalten mit unbekannten Spaltenüberschriften werden mit einer Warnung ignoriert."
#: lib/mv/membership/import/member_csv.ex
#, elixir-autogen, elixir-format
msgid "Unknown column '%{header}' will be ignored. If this is a custom field, create it in Mila before importing."
msgstr "Unbekannte Spalte '%{header}' wird ignoriert. Falls dies ein Datenfeld ist, erstellen Sie es in Mila vor dem Import."
#~ #: lib/mv_web/live/global_settings_live.ex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Custom Fields in CSV Import"

View file

@ -2293,3 +2293,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Use the data field name as the CSV column header in your file. Data fields must exist in Mila before importing, so they must be listed in the list of memberdate (like e-mail or first name). Unknown data field columns will be ignored with a warning."
msgstr ""
#: lib/mv/membership/import/member_csv.ex
#, elixir-autogen, elixir-format
msgid "Unknown column '%{header}' will be ignored. If this is a custom field, create it in Mila before importing."
msgstr ""

View file

@ -2259,7 +2259,6 @@ msgstr ""
msgid "Could not load data fields. Please check your permissions."
msgstr ""
#: lib/mv_web/live/global_settings_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "CSV files only, maximum %{size} MB"
@ -2295,6 +2294,11 @@ msgstr ""
msgid "Use the data field name as the CSV column header in your file. Data fields must exist in Mila before importing, so they must be listed in the list of memberdate (like e-mail or first name). Unknown data field columns will be ignored with a warning."
msgstr ""
#: lib/mv/membership/import/member_csv.ex
#, elixir-autogen, elixir-format
msgid "Unknown column '%{header}' will be ignored. If this is a custom field, create it in Mila before importing."
msgstr "Unknown column '%{header}' will be ignored. If this is a custom field, create it in Mila before importing."
#~ #: lib/mv_web/live/global_settings_live.ex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Custom Fields in CSV Import"

View file

@ -1,14 +0,0 @@
defmodule Mv.ConfigTest do
@moduledoc """
Tests for Mv.Config module.
"""
use ExUnit.Case, async: false
alias Mv.Config
# Note: CSV import configuration functions were never implemented.
# The codebase uses hardcoded constants instead:
# - @max_file_size_bytes 10_485_760 in GlobalSettingsLive
# - @default_max_rows 1000 in MemberCSV
# These tests have been removed as they tested non-existent functions.
end

View file

@ -10,7 +10,7 @@ defmodule MvWeb.GlobalSettingsLiveConfigTest do
import Phoenix.LiveViewTest
# Helper function to upload CSV file in tests
defp upload_csv_file(view, csv_content, filename \\ "test_import.csv") do
defp upload_csv_file(view, csv_content, filename) do
view
|> file_input("#csv-upload-form", :csv_file, [
%{