Export participants to different formats
* CSV * PDF (requires Python dependency `weasyprint`) * ODS (requires Python dependency `pyexcel_ods3`) Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -6,6 +6,7 @@ defmodule Mobilizon.Config do
|
||||
alias Mobilizon.Actors
|
||||
alias Mobilizon.Service.GitStatus
|
||||
require Logger
|
||||
import Mobilizon.Service.Export.Participants.Common, only: [enabled_formats: 0]
|
||||
|
||||
@type mobilizon_config :: [
|
||||
name: String.t(),
|
||||
@@ -302,6 +303,13 @@ defmodule Mobilizon.Config do
|
||||
def instance_event_creation_enabled?,
|
||||
do: :mobilizon |> Application.get_env(:events) |> Keyword.get(:creation)
|
||||
|
||||
@spec instance_export_formats :: %{event_participants: list(String.t())}
|
||||
def instance_export_formats do
|
||||
%{
|
||||
event_participants: enabled_formats()
|
||||
}
|
||||
end
|
||||
|
||||
@spec anonymous_actor_id :: integer
|
||||
def anonymous_actor_id, do: get_cached_value(:anonymous_actor_id)
|
||||
@spec relay_actor_id :: integer
|
||||
|
||||
@@ -796,7 +796,7 @@ defmodule Mobilizon.Events do
|
||||
end
|
||||
end
|
||||
|
||||
@spec get_participant_by_confirmation_token(String.t()) :: Participant.t()
|
||||
@spec get_participant_by_confirmation_token(String.t()) :: Participant.t() | nil
|
||||
def get_participant_by_confirmation_token(confirmation_token) do
|
||||
Participant
|
||||
|> where([p], fragment("? ->>'confirmation_token' = ?", p.metadata, ^confirmation_token))
|
||||
@@ -857,9 +857,8 @@ defmodule Mobilizon.Events do
|
||||
limit \\ nil
|
||||
) do
|
||||
id
|
||||
|> list_participants_for_event_query()
|
||||
|> filter_role(roles)
|
||||
|> order_by(asc: :role)
|
||||
|> participants_for_event_query(roles)
|
||||
|> preload([:actor, :event])
|
||||
|> Page.build_page(page, limit)
|
||||
end
|
||||
|
||||
@@ -1604,11 +1603,8 @@ defmodule Mobilizon.Events do
|
||||
|
||||
@spec list_participants_for_event_query(String.t()) :: Ecto.Query.t()
|
||||
defp list_participants_for_event_query(event_id) do
|
||||
from(
|
||||
p in Participant,
|
||||
where: p.event_id == ^event_id,
|
||||
preload: [:actor, :event]
|
||||
)
|
||||
Participant
|
||||
|> where([p], p.event_id == ^event_id)
|
||||
end
|
||||
|
||||
@spec list_participant_actors_for_event_query(String.t()) :: Ecto.Query.t()
|
||||
@@ -1621,6 +1617,21 @@ defmodule Mobilizon.Events do
|
||||
)
|
||||
end
|
||||
|
||||
@spec participants_for_event_query(String.t(), list(atom())) :: Ecto.Query.t()
|
||||
def participants_for_event_query(id, roles \\ []) do
|
||||
id
|
||||
|> list_participants_for_event_query()
|
||||
|> filter_role(roles)
|
||||
|> order_by(asc: :role)
|
||||
end
|
||||
|
||||
def participant_for_event_export_query(id, roles) do
|
||||
id
|
||||
|> participants_for_event_query(roles)
|
||||
|> join(:inner, [p], a in Actor, on: p.actor_id == a.id)
|
||||
|> select([p, a], {p, a})
|
||||
end
|
||||
|
||||
@doc """
|
||||
List emails for local users (including anonymous ones) participating to an event
|
||||
|
||||
|
||||
57
lib/mobilizon/export.ex
Normal file
57
lib/mobilizon/export.ex
Normal file
@@ -0,0 +1,57 @@
|
||||
defmodule Mobilizon.Export do
|
||||
@moduledoc """
|
||||
Manage exported files
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
import Ecto.Query, only: [where: 3]
|
||||
alias Mobilizon.Storage.Repo
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
file_path: String.t(),
|
||||
file_name: String.t() | nil,
|
||||
file_size: integer() | nil,
|
||||
type: String.t(),
|
||||
reference: String.t(),
|
||||
format: String.t()
|
||||
}
|
||||
|
||||
@required_attrs [:file_path, :type, :reference, :format]
|
||||
@optional_attrs [:file_size, :file_name]
|
||||
@attrs @required_attrs ++ @optional_attrs
|
||||
|
||||
schema "exports" do
|
||||
field(:file_path, :string)
|
||||
field(:file_size, :integer)
|
||||
field(:file_name, :string)
|
||||
field(:type, :string)
|
||||
field(:reference, :string)
|
||||
field(:format, :string)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@doc false
|
||||
def changeset(export, attrs) do
|
||||
export
|
||||
|> cast(attrs, @attrs)
|
||||
|> validate_required(@required_attrs)
|
||||
end
|
||||
|
||||
@spec get_export(String.t(), String.t(), String.t()) :: t() | nil
|
||||
def get_export(file_path, type, format) do
|
||||
__MODULE__
|
||||
|> where([e], e.file_path == ^file_path and e.type == ^type and e.format == ^format)
|
||||
|> Repo.one()
|
||||
end
|
||||
|
||||
@spec outdated(String.t(), String.t(), integer()) :: list(t())
|
||||
def outdated(type, format, expiration) do
|
||||
expiration_date = DateTime.add(DateTime.utc_now(), -expiration)
|
||||
|
||||
__MODULE__
|
||||
|> where([e], e.type == ^type and e.format == ^format and e.updated_at < ^expiration_date)
|
||||
|> Repo.all()
|
||||
end
|
||||
end
|
||||
@@ -34,6 +34,7 @@ defmodule Mobilizon.Users.PushSubscription do
|
||||
|> unique_constraint([:digest, :user_id], name: :user_push_subscriptions_user_id_digest_index)
|
||||
end
|
||||
|
||||
@spec compute_digest(map()) :: String.t()
|
||||
defp compute_digest(attrs) do
|
||||
data =
|
||||
Jason.encode!(%{endpoint: attrs.endpoint, keys: %{auth: attrs.auth, p256dh: attrs.p256dh}})
|
||||
|
||||
@@ -129,7 +129,7 @@ defmodule Mobilizon.Users.User do
|
||||
end
|
||||
|
||||
@doc false
|
||||
@spec registration_changeset(t, map) :: Ecto.Changeset.t()
|
||||
@spec registration_changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||
def registration_changeset(%__MODULE__{} = user, attrs) do
|
||||
user
|
||||
|> changeset(attrs)
|
||||
@@ -147,7 +147,7 @@ defmodule Mobilizon.Users.User do
|
||||
end
|
||||
|
||||
@doc false
|
||||
@spec auth_provider_changeset(t, map) :: Ecto.Changeset.t()
|
||||
@spec auth_provider_changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||
def auth_provider_changeset(%__MODULE__{} = user, attrs) do
|
||||
user
|
||||
|> changeset(attrs)
|
||||
@@ -156,13 +156,13 @@ defmodule Mobilizon.Users.User do
|
||||
end
|
||||
|
||||
@doc false
|
||||
@spec send_password_reset_changeset(t, map) :: Ecto.Changeset.t()
|
||||
@spec send_password_reset_changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||
def send_password_reset_changeset(%__MODULE__{} = user, attrs) do
|
||||
cast(user, attrs, [:reset_password_token, :reset_password_sent_at])
|
||||
end
|
||||
|
||||
@doc false
|
||||
@spec password_reset_changeset(t, map) :: Ecto.Changeset.t()
|
||||
@spec password_reset_changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||
def password_reset_changeset(%__MODULE__{} = user, attrs) do
|
||||
password_change_changeset(user, attrs, @password_reset_required_attrs)
|
||||
end
|
||||
|
||||
@@ -281,9 +281,9 @@ defmodule Mobilizon.Users do
|
||||
@doc """
|
||||
Returns the list of users.
|
||||
"""
|
||||
@spec list_users(String.t(), integer | nil, integer | nil, atom | nil, atom | nil) ::
|
||||
@spec list_users(String.t(), integer | nil, integer | nil, atom, atom) ::
|
||||
Page.t(User.t())
|
||||
def list_users(email \\ "", page \\ nil, limit \\ nil, sort \\ nil, direction \\ nil)
|
||||
def list_users(email, page, limit \\ nil, sort, direction)
|
||||
|
||||
def list_users("", page, limit, sort, direction) do
|
||||
User
|
||||
@@ -452,7 +452,7 @@ defmodule Mobilizon.Users do
|
||||
"""
|
||||
@spec create_push_subscription(map()) ::
|
||||
{:ok, PushSubscription.t()} | {:error, Ecto.Changeset.t()}
|
||||
def create_push_subscription(attrs \\ %{}) do
|
||||
def create_push_subscription(attrs) do
|
||||
%PushSubscription{}
|
||||
|> PushSubscription.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
|
||||
Reference in New Issue
Block a user