Track usage of media files and add a job to clean them

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2020-11-26 11:41:13 +01:00
parent c19e326bd8
commit c9457fe0d3
78 changed files with 1405 additions and 700 deletions

View File

@@ -1,34 +1,59 @@
defmodule Mobilizon.GraphQL.API.Comments do
@moduledoc """
API for Comments.
API for discussions and comments.
"""
alias Mobilizon.Actors.Actor
alias Mobilizon.Discussions.Comment
alias Mobilizon.Federation.ActivityPub
alias Mobilizon.Federation.ActivityPub.Activity
alias Mobilizon.GraphQL.API.Utils
@doc """
Create a comment
Creates a comment from an actor
"""
@spec create_comment(map) :: {:ok, Activity.t(), Comment.t()} | any
def create_comment(args) do
args = extract_pictures_from_comment_body(args)
ActivityPub.create(:comment, args, true)
end
@doc """
Updates a comment
"""
@spec update_comment(Comment.t(), map()) :: {:ok, Activity.t(), Comment.t()} | any
def update_comment(%Comment{} = comment, args) do
args = extract_pictures_from_comment_body(args)
ActivityPub.update(comment, args, true)
end
@doc """
Deletes a comment
Deletes a comment from an actor
"""
@spec delete_comment(Comment.t(), Actor.t()) :: {:ok, Activity.t(), Comment.t()} | any
def delete_comment(%Comment{} = comment, %Actor{} = actor) do
ActivityPub.delete(comment, actor, true)
end
@doc """
Creates a discussion (or reply to a discussion)
"""
@spec create_discussion(map()) :: map()
def create_discussion(args) do
args = extract_pictures_from_comment_body(args)
ActivityPub.create(
:discussion,
args,
true
)
end
@spec extract_pictures_from_comment_body(map()) :: map()
defp extract_pictures_from_comment_body(%{text: text, actor_id: actor_id} = args) do
pictures = Utils.extract_pictures_from_body(text, actor_id)
Map.put(args, :media, pictures)
end
defp extract_pictures_from_comment_body(args), do: args
end

View File

@@ -8,6 +8,7 @@ defmodule Mobilizon.GraphQL.API.Events do
alias Mobilizon.Federation.ActivityPub
alias Mobilizon.Federation.ActivityPub.{Activity, Utils}
alias Mobilizon.GraphQL.API.Utils, as: APIUtils
@doc """
Create an event
@@ -15,6 +16,7 @@ defmodule Mobilizon.GraphQL.API.Events do
@spec create_event(map) :: {:ok, Activity.t(), Event.t()} | any
def create_event(args) do
with organizer_actor <- Map.get(args, :organizer_actor),
args <- extract_pictures_from_event_body(args, organizer_actor),
args <-
Map.update(args, :picture, nil, fn picture ->
process_picture(picture, organizer_actor)
@@ -30,6 +32,7 @@ defmodule Mobilizon.GraphQL.API.Events do
@spec update_event(map, Event.t()) :: {:ok, Activity.t(), Event.t()} | any
def update_event(args, %Event{} = event) do
with organizer_actor <- Map.get(args, :organizer_actor),
args <- extract_pictures_from_event_body(args, organizer_actor),
args <-
Map.update(args, :picture, nil, fn picture ->
process_picture(picture, organizer_actor)
@@ -40,23 +43,32 @@ defmodule Mobilizon.GraphQL.API.Events do
@doc """
Trigger the deletion of an event
If the event is deleted by
"""
def delete_event(%Event{} = event, %Actor{} = actor, federate \\ true) do
ActivityPub.delete(event, actor, federate)
end
defp process_picture(nil, _), do: nil
defp process_picture(%{picture_id: _picture_id} = args, _), do: args
defp process_picture(%{media_id: _picture_id} = args, _), do: args
defp process_picture(%{picture: picture}, %Actor{id: actor_id}) do
defp process_picture(%{media: media}, %Actor{id: actor_id}) do
%{
file:
picture
media
|> Map.get(:file)
|> Utils.make_picture_data(description: Map.get(picture, :name)),
|> Utils.make_media_data(description: Map.get(media, :name)),
actor_id: actor_id
}
end
@spec extract_pictures_from_event_body(map(), Actor.t()) :: map()
defp extract_pictures_from_event_body(
%{description: description} = args,
%Actor{id: organizer_actor_id}
) do
pictures = APIUtils.extract_pictures_from_body(description, organizer_actor_id)
Map.put(args, :media, pictures)
end
defp extract_pictures_from_event_body(args, _), do: args
end

View File

@@ -3,7 +3,8 @@ defmodule Mobilizon.GraphQL.API.Utils do
Utils for API.
"""
alias Mobilizon.Config
alias Mobilizon.{Config, Medias}
alias Mobilizon.Medias.Media
alias Mobilizon.Service.Formatter
@doc """
@@ -40,4 +41,41 @@ defmodule Mobilizon.GraphQL.API.Utils do
{:error, "Comment must be up to #{max_size} characters"}
end
end
@doc """
Use the data-media-id attributes to extract media from body text
"""
@spec extract_pictures_from_body(String.t(), integer() | String.t()) :: list(Media.t())
def extract_pictures_from_body(body, actor_id) do
body
|> do_extract_pictures_from_body()
|> Enum.map(&fetch_picture(&1, actor_id))
|> Enum.filter(& &1)
end
@spec do_extract_pictures_from_body(String.t()) :: list(String.t())
defp do_extract_pictures_from_body(body) when is_nil(body) or body == "", do: []
defp do_extract_pictures_from_body(body) do
{:ok, document} = Floki.parse_document(body)
document
|> Floki.attribute("img", "data-media-id")
end
@spec fetch_picture(String.t() | integer(), String.t() | integer()) :: Media.t() | nil
defp fetch_picture(id, actor_id) do
with %Media{actor_id: media_actor_id} = media <- Medias.get_media(id),
{:owns_media, true} <-
{:owns_media, check_actor_owns_media?(actor_id, media_actor_id)} do
media
else
_ -> nil
end
end
@spec check_actor_owns_media?(integer() | String.t(), integer() | String.t()) :: boolean()
defp check_actor_owns_media?(actor_id, media_actor_id) do
actor_id == media_actor_id || Mobilizon.Actors.is_member?(media_actor_id, actor_id)
end
end

View File

@@ -7,6 +7,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Discussion do
alias Mobilizon.Actors.Actor
alias Mobilizon.Discussions.{Comment, Discussion}
alias Mobilizon.Federation.ActivityPub
alias Mobilizon.GraphQL.API.Comments
alias Mobilizon.Storage.Page
alias Mobilizon.Users.User
import Mobilizon.Web.Gettext
@@ -94,17 +95,13 @@ defmodule Mobilizon.GraphQL.Resolvers.Discussion do
with {:actor, %Actor{id: creator_id} = _actor} <- {:actor, Users.get_actor_for_user(user)},
{:member, true} <- {:member, Actors.is_member?(creator_id, group_id)},
{:ok, _activity, %Discussion{} = discussion} <-
ActivityPub.create(
:discussion,
%{
title: title,
text: text,
actor_id: group_id,
creator_id: creator_id,
attributed_to_id: group_id
},
true
) do
Comments.create_discussion(%{
title: title,
text: text,
actor_id: group_id,
creator_id: creator_id,
attributed_to_id: group_id
}) do
{:ok, discussion}
else
{:member, false} ->
@@ -134,19 +131,15 @@ defmodule Mobilizon.GraphQL.Resolvers.Discussion do
{:no_discussion, Discussions.get_discussion(discussion_id)},
{:member, true} <- {:member, Actors.is_member?(creator_id, actor_id)},
{:ok, _activity, %Discussion{} = discussion} <-
ActivityPub.create(
:discussion,
%{
text: text,
discussion_id: discussion_id,
actor_id: creator_id,
attributed_to_id: actor_id,
in_reply_to_comment_id: last_comment_id,
origin_comment_id:
origin_comment_id || previous_in_reply_to_comment_id || last_comment_id
},
true
) do
Comments.create_discussion(%{
text: text,
discussion_id: discussion_id,
actor_id: creator_id,
attributed_to_id: actor_id,
in_reply_to_comment_id: last_comment_id,
origin_comment_id:
origin_comment_id || previous_in_reply_to_comment_id || last_comment_id
}) do
{:ok, discussion}
end
end

View File

@@ -96,8 +96,8 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do
# TODO Move me to somewhere cleaner
defp save_attached_pictures(args) do
Enum.reduce([:avatar, :banner], args, fn key, args ->
if Map.has_key?(args, key) && !is_nil(args[key][:picture]) do
pic = args[key][:picture]
if Map.has_key?(args, key) && !is_nil(args[key][:media]) do
pic = args[key][:media]
with {:ok, %{name: name, url: url, content_type: content_type, size: _size}} <-
Upload.store(pic.file, type: key, description: pic.alt) do

View File

@@ -1,50 +1,47 @@
defmodule Mobilizon.GraphQL.Resolvers.Picture do
defmodule Mobilizon.GraphQL.Resolvers.Media do
@moduledoc """
Handles the picture-related GraphQL calls
Handles the media-related GraphQL calls
"""
alias Mobilizon.Actors.Actor
alias Mobilizon.{Media, Users}
alias Mobilizon.Media.Picture
alias Mobilizon.{Medias, Users}
alias Mobilizon.Medias.Media
alias Mobilizon.Users.User
import Mobilizon.Web.Gettext
@doc """
Get picture for an event
Get media for an event
See Mobilizon.Web.Resolvers.Event.create_event/3
"""
def picture(%{picture_id: picture_id} = _parent, _args, _resolution) do
with {:ok, picture} <- do_fetch_picture(picture_id), do: {:ok, picture}
def media(%{picture_id: media_id} = _parent, _args, _resolution) do
with {:ok, media} <- do_fetch_media(media_id), do: {:ok, media}
end
def picture(%{picture: picture} = _parent, _args, _resolution), do: {:ok, picture}
def picture(_parent, %{id: picture_id}, _resolution), do: do_fetch_picture(picture_id)
def picture(_parent, _args, _resolution), do: {:ok, nil}
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}
@spec do_fetch_picture(nil) :: {:error, nil}
defp do_fetch_picture(nil), do: {:error, nil}
def medias(%{media: medias}, _args, _resolution) do
{:ok, Enum.map(medias, &transform_media/1)}
end
@spec do_fetch_picture(String.t()) :: {:ok, Picture.t()} | {:error, :not_found}
defp do_fetch_picture(picture_id) do
case Media.get_picture(picture_id) do
%Picture{id: id, file: file} ->
{:ok,
%{
name: file.name,
url: file.url,
id: id,
content_type: file.content_type,
size: file.size
}}
@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_picture(map, map, map) :: {:ok, Picture.t()} | {:error, any}
def upload_picture(
@spec upload_media(map, map, map) :: {:ok, Media.t()} | {:error, any}
def upload_media(
_parent,
%{file: %Plug.Upload{} = file} = args,
%{context: %{current_user: %User{} = user}}
@@ -57,16 +54,9 @@ defmodule Mobilizon.GraphQL.Resolvers.Picture do
|> Map.put(:url, url)
|> Map.put(:size, size)
|> Map.put(:content_type, content_type),
{:ok, picture = %Picture{}} <-
Media.create_picture(%{"file" => args, "actor_id" => actor_id}) do
{:ok,
%{
name: picture.file.name,
url: picture.file.url,
id: picture.id,
content_type: picture.file.content_type,
size: picture.file.size
}}
{:ok, media = %Media{}} <-
Medias.create_media(%{"file" => args, "actor_id" => actor_id}) do
{:ok, transform_media(media)}
else
{:error, :mime_type_not_allowed} ->
{:error, dgettext("errors", "File doesn't have an allowed MIME type.")}
@@ -76,28 +66,28 @@ defmodule Mobilizon.GraphQL.Resolvers.Picture do
end
end
def upload_picture(_parent, _args, _resolution), do: {:error, :unauthenticated}
def upload_media(_parent, _args, _resolution), do: {:error, :unauthenticated}
@doc """
Remove a picture that the user owns
Remove a media that the user owns
"""
@spec remove_picture(map(), map(), map()) ::
{:ok, Picture.t()}
@spec remove_media(map(), map(), map()) ::
{:ok, Media.t()}
| {:error, :unauthorized}
| {:error, :unauthenticated}
| {:error, :not_found}
def remove_picture(_parent, %{id: picture_id}, %{context: %{current_user: %User{} = user}}) do
with {:picture, %Picture{actor_id: actor_id} = picture} <-
{:picture, Media.get_picture(picture_id)},
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
Media.delete_picture(picture)
Medias.delete_media(media)
else
{:picture, nil} -> {:error, :not_found}
{:media, nil} -> {:error, :not_found}
{:is_owned, _} -> {:error, :unauthorized}
end
end
def remove_picture(_parent, _args, _resolution), do: {:error, :unauthenticated}
def remove_media(_parent, _args, _resolution), do: {:error, :unauthenticated}
@doc """
Return the total media size for an actor
@@ -108,7 +98,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Picture do
context: %{current_user: %User{} = user}
}) do
if can_get_actor_size?(user, actor_id) do
{:ok, Media.media_size_for_actor(actor_id)}
{:ok, Medias.media_size_for_actor(actor_id)}
else
{:error, :unauthorized}
end
@@ -125,7 +115,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Picture do
context: %{current_user: %User{} = logged_user}
}) do
if can_get_user_size?(logged_user, user_id) do
{:ok, Media.media_size_for_user(user_id)}
{:ok, Medias.media_size_for_user(user_id)}
else
{:error, :unauthorized}
end
@@ -133,6 +123,17 @@ defmodule Mobilizon.GraphQL.Resolvers.Picture do
def user_size(_parent, _args, _resolution), do: {:error, :unauthenticated}
@spec transform_media(Media.t()) :: map()
defp transform_media(%Media{id: id, file: file}) do
%{
name: file.name,
url: file.url,
id: id,
content_type: file.content_type,
size: file.size
}
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))

View File

@@ -13,6 +13,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Person do
import Mobilizon.Web.Gettext
alias Mobilizon.Federation.ActivityPub
require Logger
alias Mobilizon.Web.{MediaProxy, Upload}
@@ -137,6 +138,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Person do
%{id: id} = args,
%{context: %{current_user: user}} = _resolution
) do
require Logger
args = Map.put(args, :user_id, user.id)
with {:find_actor, %Actor{} = actor} <-
@@ -198,11 +200,11 @@ defmodule Mobilizon.GraphQL.Resolvers.Person do
defp save_attached_pictures(args) do
Enum.reduce([:avatar, :banner], args, fn key, args ->
if Map.has_key?(args, key) && !is_nil(args[key][:picture]) do
pic = args[key][:picture]
if Map.has_key?(args, key) && !is_nil(args[key][:media]) do
media = args[key][:media]
with {:ok, %{name: name, url: url, content_type: content_type, size: _size}} <-
Upload.store(pic.file, type: key, description: pic.alt) do
Upload.store(media.file, type: key, description: media.alt) do
Map.put(args, key, %{"name" => name, "url" => url, "mediaType" => content_type})
end
else

View File

@@ -116,6 +116,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Post do
Map.update(args, :picture, nil, fn picture ->
process_picture(picture, group)
end),
args <- extract_pictures_from_post_body(args, actor_id),
{:ok, _, %Post{} = post} <-
ActivityPub.create(
:post,
@@ -156,6 +157,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Post do
Map.update(args, :picture, nil, fn picture ->
process_picture(picture, group)
end),
args <- extract_pictures_from_post_body(args, actor_id),
{:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
{:ok, _, %Post{} = post} <-
ActivityPub.update(post, args, true, %{"actor" => actor_url}) do
@@ -210,15 +212,23 @@ defmodule Mobilizon.GraphQL.Resolvers.Post do
end
defp process_picture(nil, _), do: nil
defp process_picture(%{picture_id: _picture_id} = args, _), do: args
defp process_picture(%{media_id: _picture_id} = args, _), do: args
defp process_picture(%{picture: picture}, %Actor{id: actor_id}) do
defp process_picture(%{media: media}, %Actor{id: actor_id}) do
%{
file:
picture
media
|> Map.get(:file)
|> Utils.make_picture_data(description: Map.get(picture, :name)),
|> Utils.make_media_data(description: Map.get(media, :name)),
actor_id: actor_id
}
end
@spec extract_pictures_from_post_body(map(), String.t()) :: map()
defp extract_pictures_from_post_body(%{body: body} = args, actor_id) do
pictures = Mobilizon.GraphQL.API.Utils.extract_pictures_from_body(body, actor_id)
Map.put(args, :media, pictures)
end
defp extract_pictures_from_post_body(args, _actor_id), do: args
end

View File

@@ -529,7 +529,7 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
context: %{current_user: %User{id: logged_in_user_id}}
})
when user_id == logged_in_user_id do
%{elements: elements, total: total} = Mobilizon.Media.pictures_for_user(user_id, page, limit)
%{elements: elements, total: total} = Mobilizon.Medias.medias_for_user(user_id, page, limit)
{:ok,
%{

View File

@@ -30,7 +30,7 @@ defmodule Mobilizon.GraphQL.Schema do
import_types(Schema.Custom.Point)
import_types(Schema.UserType)
import_types(Schema.PictureType)
import_types(Schema.MediaType)
import_types(Schema.ActorInterface)
import_types(Schema.Actors.PersonType)
import_types(Schema.Actors.GroupType)
@@ -145,7 +145,7 @@ defmodule Mobilizon.GraphQL.Schema do
import_fields(:tag_queries)
import_fields(:address_queries)
import_fields(:config_queries)
import_fields(:picture_queries)
import_fields(:media_queries)
import_fields(:report_queries)
import_fields(:admin_queries)
import_fields(:todo_list_queries)
@@ -168,7 +168,7 @@ defmodule Mobilizon.GraphQL.Schema do
import_fields(:participant_mutations)
import_fields(:member_mutations)
import_fields(:feed_token_mutations)
import_fields(:picture_mutations)
import_fields(:media_mutations)
import_fields(:report_mutations)
import_fields(:admin_mutations)
import_fields(:todo_list_mutations)

View File

@@ -28,8 +28,8 @@ defmodule Mobilizon.GraphQL.Schema.ActorInterface do
field(:suspended, :boolean, description: "If the actor is suspended")
field(:avatar, :picture, description: "The actor's avatar picture")
field(:banner, :picture, description: "The actor's banner picture")
field(:avatar, :media, description: "The actor's avatar media")
field(:banner, :media, description: "The actor's banner media")
# These one should have a privacy setting
field(:following, list_of(:follower), description: "List of followings")

View File

@@ -3,7 +3,7 @@ defmodule Mobilizon.GraphQL.Schema.Actors.ApplicationType do
Schema representation for Group.
"""
alias Mobilizon.GraphQL.Resolvers.Picture
alias Mobilizon.GraphQL.Resolvers.Media
use Absinthe.Schema.Notation
@desc """
@@ -27,8 +27,8 @@ defmodule Mobilizon.GraphQL.Schema.Actors.ApplicationType do
field(:suspended, :boolean, description: "If the actor is suspended")
field(:avatar, :picture, description: "The actor's avatar picture")
field(:banner, :picture, description: "The actor's banner picture")
field(:avatar, :media, description: "The actor's avatar media")
field(:banner, :media, description: "The actor's banner media")
# These one should have a privacy setting
field(:following, list_of(:follower), description: "List of followings")
@@ -37,7 +37,7 @@ defmodule Mobilizon.GraphQL.Schema.Actors.ApplicationType do
field(:followingCount, :integer, description: "Number of actors following this actor")
field(:media_size, :integer,
resolve: &Picture.actor_size/3,
resolve: &Media.actor_size/3,
description: "The total size of the media from this actor"
)
end

View File

@@ -8,7 +8,7 @@ defmodule Mobilizon.GraphQL.Schema.Actors.GroupType do
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
alias Mobilizon.Addresses
alias Mobilizon.GraphQL.Resolvers.{Discussion, Group, Member, Picture, Post, Resource, Todos}
alias Mobilizon.GraphQL.Resolvers.{Discussion, Group, Media, Member, Post, Resource, Todos}
alias Mobilizon.GraphQL.Schema
import_types(Schema.Actors.MemberType)
@@ -38,8 +38,8 @@ defmodule Mobilizon.GraphQL.Schema.Actors.GroupType do
field(:suspended, :boolean, description: "If the actor is suspended")
field(:avatar, :picture, description: "The actor's avatar picture")
field(:banner, :picture, description: "The actor's banner picture")
field(:avatar, :media, description: "The actor's avatar media")
field(:banner, :media, description: "The actor's banner media")
field(:physical_address, :address,
resolve: dataloader(Addresses),
@@ -53,7 +53,7 @@ defmodule Mobilizon.GraphQL.Schema.Actors.GroupType do
field(:followingCount, :integer, description: "Number of actors following this actor")
field(:media_size, :integer,
resolve: &Picture.actor_size/3,
resolve: &Media.actor_size/3,
description: "The total size of the media from this actor"
)
@@ -198,14 +198,14 @@ defmodule Mobilizon.GraphQL.Schema.Actors.GroupType do
default_value: :public
)
arg(:avatar, :picture_input,
arg(:avatar, :media_input,
description:
"The avatar for the group, either as an object or directly the ID of an existing Picture"
"The avatar for the group, either as an object or directly the ID of an existing media"
)
arg(:banner, :picture_input,
arg(:banner, :media_input,
description:
"The banner for the group, either as an object or directly the ID of an existing Picture"
"The banner for the group, either as an object or directly the ID of an existing media"
)
arg(:physical_address, :address_input, description: "The physical address for the group")
@@ -226,14 +226,14 @@ defmodule Mobilizon.GraphQL.Schema.Actors.GroupType do
description: "Whether the group can be join freely, with approval or is invite-only."
)
arg(:avatar, :picture_input,
arg(:avatar, :media_input,
description:
"The avatar for the group, either as an object or directly the ID of an existing Picture"
"The avatar for the group, either as an object or directly the ID of an existing media"
)
arg(:banner, :picture_input,
arg(:banner, :media_input,
description:
"The banner for the group, either as an object or directly the ID of an existing Picture"
"The banner for the group, either as an object or directly the ID of an existing media"
)
arg(:physical_address, :address_input, description: "The physical address for the group")

View File

@@ -7,7 +7,7 @@ defmodule Mobilizon.GraphQL.Schema.Actors.PersonType do
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
alias Mobilizon.Events
alias Mobilizon.GraphQL.Resolvers.{Person, Picture}
alias Mobilizon.GraphQL.Resolvers.{Media, Person}
alias Mobilizon.GraphQL.Schema
import_types(Schema.Events.FeedTokenType)
@@ -40,8 +40,8 @@ defmodule Mobilizon.GraphQL.Schema.Actors.PersonType do
field(:suspended, :boolean, description: "If the actor is suspended")
field(:avatar, :picture, description: "The actor's avatar picture")
field(:banner, :picture, description: "The actor's banner picture")
field(:avatar, :media, description: "The actor's avatar media")
field(:banner, :media, description: "The actor's banner media")
# These one should have a privacy setting
field(:following, list_of(:follower), description: "List of followings")
@@ -50,7 +50,7 @@ defmodule Mobilizon.GraphQL.Schema.Actors.PersonType do
field(:followingCount, :integer, description: "Number of actors following this actor")
field(:media_size, :integer,
resolve: &Picture.actor_size/3,
resolve: &Media.actor_size/3,
description: "The total size of the media from this actor"
)
@@ -150,14 +150,14 @@ defmodule Mobilizon.GraphQL.Schema.Actors.PersonType do
arg(:summary, :string, description: "The summary for the new profile", default_value: "")
arg(:avatar, :picture_input,
arg(:avatar, :media_input,
description:
"The avatar for the profile, either as an object or directly the ID of an existing Picture"
"The avatar for the profile, either as an object or directly the ID of an existing media"
)
arg(:banner, :picture_input,
arg(:banner, :media_input,
description:
"The banner for the profile, either as an object or directly the ID of an existing Picture"
"The banner for the profile, either as an object or directly the ID of an existing media"
)
resolve(&Person.create_person/3)
@@ -171,14 +171,14 @@ defmodule Mobilizon.GraphQL.Schema.Actors.PersonType do
arg(:summary, :string, description: "The summary for this profile")
arg(:avatar, :picture_input,
arg(:avatar, :media_input,
description:
"The avatar for the profile, either as an object or directly the ID of an existing Picture"
"The avatar for the profile, either as an object or directly the ID of an existing media"
)
arg(:banner, :picture_input,
arg(:banner, :media_input,
description:
"The banner for the profile, either as an object or directly the ID of an existing Picture"
"The banner for the profile, either as an object or directly the ID of an existing media"
)
resolve(&Person.update_person/3)
@@ -200,14 +200,14 @@ defmodule Mobilizon.GraphQL.Schema.Actors.PersonType do
arg(:summary, :string, description: "The summary for the new profile", default_value: "")
arg(:email, non_null(:string), description: "The email from the user previously created")
arg(:avatar, :picture_input,
arg(:avatar, :media_input,
description:
"The avatar for the profile, either as an object or directly the ID of an existing Picture"
"The avatar for the profile, either as an object or directly the ID of an existing media"
)
arg(:banner, :picture_input,
arg(:banner, :media_input,
description:
"The banner for the profile, either as an object or directly the ID of an existing Picture"
"The banner for the profile, either as an object or directly the ID of an existing media"
)
resolve(&Person.register_person/3)

View File

@@ -43,7 +43,6 @@ defmodule Mobilizon.GraphQL.Schema.AddressType do
An address input
"""
input_object :address_input do
# Either a full picture object
field(:geom, :point, description: "The geocoordinates for the point where this address is")
field(:street, :string, description: "The address's street name (with number)")
field(:locality, :string, description: "The address's locality")

View File

@@ -8,7 +8,7 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
alias Mobilizon.{Actors, Addresses, Discussions}
alias Mobilizon.GraphQL.Resolvers.{Event, Picture, Tag}
alias Mobilizon.GraphQL.Resolvers.{Event, Media, Tag}
alias Mobilizon.GraphQL.Schema
import_types(Schema.AddressType)
@@ -31,9 +31,14 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
field(:visibility, :event_visibility, description: "The event's visibility")
field(:join_options, :event_join_options, description: "The event's visibility")
field(:picture, :picture,
field(:picture, :media,
description: "The event's picture",
resolve: &Picture.picture/3
resolve: &Media.media/3
)
field(:media, list_of(:media),
description: "The event's media",
resolve: &Media.medias/3
)
field(:publish_at, :datetime, description: "When the event was published")
@@ -328,9 +333,9 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
description: "The list of tags associated to the event"
)
arg(:picture, :picture_input,
arg(:picture, :media_input,
description:
"The picture for the event, either as an object or directly the ID of an existing Picture"
"The picture for the event, either as an object or directly the ID of an existing media"
)
arg(:publish_at, :datetime, description: "Datetime when the event was published")
@@ -379,9 +384,9 @@ defmodule Mobilizon.GraphQL.Schema.EventType do
arg(:tags, list_of(:string), description: "The list of tags associated to the event")
arg(:picture, :picture_input,
arg(:picture, :media_input,
description:
"The picture for the event, either as an object or directly the ID of an existing Picture"
"The picture for the event, either as an object or directly the ID of an existing media"
)
arg(:online_address, :string, description: "Online address of the event")

View File

@@ -0,0 +1,68 @@
defmodule Mobilizon.GraphQL.Schema.MediaType do
@moduledoc """
Schema representation for Medias
"""
use Absinthe.Schema.Notation
alias Mobilizon.GraphQL.Resolvers.Media
@desc "A media"
object :media do
field(:id, :id, description: "The media's ID")
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")
field(:content_type, :string, description: "The media's detected content type")
field(:size, :integer, description: "The media's size")
end
@desc """
A paginated list of medias
"""
object :paginated_media_list do
field(:elements, list_of(:media), description: "The list of medias")
field(:total, :integer, description: "The total number of medias in the list")
end
@desc "An attached media or a link to a media"
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")
end
@desc "An attached media"
input_object :media_input_object do
field(:name, non_null(:string), description: "The media's name")
field(:alt, :string, description: "The media's alternative text")
field(:file, non_null(:upload), description: "The media file")
field(:actor_id, :id, description: "The media owner")
end
object :media_queries do
@desc "Get a media"
field :media, :media do
arg(:id, non_null(:id), description: "The media ID")
resolve(&Media.media/3)
end
end
object :media_mutations do
@desc "Upload a media"
field :upload_media, :media do
arg(:name, non_null(:string), description: "The media's name")
arg(:alt, :string, description: "The media's alternative text")
arg(:file, non_null(:upload), description: "The media file")
resolve(&Media.upload_media/3)
end
@desc """
Remove a media
"""
field :remove_media, :deleted_object do
arg(:id, non_null(:id), description: "The media's ID")
resolve(&Media.remove_media/3)
end
end
end

View File

@@ -1,68 +0,0 @@
defmodule Mobilizon.GraphQL.Schema.PictureType do
@moduledoc """
Schema representation for Pictures
"""
use Absinthe.Schema.Notation
alias Mobilizon.GraphQL.Resolvers.Picture
@desc "A picture"
object :picture do
field(:id, :id, description: "The picture's ID")
field(:alt, :string, description: "The picture's alternative text")
field(:name, :string, description: "The picture's name")
field(:url, :string, description: "The picture's full URL")
field(:content_type, :string, description: "The picture's detected content type")
field(:size, :integer, description: "The picture's size")
end
@desc """
A paginated list of pictures
"""
object :paginated_picture_list do
field(:elements, list_of(:picture), description: "The list of pictures")
field(:total, :integer, description: "The total number of pictures in the list")
end
@desc "An attached picture or a link to a picture"
input_object :picture_input do
# Either a full picture object
field(:picture, :picture_input_object, description: "A full picture attached")
# Or directly the ID of an existing picture
field(:picture_id, :id, description: "The ID of an existing picture")
end
@desc "An attached picture"
input_object :picture_input_object do
field(:name, non_null(:string), description: "The picture's name")
field(:alt, :string, description: "The picture's alternative text")
field(:file, non_null(:upload), description: "The picture file")
field(:actor_id, :id, description: "The picture owner")
end
object :picture_queries do
@desc "Get a picture"
field :picture, :picture do
arg(:id, non_null(:id), description: "The picture ID")
resolve(&Picture.picture/3)
end
end
object :picture_mutations do
@desc "Upload a picture"
field :upload_picture, :picture do
arg(:name, non_null(:string), description: "The picture's name")
arg(:alt, :string, description: "The picture's alternative text")
arg(:file, non_null(:upload), description: "The picture file")
resolve(&Picture.upload_picture/3)
end
@desc """
Remove a picture
"""
field :remove_picture, :deleted_object do
arg(:id, non_null(:id), description: "The picture's ID")
resolve(&Picture.remove_picture/3)
end
end
end

View File

@@ -3,7 +3,7 @@ defmodule Mobilizon.GraphQL.Schema.PostType do
Schema representation for Posts
"""
use Absinthe.Schema.Notation
alias Mobilizon.GraphQL.Resolvers.{Picture, Post, Tag}
alias Mobilizon.GraphQL.Resolvers.{Media, Post, Tag}
@desc "A post"
object :post do
@@ -25,9 +25,9 @@ defmodule Mobilizon.GraphQL.Schema.PostType do
description: "The post's tags"
)
field(:picture, :picture,
description: "The posts's picture",
resolve: &Picture.picture/3
field(:picture, :media,
description: "The posts's media",
resolve: &Media.media/3
)
end
@@ -76,9 +76,9 @@ defmodule Mobilizon.GraphQL.Schema.PostType do
description: "The list of tags associated to the post"
)
arg(:picture, :picture_input,
arg(:picture, :media_input,
description:
"The banner for the post, either as an object or directly the ID of an existing Picture"
"The banner for the post, either as an object or directly the ID of an existing media"
)
resolve(&Post.create_post/3)
@@ -99,9 +99,9 @@ defmodule Mobilizon.GraphQL.Schema.PostType do
arg(:tags, list_of(:string), description: "The list of tags associated to the post")
arg(:picture, :picture_input,
arg(:picture, :media_input,
description:
"The banner for the post, either as an object or directly the ID of an existing Picture"
"The banner for the post, either as an object or directly the ID of an existing media"
)
resolve(&Post.update_post/3)

View File

@@ -7,7 +7,7 @@ defmodule Mobilizon.GraphQL.Schema.UserType do
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
alias Mobilizon.Events
alias Mobilizon.GraphQL.Resolvers.{Picture, User}
alias Mobilizon.GraphQL.Resolvers.{Media, User}
alias Mobilizon.GraphQL.Schema
import_types(Schema.SortType)
@@ -111,7 +111,7 @@ defmodule Mobilizon.GraphQL.Schema.UserType do
description: "The IP adress the user's currently signed-in with"
)
field(:media, :paginated_picture_list, description: "The user's media objects") do
field(:media, :paginated_media_list, description: "The user's media objects") do
arg(:page, :integer,
default_value: 1,
description: "The page in the paginated user media list"
@@ -122,7 +122,7 @@ defmodule Mobilizon.GraphQL.Schema.UserType do
end
field(:media_size, :integer,
resolve: &Picture.user_size/3,
resolve: &Media.user_size/3,
description: "The total size of all the media from this user (from all their actors)"
)
end