ods.ex 2.96 KB
Newer Older
1
2
3
4
5
defmodule Mobilizon.Service.Export.Participants.ODS do
  @moduledoc """
  Export a list of participants to ODS
  """

6
  alias Mobilizon.{Events, Export, PythonPort, PythonWorker}
7
8
9
10
11
12
  alias Mobilizon.Events.Event
  alias Mobilizon.Storage.Repo
  alias Mobilizon.Web.Gettext, as: GettextBackend
  import Mobilizon.Web.Gettext, only: [gettext: 2]

  import Mobilizon.Service.Export.Participants.Common,
13
14
15
16
17
18
19
20
    only: [
      save_upload: 5,
      to_list: 1,
      clean_exports: 2,
      columns: 0,
      export_enabled?: 1,
      export_path: 1
    ]
21
22
23
24
25
26
27
28
29
30
31
32

  @extension "ods"

  def extension do
    @extension
  end

  @spec export(Event.t(), Keyword.t()) ::
          {:ok, String.t()} | {:error, :failed_to_save_upload | :export_dependency_not_installed}
  def export(%Event{id: event_id} = event, options \\ []) do
    if ready?() do
      filename = "#{ShortUUID.encode!(Ecto.UUID.generate())}.ods"
33
      full_path = Path.join([export_path(@extension), filename])
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

      case Repo.transaction(
             fn ->
               content =
                 event_id
                 |> Events.participant_for_event_export_query(Keyword.get(options, :roles, []))
                 |> Repo.all()
                 |> Enum.map(&to_list/1)
                 |> (fn data -> Enum.concat([columns()], data) end).()
                 |> generate_ods()

               File.write!(full_path, content)

               with {:error, err} <- save_ods_upload(full_path, filename, event) do
                 Repo.rollback(err)
               end
             end,
             timeout: :infinity
           ) do
        {:error, _err} ->
          File.rm!(full_path)
          {:error, :failed_to_save_upload}

        {:ok, _ok} ->
          {:ok, filename}
      end
    else
      {:error, :export_dependency_not_installed}
    end
  end

  defp generate_ods(data) do
    data
    |> Jason.encode!()
    |> PythonWorker.generate_ods()
  end

  @spec save_ods_upload(String.t(), String.t(), Event.t()) ::
          {:ok, Export.t()} | {:error, atom() | Ecto.Changeset.t()}
  defp save_ods_upload(full_path, filename, %Event{id: event_id, title: title}) do
    GettextBackend.gettext_comment(
      "File name template for exported list of participants. Should NOT contain spaces. Make sure the output is going to be something standardized that is acceptable as a file name on most systems."
    )

    save_upload(
      full_path,
      filename,
      to_string(event_id),
      gettext("%{event}_participants", event: title) <> ".ods",
      "ods"
    )
  end

  @doc """
  Clean outdated files in export folder
  """
  @spec clean_exports :: :ok
  def clean_exports do
92
    clean_exports(@extension, export_path(@extension))
93
94
95
96
  end

  @spec dependencies_ok? :: boolean
  def dependencies_ok? do
97
    PythonPort.python_exists?() && PythonWorker.has_module("pyexcel_ods3")
98
99
100
101
102
103
104
105
106
107
108
109
  end

  @spec enabled? :: boolean
  def enabled? do
    export_enabled?(__MODULE__)
  end

  @spec ready? :: boolean
  def ready? do
    enabled?() && dependencies_ok?()
  end
end