diff --git a/config/config.exs b/config/config.exs index 16f6088c..d900dffa 100644 --- a/config/config.exs +++ b/config/config.exs @@ -108,7 +108,7 @@ config :keila, KeilaWeb.Gettext, default_locale: "en", locales: ["de", "en"] -config(:keila, Keila.Mailer, from_email: "keila@localhost") +config(:keila, Keila.Auth.Emails, from_email: "keila@localhost") # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. diff --git a/lib/keila/auth/emails.ex b/lib/keila/auth/emails.ex index 529e07b8..614a909c 100644 --- a/lib/keila/auth/emails.ex +++ b/lib/keila/auth/emails.ex @@ -109,6 +109,6 @@ defmodule Keila.Auth.Emails do end defp system_from_email() do - Application.get_env(:keila, Keila.Mailer) |> Keyword.fetch!(:from_email) + Application.get_env(:keila, __MODULE__) |> Keyword.fetch!(:from_email) end end diff --git a/lib/keila/contacts/contacts.ex b/lib/keila/contacts/contacts.ex index 63c8783a..a72e0381 100644 --- a/lib/keila/contacts/contacts.ex +++ b/lib/keila/contacts/contacts.ex @@ -11,25 +11,42 @@ defmodule Keila.Contacts do @doc """ Creates a new Contact within the given Project. + + + ## Options + - `:set_status` - Also sets the `status` field from `params` when `true`. """ - @spec create_contact(Project.id(), map()) :: + @spec create_contact(Project.id(), map(), Keyword.t()) :: {:ok, Contact.t()} | {:error, Changeset.t(Contact.t())} - def create_contact(project_id, params) when is_binary(project_id) or is_integer(project_id) do + def create_contact(project_id, params, opts \\ []) + when is_binary(project_id) or is_integer(project_id) do params |> Contact.creation_changeset(project_id) + |> maybe_update_contact_status(params, opts[:set_status]) |> Repo.insert() end + defp maybe_update_contact_status(changeset, params, update?) + + defp maybe_update_contact_status(changeset, params, true), + do: Contact.update_status_changeset(changeset, params) + + defp maybe_update_contact_status(changeset, _params, _), do: changeset + defdelegate perform_form_action(form, params, opts), to: __MODULE__.FormActionHandler defdelegate perform_form_action(form, params), to: __MODULE__.FormActionHandler @doc """ Updates the specified Contact. + + ## Options + - `:update_status` - Also updates the `status` field from `params` when `true`. """ - @spec update_contact(Contact.id(), map()) :: {:ok, Contact} | {:error, Contact} - def update_contact(id, params) do + @spec update_contact(Contact.id(), map(), Keyword.t()) :: {:ok, Contact} | {:error, Contact} + def update_contact(id, params, opts \\ []) do get_contact(id) |> Contact.update_changeset(params) + |> maybe_update_contact_status(params, opts[:update_status]) |> Repo.update() end diff --git a/lib/keila/contacts/schemas/contact.ex b/lib/keila/contacts/schemas/contact.ex index 6861e135..9d83f730 100644 --- a/lib/keila/contacts/schemas/contact.ex +++ b/lib/keila/contacts/schemas/contact.ex @@ -30,6 +30,13 @@ defmodule Keila.Contacts.Contact do |> check_data_size_constraint() end + @spec update_status_changeset(t() | Ecto.Changeset.t(t()), Ecto.Changeset.data()) :: + Ecto.Changeset.t(t()) + def update_status_changeset(struct \\ %__MODULE__{}, params) do + struct + |> cast(params, [:status]) + end + @spec update_changeset(t(), Ecto.Changeset.data()) :: Ecto.Changeset.t(t()) def update_changeset(struct \\ %__MODULE__{}, params) do struct diff --git a/lib/keila/contacts/schemas/segment.ex b/lib/keila/contacts/schemas/segment.ex index 9c021d95..a63ef8d0 100644 --- a/lib/keila/contacts/schemas/segment.ex +++ b/lib/keila/contacts/schemas/segment.ex @@ -14,6 +14,7 @@ defmodule Keila.Contacts.Segment do def creation_changeset(struct \\ %__MODULE__{}, params) do struct |> cast(params, [:name, :project_id, :filter]) + |> ensure_filter_not_empty() end @spec update_changeset(t(), Changeset.data()) :: Changeset.t(t()) @@ -21,5 +22,13 @@ defmodule Keila.Contacts.Segment do struct |> cast(params, [:name, :filter]) |> validate_required(:name) + |> ensure_filter_not_empty() + end + + defp ensure_filter_not_empty(changeset) do + case get_field(changeset, :filter) do + nil -> put_change(changeset, :filter, %{}) + _other -> changeset + end end end diff --git a/lib/keila_web/api/controllers/api_contact_controller.ex b/lib/keila_web/api/controllers/api_contact_controller.ex index 6e77c2a2..bbe0b03d 100644 --- a/lib/keila_web/api/controllers/api_contact_controller.ex +++ b/lib/keila_web/api/controllers/api_contact_controller.ex @@ -73,7 +73,7 @@ defmodule KeilaWeb.ApiContactController do @spec create(Plug.Conn.t(), Map.t()) :: Plug.Conn.t() def create(conn, _params) do - case Contacts.create_contact(project_id(conn), conn.body_params.data) do + case Contacts.create_contact(project_id(conn), conn.body_params.data, set_status: true) do {:ok, contact} -> render(conn, "contact.json", %{contact: contact}) {:error, changeset} -> Errors.send_changeset_error(conn, changeset) end @@ -107,7 +107,7 @@ defmodule KeilaWeb.ApiContactController do @spec update(Plug.Conn.t(), map()) :: Plug.Conn.t() def update(conn, %{id: id}) do if Contacts.get_project_contact(project_id(conn), id) do - case Contacts.update_contact(id, conn.body_params.data) do + case Contacts.update_contact(id, conn.body_params.data, update_status: true) do {:ok, contact} -> render(conn, "contact.json", %{contact: contact}) {:error, changeset} -> Errors.send_changeset_error(conn, changeset) end diff --git a/lib/keila_web/api/schemas/contact.ex b/lib/keila_web/api/schemas/contact.ex index e5773286..dd82c2b6 100644 --- a/lib/keila_web/api/schemas/contact.ex +++ b/lib/keila_web/api/schemas/contact.ex @@ -65,6 +65,6 @@ defmodule KeilaWeb.Api.Schemas.Contact.Params do use KeilaWeb.Api.Schema @properties KeilaWeb.Api.Schemas.Contact.properties() - @allowed_properties [:email, :first_name, :last_name, :data] + @allowed_properties [:email, :first_name, :last_name, :data, :status] build_open_api_schema(@properties, only: @allowed_properties) end diff --git a/lib/keila_web/controllers/contact_controller.ex b/lib/keila_web/controllers/contact_controller.ex index 5a7b71ca..81852f2a 100644 --- a/lib/keila_web/controllers/contact_controller.ex +++ b/lib/keila_web/controllers/contact_controller.ex @@ -102,8 +102,8 @@ defmodule KeilaWeb.ContactController do defp get_sort_by(_), do: "inserted_at" - defp get_sort_order(%{"sort_order" => "-1"}), do: -1 - defp get_sort_order(_), do: 1 + defp get_sort_order(%{"sort_order" => "1"}), do: 1 + defp get_sort_order(_), do: -1 @spec delete(Plug.Conn.t(), map()) :: Plug.Conn.t() def delete(conn, params) do diff --git a/test/keila_web/api/api_contact_controller_test.exs b/test/keila_web/api/api_contact_controller_test.exs index bd78e85d..27381a37 100644 --- a/test/keila_web/api/api_contact_controller_test.exs +++ b/test/keila_web/api/api_contact_controller_test.exs @@ -172,6 +172,13 @@ defmodule KeilaWeb.ApiContactControllerTest do assert %{"data" => %{"first_name" => "Updated Name"}} = json_response(conn, 200) end + test "allows changing contact status", %{authorized_conn: conn, project: project} do + contact = insert!(:contact, project_id: project.id) + body = %{"data" => %{"status" => "unsubscribed"}} + conn = patch_json(conn, Routes.api_contact_path(conn, :update, contact.id), body) + assert %{"data" => %{"status" => "unsubscribed"}} = json_response(conn, 200) + end + @tag :api_contact_controller test "renders changeset error", %{authorized_conn: conn, project: project} do contact = insert!(:contact, project_id: project.id)