162 lines
4.9 KiB
Elixir
162 lines
4.9 KiB
Elixir
defmodule Mobilizon.GraphQL.Resolvers.Media do
|
|
@moduledoc """
|
|
Handles the media-related GraphQL calls
|
|
"""
|
|
|
|
alias Mobilizon.Actors.Actor
|
|
alias Mobilizon.Medias
|
|
alias Mobilizon.Medias.Media
|
|
alias Mobilizon.Users.User
|
|
import Mobilizon.Web.Gettext
|
|
|
|
@doc """
|
|
Get media for an event
|
|
|
|
See Mobilizon.Web.Resolvers.Event.create_event/3
|
|
"""
|
|
def media(%{picture_id: media_id} = _parent, _args, _resolution) do
|
|
with {:ok, media} <- do_fetch_media(media_id), do: {:ok, media}
|
|
end
|
|
|
|
def media(%{picture: media} = _parent, _args, _resolution), do: {:ok, media}
|
|
def media(_parent, %{id: media_id}, _resolution), do: do_fetch_media(media_id)
|
|
def media(_parent, _args, _resolution), do: {:ok, nil}
|
|
|
|
def medias(%{media: medias}, _args, _resolution) do
|
|
{:ok, Enum.map(medias, &transform_media/1)}
|
|
end
|
|
|
|
@spec do_fetch_media(nil) :: {:error, nil}
|
|
defp do_fetch_media(nil), do: {:error, nil}
|
|
|
|
@spec do_fetch_media(String.t()) :: {:ok, Media.t()} | {:error, :not_found}
|
|
defp do_fetch_media(media_id) do
|
|
case Medias.get_media(media_id) do
|
|
%Media{} = media ->
|
|
{:ok, transform_media(media)}
|
|
|
|
nil ->
|
|
{:error, :not_found}
|
|
end
|
|
end
|
|
|
|
@spec upload_media(map, map, map) :: {:ok, Media.t()} | {:error, any}
|
|
def upload_media(
|
|
_parent,
|
|
%{file: %Plug.Upload{} = file} = args,
|
|
%{context: %{current_actor: %Actor{id: actor_id}}}
|
|
) 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: actor_id,
|
|
metadata: Map.take(uploaded, [:width, :height, :blurhash])
|
|
}) do
|
|
{:ok, transform_media(media)}
|
|
else
|
|
{:error, :mime_type_not_allowed} ->
|
|
{:error, dgettext("errors", "File doesn't have an allowed MIME type.")}
|
|
|
|
error ->
|
|
{:error, error}
|
|
end
|
|
end
|
|
|
|
def upload_media(_parent, _args, _resolution), do: {:error, :unauthenticated}
|
|
|
|
@doc """
|
|
Remove a media that the user owns
|
|
"""
|
|
@spec remove_media(map(), map(), map()) ::
|
|
{:ok, Media.t()}
|
|
| {:error, :unauthorized}
|
|
| {:error, :unauthenticated}
|
|
| {:error, :not_found}
|
|
def remove_media(_parent, %{id: media_id}, %{context: %{current_user: %User{} = user}}) do
|
|
with {:media, %Media{actor_id: actor_id} = media} <-
|
|
{:media, Medias.get_media(media_id)},
|
|
{:is_owned, %Actor{} = _actor} <- User.owns_actor(user, actor_id) do
|
|
Medias.delete_media(media)
|
|
else
|
|
{:media, nil} -> {:error, :not_found}
|
|
{:is_owned, _} -> {:error, :unauthorized}
|
|
{:error, :enofile} -> {:error, "File not found"}
|
|
end
|
|
end
|
|
|
|
def remove_media(_parent, _args, _resolution), do: {:error, :unauthenticated}
|
|
|
|
@doc """
|
|
Return the total media size for an actor
|
|
"""
|
|
@spec actor_size(map(), map(), map()) ::
|
|
{:ok, integer()} | {:error, :unauthorized} | {:error, :unauthenticated}
|
|
def actor_size(%Actor{id: actor_id}, _args, %{
|
|
context: %{current_user: %User{} = user}
|
|
}) do
|
|
if can_get_actor_size?(user, actor_id) do
|
|
{:ok, Medias.media_size_for_actor(actor_id)}
|
|
else
|
|
{:error, :unauthorized}
|
|
end
|
|
end
|
|
|
|
def actor_size(_parent, _args, _resolution), do: {:error, :unauthenticated}
|
|
|
|
@doc """
|
|
Return the total media size for a local user
|
|
"""
|
|
@spec user_size(map(), map(), map()) ::
|
|
{:ok, integer()} | {:error, :unauthorized} | {:error, :unauthenticated}
|
|
def user_size(%User{id: user_id}, _args, %{
|
|
context: %{current_user: %User{} = logged_user}
|
|
}) do
|
|
if can_get_user_size?(logged_user, user_id) do
|
|
{:ok, Medias.media_size_for_user(user_id)}
|
|
else
|
|
{:error, :unauthorized}
|
|
end
|
|
end
|
|
|
|
def user_size(_parent, _args, _resolution), do: {:error, :unauthenticated}
|
|
|
|
@spec transform_media(Media.t()) :: map()
|
|
defp transform_media(%Media{id: id, file: file, metadata: metadata}) do
|
|
%{
|
|
name: file.name,
|
|
url: file.url,
|
|
id: id,
|
|
content_type: file.content_type,
|
|
size: file.size,
|
|
metadata: metadata
|
|
}
|
|
end
|
|
|
|
@spec can_get_user_size?(User.t(), integer()) :: boolean()
|
|
defp can_get_actor_size?(%User{role: role} = user, actor_id) do
|
|
role in [:moderator, :administrator] || owns_actor?(User.owns_actor(user, actor_id))
|
|
end
|
|
|
|
@spec owns_actor?({:is_owned, Actor.t() | nil}) :: boolean()
|
|
defp owns_actor?({:is_owned, %Actor{} = _actor}), do: true
|
|
defp owns_actor?({:is_owned, _}), do: false
|
|
|
|
@spec can_get_user_size?(User.t(), integer()) :: boolean()
|
|
defp can_get_user_size?(%User{role: role, id: logged_user_id}, user_id) do
|
|
user_id == logged_user_id || role in [:moderator, :administrator]
|
|
end
|
|
end
|