Refactoring of Media context

This commit is contained in:
miffy 2019-09-07 02:36:37 +02:00
parent 4a0c1ea42e
commit c2b4fb6cff
5 changed files with 122 additions and 139 deletions

View file

@ -1,125 +0,0 @@
defmodule Mobilizon.Media do
@moduledoc """
The Media context.
"""
import Ecto.Query, warn: false
alias Mobilizon.Repo
alias Mobilizon.Media.Picture
alias Mobilizon.Media.File
alias Ecto.Multi
@doc false
def data() do
Dataloader.Ecto.new(Mobilizon.Repo, query: &query/2)
end
@doc false
def query(queryable, _params) do
queryable
end
@doc """
Gets a single picture.
Raises `Ecto.NoResultsError` if the Picture does not exist.
## Examples
iex> get_picture!(123)
%Picture{}
iex> get_picture!(456)
** (Ecto.NoResultsError)
"""
def get_picture!(id), do: Repo.get!(Picture, id)
def get_picture(id), do: Repo.get(Picture, id)
@doc """
Get a picture by it's URL
"""
@spec get_picture_by_url(String.t()) :: Picture.t() | nil
def get_picture_by_url(url) do
from(
p in Picture,
where: fragment("? @> ?", p.file, ~s|{"url": "#{url}"}|)
)
|> Repo.one()
end
@doc """
Creates a picture.
## Examples
iex> create_picture(%{field: value})
{:ok, %Picture{}}
iex> create_picture(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_picture(attrs \\ %{}) do
%Picture{}
|> Picture.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a picture.
## Examples
iex> update_picture(picture, %{field: new_value})
{:ok, %Picture{}}
iex> update_picture(picture, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_picture(%Picture{} = picture, attrs) do
picture
|> Picture.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a Picture.
## Examples
iex> delete_picture(picture)
{:ok, %Picture{}}
iex> delete_picture(picture)
{:error, %Ecto.Changeset{}}
"""
def delete_picture(%Picture{} = picture) do
case Multi.new()
|> Multi.delete(:picture, picture)
|> Multi.run(:remove, fn _repo, %{picture: %Picture{file: %File{url: url}}} = _picture ->
MobilizonWeb.Upload.remove(url)
end)
|> Repo.transaction() do
{:ok, %{picture: %Picture{} = picture}} -> {:ok, picture}
{:error, :remove, error, _} -> {:error, error}
end
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking picture changes.
## Examples
iex> change_picture(picture)
%Ecto.Changeset{source: %Picture{}}
"""
def change_picture(%Picture{} = picture) do
Picture.changeset(picture, %{})
end
end

View file

@ -1,9 +1,22 @@
defmodule Mobilizon.Media.File do defmodule Mobilizon.Media.File do
@moduledoc """ @moduledoc """
Represents a file entity Represents a file entity.
""" """
use Ecto.Schema use Ecto.Schema
import Ecto.Changeset
import Ecto.Changeset, only: [cast: 3, validate_required: 2]
@type t :: %__MODULE__{
name: String.t(),
url: String.t(),
content_type: String.t(),
size: integer
}
@required_attrs [:name, :url]
@optional_attrs [:content_type, :size]
@attrs @required_attrs ++ @optional_attrs
embedded_schema do embedded_schema do
field(:name, :string) field(:name, :string)
@ -15,9 +28,10 @@ defmodule Mobilizon.Media.File do
end end
@doc false @doc false
def changeset(picture, attrs) do @spec changeset(t | Ecto.Changeset.t(), map) :: Ecto.Changeset.t()
picture def changeset(file, attrs) do
|> cast(attrs, [:name, :url, :content_type, :size]) file
|> validate_required([:name, :url]) |> cast(attrs, @attrs)
|> validate_required(@required_attrs)
end end
end end

View file

@ -0,0 +1,90 @@
defmodule Mobilizon.Media do
@moduledoc """
The Media context.
"""
import Ecto.Query
alias Ecto.Multi
alias Mobilizon.Media.{File, Picture}
alias Mobilizon.Repo
@doc false
@spec data :: Dataloader.Ecto.t()
def data, do: Dataloader.Ecto.new(Mobilizon.Repo, query: &query/2)
@doc false
@spec query(Ecto.Query.t(), map) :: Ecto.Query.t()
def query(queryable, _params), do: queryable
@doc """
Gets a single picture.
"""
@spec get_picture(integer | String.t()) :: Picture.t() | nil
def get_picture(id), do: Repo.get(Picture, id)
@doc """
Gets a single picture.
Raises `Ecto.NoResultsError` if the picture does not exist.
"""
@spec get_picture!(integer | String.t()) :: Picture.t()
def get_picture!(id), do: Repo.get!(Picture, id)
@doc """
Get a picture by it's URL.
"""
@spec get_picture_by_url(String.t()) :: Picture.t() | nil
def get_picture_by_url(url) do
url
|> picture_by_url_query()
|> Repo.one()
end
@doc """
Creates a picture.
"""
@spec create_picture(map) :: {:ok, Picture.t()} | {:error, Ecto.Changeset.t()}
def create_picture(attrs \\ %{}) do
%Picture{}
|> Picture.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a picture.
"""
@spec update_picture(Picture.t(), map) :: {:ok, Picture.t()} | {:error, Ecto.Changeset.t()}
def update_picture(%Picture{} = picture, attrs) do
picture
|> Picture.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a picture.
"""
@spec delete_picture(Picture.t()) :: {:ok, Picture.t()} | {:error, Ecto.Changeset.t()}
def delete_picture(%Picture{} = picture) do
transaction =
Multi.new()
|> Multi.delete(:picture, picture)
|> Multi.run(:remove, fn _repo, %{picture: %Picture{file: %File{url: url}}} ->
MobilizonWeb.Upload.remove(url)
end)
|> Repo.transaction()
case transaction do
{:ok, %{picture: %Picture{} = picture}} -> {:ok, picture}
{:error, :remove, error, _} -> {:error, error}
end
end
@spec picture_by_url_query(String.t()) :: Ecto.Query.t()
defp picture_by_url_query(url) do
from(
p in Picture,
where: fragment("? @> ?", p.file, ~s|{"url": "#{url}"}|)
)
end
end

View file

@ -1,11 +1,19 @@
defmodule Mobilizon.Media.Picture do defmodule Mobilizon.Media.Picture do
@moduledoc """ @moduledoc """
Represents a picture entity Represents a picture entity.
""" """
use Ecto.Schema use Ecto.Schema
import Ecto.Changeset
alias Mobilizon.Media.File import Ecto.Changeset, only: [cast: 3, cast_embed: 2]
alias Mobilizon.Actors.Actor alias Mobilizon.Actors.Actor
alias Mobilizon.Media.File
@type t :: %__MODULE__{
file: File.t(),
actor: Actor.t()
}
schema "pictures" do schema "pictures" do
embeds_one(:file, File, on_replace: :update) embeds_one(:file, File, on_replace: :update)
@ -15,6 +23,7 @@ defmodule Mobilizon.Media.Picture do
end end
@doc false @doc false
@spec changeset(t | Ecto.Changeset.t(), map) :: Ecto.Changeset.t()
def changeset(picture, attrs) do def changeset(picture, attrs) do
picture picture
|> cast(attrs, [:actor_id]) |> cast(attrs, [:actor_id])

View file

@ -60,10 +60,5 @@ defmodule Mobilizon.MediaTest do
"/" <> path "/" <> path
) )
end end
test "change_picture/1 returns a picture changeset" do
picture = insert(:picture)
assert %Ecto.Changeset{} = Media.change_picture(picture)
end
end end
end end