WIP: Implements CSV export closes #285 #408
5 changed files with 93 additions and 18 deletions
|
|
@ -10,10 +10,10 @@ defmodule MvWeb.MemberExportController do
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
import Ash.Expr
|
import Ash.Expr
|
||||||
|
|
||||||
alias Mv.Membership.Member
|
|
||||||
alias Mv.Membership.CustomField
|
|
||||||
alias Mv.Membership.MembersCSV
|
|
||||||
alias Mv.Authorization.Actor
|
alias Mv.Authorization.Actor
|
||||||
|
alias Mv.Membership.CustomField
|
||||||
|
alias Mv.Membership.Member
|
||||||
|
alias Mv.Membership.MembersCSV
|
||||||
|
|
||||||
@member_fields_allowlist Mv.Constants.member_fields() |> Enum.map(&Atom.to_string/1)
|
@member_fields_allowlist Mv.Constants.member_fields() |> Enum.map(&Atom.to_string/1)
|
||||||
@custom_field_prefix Mv.Constants.custom_field_prefix()
|
@custom_field_prefix Mv.Constants.custom_field_prefix()
|
||||||
|
|
@ -100,7 +100,9 @@ defmodule MvWeb.MemberExportController do
|
||||||
|
|
||||||
defp filter_valid_uuids(id_list) when is_list(id_list) do
|
defp filter_valid_uuids(id_list) when is_list(id_list) do
|
||||||
id_list
|
id_list
|
||||||
|> Enum.filter(fn id -> is_binary(id) and match?({:ok, _}, Ecto.UUID.cast(id)) end)
|
|> Enum.filter(fn id ->
|
||||||
|
is_binary(id) and match?({:ok, _}, Ecto.UUID.cast(id))
|
||||||
|
end)
|
||||||
|> Enum.uniq()
|
|> Enum.uniq()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -130,14 +132,18 @@ defmodule MvWeb.MemberExportController do
|
||||||
|> Ash.Query.filter(expr(id in ^custom_field_ids))
|
|> Ash.Query.filter(expr(id in ^custom_field_ids))
|
||||||
|> Ash.Query.select([:id, :name, :value_type])
|
|> Ash.Query.select([:id, :name, :value_type])
|
||||||
|
|
||||||
case Ash.read(query, actor: actor) do
|
query
|
||||||
{:ok, custom_fields} ->
|
|> Ash.read(actor: actor)
|
||||||
by_id = build_custom_fields_by_id(custom_field_ids, custom_fields)
|
|> handle_custom_fields_read_result(custom_field_ids)
|
||||||
{:ok, by_id}
|
end
|
||||||
|
|
||||||
{:error, %Ash.Error.Forbidden{}} ->
|
defp handle_custom_fields_read_result({:ok, custom_fields}, custom_field_ids) do
|
||||||
{:error, :forbidden}
|
by_id = build_custom_fields_by_id(custom_field_ids, custom_fields)
|
||||||
end
|
{:ok, by_id}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_custom_fields_read_result({:error, %Ash.Error.Forbidden{}}, _custom_field_ids) do
|
||||||
|
{:error, :forbidden}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp build_custom_fields_by_id(custom_field_ids, custom_fields) do
|
defp build_custom_fields_by_id(custom_field_ids, custom_fields) do
|
||||||
|
|
|
||||||
|
|
@ -642,24 +642,48 @@ defmodule MvWeb.ImportExportLive do
|
||||||
# Start async task to process chunk in production
|
# Start async task to process chunk in production
|
||||||
# Use start_child for fire-and-forget: no monitor, no Task messages
|
# Use start_child for fire-and-forget: no monitor, no Task messages
|
||||||
# We only use our own send/2 messages for communication
|
# We only use our own send/2 messages for communication
|
||||||
Task.Supervisor.start_child(Mv.TaskSupervisor, fn ->
|
Task.Supervisor.start_child(
|
||||||
# Set locale in task process for translations
|
Mv.TaskSupervisor,
|
||||||
Gettext.put_locale(MvWeb.Gettext, locale)
|
build_chunk_processing_task(
|
||||||
|
|
||||||
process_chunk_with_error_handling(
|
|
||||||
chunk,
|
chunk,
|
||||||
import_state.column_map,
|
import_state.column_map,
|
||||||
import_state.custom_field_map,
|
import_state.custom_field_map,
|
||||||
opts,
|
opts,
|
||||||
live_view_pid,
|
live_view_pid,
|
||||||
idx
|
idx,
|
||||||
|
locale
|
||||||
)
|
)
|
||||||
end)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Builds the task function for processing a chunk asynchronously.
|
||||||
|
defp build_chunk_processing_task(
|
||||||
|
chunk,
|
||||||
|
column_map,
|
||||||
|
custom_field_map,
|
||||||
|
opts,
|
||||||
|
live_view_pid,
|
||||||
|
idx,
|
||||||
|
locale
|
||||||
|
) do
|
||||||
|
fn ->
|
||||||
|
# Set locale in task process for translations
|
||||||
|
Gettext.put_locale(MvWeb.Gettext, locale)
|
||||||
|
|
||||||
|
process_chunk_with_error_handling(
|
||||||
|
chunk,
|
||||||
|
column_map,
|
||||||
|
custom_field_map,
|
||||||
|
opts,
|
||||||
|
live_view_pid,
|
||||||
|
idx
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Handles chunk processing result from async task and schedules the next chunk.
|
# Handles chunk processing result from async task and schedules the next chunk.
|
||||||
@spec handle_chunk_result(
|
@spec handle_chunk_result(
|
||||||
Phoenix.LiveView.Socket.t(),
|
Phoenix.LiveView.Socket.t(),
|
||||||
|
|
|
||||||
|
|
@ -2319,6 +2319,21 @@ 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 member data (like e-mail or first name). Unknown data field columns will be ignored with a warning."
|
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 member data (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."
|
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_web/live/member_live/index.html.heex
|
||||||
|
#, elixir-autogen, elixir-format, fuzzy
|
||||||
|
msgid "Export members to CSV"
|
||||||
|
msgstr "Mitglieder importieren (CSV)"
|
||||||
|
|
||||||
|
#: lib/mv_web/live/member_live/index.html.heex
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgid "Export to CSV"
|
||||||
|
msgstr "Als CSV exportieren"
|
||||||
|
|
||||||
|
#: lib/mv_web/live/member_live/index.html.heex
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgid "all"
|
||||||
|
msgstr "alle"
|
||||||
|
|
||||||
#~ #: lib/mv_web/live/global_settings_live.ex
|
#~ #: lib/mv_web/live/global_settings_live.ex
|
||||||
#~ #, elixir-autogen, elixir-format, fuzzy
|
#~ #, elixir-autogen, elixir-format, fuzzy
|
||||||
#~ msgid "Custom Fields in CSV Import"
|
#~ msgid "Custom Fields in CSV Import"
|
||||||
|
|
|
||||||
|
|
@ -2319,3 +2319,18 @@ msgstr ""
|
||||||
#, elixir-autogen, elixir-format
|
#, 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 member data (like e-mail or first name). Unknown data field columns will be ignored with a warning."
|
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 member data (like e-mail or first name). Unknown data field columns will be ignored with a warning."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/mv_web/live/member_live/index.html.heex
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgid "Export members to CSV"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/mv_web/live/member_live/index.html.heex
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgid "Export to CSV"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/mv_web/live/member_live/index.html.heex
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgid "all"
|
||||||
|
msgstr ""
|
||||||
|
|
|
||||||
|
|
@ -2320,6 +2320,21 @@ 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 member data (like e-mail or first name). Unknown data field columns will be ignored with a warning."
|
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 member data (like e-mail or first name). Unknown data field columns will be ignored with a warning."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/mv_web/live/member_live/index.html.heex
|
||||||
|
#, elixir-autogen, elixir-format, fuzzy
|
||||||
|
msgid "Export members to CSV"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/mv_web/live/member_live/index.html.heex
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgid "Export to CSV"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/mv_web/live/member_live/index.html.heex
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgid "all"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#~ #: lib/mv_web/live/global_settings_live.ex
|
#~ #: lib/mv_web/live/global_settings_live.ex
|
||||||
#~ #, elixir-autogen, elixir-format, fuzzy
|
#~ #, elixir-autogen, elixir-format, fuzzy
|
||||||
#~ msgid "Custom Fields in CSV Import"
|
#~ msgid "Custom Fields in CSV Import"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue