defmodule Mobilizon.Admin.Setting do @moduledoc """ A Key-Value settings table for basic settings """ use Ecto.Schema import Ecto.Changeset alias Ecto.Changeset @required_attrs [:group, :name] @optional_attrs [:value] @attrs @required_attrs ++ @optional_attrs @type t :: %{ group: String.t(), name: String.t(), value: String.t() } schema "admin_settings" do field(:group, :string) field(:name, :string) field(:value, :string) timestamps() end @doc false @spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t() def changeset(setting, attrs) do setting |> cast(attrs, @attrs) |> validate_required(@required_attrs) |> unique_constraint(:group, name: :admin_settings_group_name_index) end end defmodule Mobilizon.Admin.SettingMedia do @moduledoc """ A Key-Value settings table for media settings """ use Ecto.Schema import Ecto.Changeset alias Ecto.Changeset alias Mobilizon.Federation.ActivityPub.Relay alias Mobilizon.Medias alias Mobilizon.Medias.Media alias Mobilizon.Storage.Repo @required_attrs [:group, :name] @type t :: %{ group: String.t(), name: String.t(), media: Media.t() } schema "admin_settings_medias" do field(:group, :string) field(:name, :string) belongs_to(:media, Media, on_replace: :delete) timestamps() end @doc false @spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t() def changeset(setting_media, attrs) do setting_media |> Repo.preload(:media) |> cast(attrs, @required_attrs) |> put_media(attrs) |> validate_required(@required_attrs) |> unique_constraint(:group, name: :admin_settings_medias_group_name_index) end # In case the provided media is an existing one (identified by id) @spec put_media(Changeset.t(), map) :: Changeset.t() defp put_media(%Changeset{} = changeset, %{media: %{media_id: id}}) do %Media{} = media = Medias.get_media!(id) put_assoc(changeset, :media, media) end # In case the provided media is an existing one (identified by uuid) @spec put_media(Changeset.t(), map) :: Changeset.t() defp put_media(%Changeset{} = changeset, %{media: %{media_uuid: uuid}}) do %Media{} = media = Medias.get_media_by_uuid!(uuid) put_assoc(changeset, :media, media) end # In case it's a new media defp put_media(%Changeset{} = changeset, %{media: %{media: media}}) do {:ok, media} = upload_media(media) put_assoc(changeset, :media, media) end # In case there is no media defp put_media(%Changeset{} = changeset, _media) do put_assoc(changeset, :media, nil) end import Mobilizon.Web.Gettext @spec upload_media(map) :: {:ok, Media.t()} | {:error, any} defp upload_media(%{file: %Plug.Upload{} = file} = args) do with {:ok, %{ name: _name, url: url, content_type: content_type, size: size } = uploaded} <- Mobilizon.Web.Upload.store(file), args <- args |> Map.put(:url, url) |> Map.put(:size, size) |> Map.put(:content_type, content_type), {:ok, media = %Media{}} <- Medias.create_media(%{ file: args, actor_id: Map.get(args, :actor_id, Relay.get_actor().id), metadata: Map.take(uploaded, [:width, :height, :blurhash]) }) do {:ok, media} else {:error, :mime_type_not_allowed} -> {:error, dgettext("errors", "File doesn't have an allowed MIME type.")} error -> {:error, error} end end end