refactor(media): use UUID instead of ID for media retrieval in GraphQL
Fixes #1760
This commit is contained in:
@@ -54,7 +54,7 @@ defmodule Mobilizon.GraphQL.API.Events do
|
||||
end
|
||||
|
||||
defp process_picture(nil, _), do: nil
|
||||
defp process_picture(%{media_id: _picture_id} = args, _), do: args
|
||||
defp process_picture(%{media_uuid: _picture_id} = args, _), do: args
|
||||
|
||||
defp process_picture(%{media: media}, %Actor{id: actor_id}) do
|
||||
# case url
|
||||
|
||||
@@ -30,6 +30,16 @@ defmodule Mobilizon.GraphQL.Resolvers.Media do
|
||||
{:ok, Enum.map(medias, &transform_media/1)}
|
||||
end
|
||||
|
||||
def get_media_by_uuid(_parent, %{uuid: uuid}, _resolution) do
|
||||
case Medias.get_media_by_uuid(uuid) do
|
||||
%Media{} = media ->
|
||||
{:ok, transform_media(media)}
|
||||
|
||||
nil ->
|
||||
{:error, :not_found}
|
||||
end
|
||||
end
|
||||
|
||||
@spec do_fetch_media(nil) :: {:error, nil}
|
||||
defp do_fetch_media(nil), do: {:error, nil}
|
||||
|
||||
@@ -103,6 +113,22 @@ defmodule Mobilizon.GraphQL.Resolvers.Media do
|
||||
|
||||
def remove_media(_parent, _args, _resolution), do: {:error, :unauthenticated}
|
||||
|
||||
def remove_media_by_uuid(_parent, %{uuid: media_uuid}, %{
|
||||
context: %{current_user: %User{} = user}
|
||||
}) do
|
||||
with {:media, %Media{actor_id: actor_id} = media} <-
|
||||
{:media, Medias.get_media_by_uuid(media_uuid)},
|
||||
{: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_by_uuid(_parent, _args, _resolution), do: {:error, :unauthenticated}
|
||||
|
||||
@doc """
|
||||
Return the total media size for an actor
|
||||
"""
|
||||
@@ -140,11 +166,12 @@ defmodule Mobilizon.GraphQL.Resolvers.Media do
|
||||
@spec transform_media(Media.t() | nil) :: map() | nil
|
||||
def transform_media(nil), do: nil
|
||||
|
||||
def transform_media(%Media{id: id, file: file, metadata: metadata}) do
|
||||
def transform_media(%Media{id: id, uuid: uuid, file: file, metadata: metadata}) do
|
||||
%{
|
||||
name: file.name,
|
||||
url: file.url,
|
||||
id: id,
|
||||
uuid: uuid,
|
||||
content_type: file.content_type,
|
||||
size: file.size,
|
||||
metadata: metadata
|
||||
|
||||
@@ -63,6 +63,12 @@ defmodule Mobilizon.GraphQL.Schema do
|
||||
field(:id, :id)
|
||||
end
|
||||
|
||||
@desc "A struct containing the uuid of the deleted object"
|
||||
object :deleted_object_by_uuid do
|
||||
meta(:authorize, :all)
|
||||
field(:uuid, :uuid)
|
||||
end
|
||||
|
||||
@desc "A JWT and the associated user ID"
|
||||
object :login do
|
||||
meta(:authorize, :all)
|
||||
|
||||
@@ -12,7 +12,7 @@ defmodule Mobilizon.GraphQL.Schema.MediaType do
|
||||
@desc "A media"
|
||||
object :media do
|
||||
meta(:authorize, :all)
|
||||
field(:id, :id, description: "The media's ID")
|
||||
field(:uuid, :uuid, description: "The media's UUID")
|
||||
field(:alt, :string, description: "The media's alternative text")
|
||||
field(:name, :string, description: "The media's name")
|
||||
field(:url, :string, description: "The media's full URL")
|
||||
@@ -44,8 +44,8 @@ defmodule Mobilizon.GraphQL.Schema.MediaType do
|
||||
input_object :media_input do
|
||||
# Either a full media object
|
||||
field(:media, :media_input_object, description: "A full media attached")
|
||||
# Or directly the ID of an existing media
|
||||
field(:media_id, :id, description: "The ID of an existing media")
|
||||
# Or directly the UUID of an existing media
|
||||
field(:media_uuid, :uuid, description: "The UUID of an existing media")
|
||||
end
|
||||
|
||||
@desc "An attached media"
|
||||
@@ -58,11 +58,11 @@ defmodule Mobilizon.GraphQL.Schema.MediaType do
|
||||
end
|
||||
|
||||
object :media_queries do
|
||||
@desc "Get a media"
|
||||
@desc "Get a media by uuid"
|
||||
field :media, :media do
|
||||
arg(:id, non_null(:id), description: "The media ID")
|
||||
arg(:uuid, non_null(:uuid), description: "The media UUID")
|
||||
middleware(Rajska.QueryAuthorization, permit: :all)
|
||||
resolve(&Media.media/3)
|
||||
resolve(&Media.get_media_by_uuid/3)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -89,16 +89,17 @@ defmodule Mobilizon.GraphQL.Schema.MediaType do
|
||||
@desc """
|
||||
Remove a media
|
||||
"""
|
||||
field :remove_media, :deleted_object do
|
||||
arg(:id, non_null(:id), description: "The media's ID")
|
||||
field :remove_media, :deleted_object_by_uuid do
|
||||
arg(:uuid, non_null(:uuid), description: "The media's UUID")
|
||||
|
||||
middleware(Rajska.QueryAuthorization,
|
||||
permit: :user,
|
||||
scope: Mobilizon.Medias.Media,
|
||||
rule: :"write:media:remove"
|
||||
rule: :"write:media:remove",
|
||||
args: :uuid
|
||||
)
|
||||
|
||||
resolve(&Media.remove_media/3)
|
||||
resolve(&Media.remove_media_by_uuid/3)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -258,9 +258,14 @@ defmodule Mobilizon.Events.Event do
|
||||
|
||||
# In case the provided picture is an existing one
|
||||
@spec put_picture(Changeset.t(), map) :: Changeset.t()
|
||||
defp put_picture(%Changeset{} = changeset, %{picture: %{media_id: id} = _picture}) do
|
||||
%Media{} = picture = Medias.get_media!(id)
|
||||
put_assoc(changeset, :picture, picture)
|
||||
defp put_picture(%Changeset{} = changeset, %{picture: %{media_uuid: uuid} = _picture}) do
|
||||
case Medias.get_media_by_uuid(uuid) do
|
||||
%Media{} = picture ->
|
||||
put_assoc(changeset, :picture, picture)
|
||||
|
||||
nil ->
|
||||
add_error(changeset, :picture, "Media with UUID #{uuid} not found")
|
||||
end
|
||||
end
|
||||
|
||||
# In case it's a new picture
|
||||
|
||||
@@ -5,7 +5,7 @@ defmodule Mobilizon.Medias.Media do
|
||||
|
||||
use Ecto.Schema
|
||||
|
||||
import Ecto.Changeset, only: [cast: 3, cast_embed: 2]
|
||||
import Ecto.Changeset
|
||||
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Discussions.Comment
|
||||
@@ -15,14 +15,19 @@ defmodule Mobilizon.Medias.Media do
|
||||
alias Mobilizon.Posts.Post
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
uuid: Ecto.UUID.t(),
|
||||
file: File.t(),
|
||||
metadata: Metadata.t(),
|
||||
actor: Actor.t()
|
||||
}
|
||||
|
||||
@attrs [:actor_id]
|
||||
@attrs [:actor_id, :uuid]
|
||||
|
||||
schema "medias" do
|
||||
# We need read_after_writes because the uuid is generated by
|
||||
# the database gen_random_uuid() function
|
||||
field(:uuid, Ecto.UUID, read_after_writes: true)
|
||||
|
||||
embeds_one(:file, File, on_replace: :update)
|
||||
|
||||
embeds_one(:metadata, Metadata, on_replace: :update)
|
||||
@@ -44,5 +49,6 @@ defmodule Mobilizon.Medias.Media do
|
||||
|> cast(attrs, @attrs)
|
||||
|> cast_embed(:file)
|
||||
|> cast_embed(:metadata)
|
||||
|> unique_constraint(:uuid)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -29,6 +29,12 @@ defmodule Mobilizon.Medias do
|
||||
@spec get_media!(integer | String.t()) :: Media.t()
|
||||
def get_media!(id), do: Repo.get!(Media, id)
|
||||
|
||||
@doc """
|
||||
Get a single media by uuid.
|
||||
"""
|
||||
@spec get_media_by_uuid(String.t()) :: Media.t() | nil
|
||||
def get_media_by_uuid(uuid), do: Repo.get_by(Media, uuid: uuid)
|
||||
|
||||
@doc """
|
||||
Get a media by its URL.
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user