Introduce group basic federation, event new page and notifications
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -25,7 +25,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Actor do
|
||||
Converts an AP object data to our internal data structure.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map) :: map
|
||||
@spec as_to_model_data(map()) :: {:ok, map()}
|
||||
def as_to_model_data(data) do
|
||||
avatar =
|
||||
data["icon"]["url"] &&
|
||||
@@ -41,7 +41,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Actor do
|
||||
"url" => MediaProxy.url(data["image"]["url"])
|
||||
}
|
||||
|
||||
actor_data = %{
|
||||
%{
|
||||
url: data["id"],
|
||||
avatar: avatar,
|
||||
banner: banner,
|
||||
@@ -53,20 +53,20 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Actor do
|
||||
outbox_url: data["outbox"],
|
||||
following_url: data["following"],
|
||||
followers_url: data["followers"],
|
||||
members_url: data["members"],
|
||||
resources_url: data["resources"],
|
||||
shared_inbox_url: data["endpoints"]["sharedInbox"],
|
||||
domain: URI.parse(data["id"]).host,
|
||||
manually_approves_followers: data["manuallyApprovesFollowers"],
|
||||
type: data["type"]
|
||||
}
|
||||
|
||||
{:ok, actor_data}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Convert an actor struct to an ActivityStream representation.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec model_to_as(ActorModel.t()) :: map
|
||||
@spec model_to_as(ActorModel.t()) :: map()
|
||||
def model_to_as(%ActorModel{} = actor) do
|
||||
actor_data = %{
|
||||
"id" => actor.url,
|
||||
@@ -76,6 +76,9 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Actor do
|
||||
"summary" => actor.summary,
|
||||
"following" => actor.following_url,
|
||||
"followers" => actor.followers_url,
|
||||
"members" => actor.members_url,
|
||||
"resources" => actor.resources_url,
|
||||
"todos" => actor.todos_url,
|
||||
"inbox" => actor.inbox_url,
|
||||
"outbox" => actor.outbox_url,
|
||||
"url" => actor.url,
|
||||
@@ -94,6 +97,13 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Actor do
|
||||
}
|
||||
}
|
||||
|
||||
actor_data =
|
||||
if actor.type == :Group do
|
||||
Map.put(actor_data, "members", actor.members_url)
|
||||
else
|
||||
actor_data
|
||||
end
|
||||
|
||||
actor_data =
|
||||
if is_nil(actor.avatar) do
|
||||
actor_data
|
||||
|
||||
@@ -7,7 +7,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Comment do
|
||||
"""
|
||||
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Events.Comment, as: CommentModel
|
||||
alias Mobilizon.Conversations.Comment, as: CommentModel
|
||||
alias Mobilizon.Events.Event
|
||||
alias Mobilizon.Tombstone, as: TombstoneModel
|
||||
|
||||
@@ -60,42 +60,36 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Comment do
|
||||
# We fetch the parent object
|
||||
Logger.debug("We're fetching the parent object")
|
||||
|
||||
data =
|
||||
if Map.has_key?(object, "inReplyTo") && object["inReplyTo"] != nil &&
|
||||
object["inReplyTo"] != "" do
|
||||
Logger.debug(fn -> "Object has inReplyTo #{object["inReplyTo"]}" end)
|
||||
if Map.has_key?(object, "inReplyTo") && object["inReplyTo"] != nil &&
|
||||
object["inReplyTo"] != "" do
|
||||
Logger.debug(fn -> "Object has inReplyTo #{object["inReplyTo"]}" end)
|
||||
|
||||
case ActivityPub.fetch_object_from_url(object["inReplyTo"]) do
|
||||
# Reply to an event (Event)
|
||||
{:ok, %Event{id: id}} ->
|
||||
Logger.debug("Parent object is an event")
|
||||
data |> Map.put(:event_id, id)
|
||||
case ActivityPub.fetch_object_from_url(object["inReplyTo"]) do
|
||||
# Reply to an event (Event)
|
||||
{:ok, %Event{id: id}} ->
|
||||
Logger.debug("Parent object is an event")
|
||||
data |> Map.put(:event_id, id)
|
||||
|
||||
# Reply to a comment (Comment)
|
||||
{:ok, %CommentModel{id: id} = comment} ->
|
||||
Logger.debug("Parent object is another comment")
|
||||
# Reply to a comment (Comment)
|
||||
{:ok, %CommentModel{id: id} = comment} ->
|
||||
Logger.debug("Parent object is another comment")
|
||||
|
||||
data
|
||||
|> Map.put(:in_reply_to_comment_id, id)
|
||||
|> Map.put(:origin_comment_id, comment |> CommentModel.get_thread_id())
|
||||
|> Map.put(:event_id, comment.event_id)
|
||||
data
|
||||
|> Map.put(:in_reply_to_comment_id, id)
|
||||
|> Map.put(:origin_comment_id, comment |> CommentModel.get_thread_id())
|
||||
|> Map.put(:event_id, comment.event_id)
|
||||
|
||||
# Anything else is kind of a MP
|
||||
{:error, parent} ->
|
||||
Logger.warn("Parent object is something we don't handle")
|
||||
Logger.debug(inspect(parent))
|
||||
data
|
||||
end
|
||||
else
|
||||
Logger.debug("No parent object for this comment")
|
||||
|
||||
data
|
||||
# Anything else is kind of a MP
|
||||
{:error, parent} ->
|
||||
Logger.warn("Parent object is something we don't handle")
|
||||
Logger.debug(inspect(parent))
|
||||
data
|
||||
end
|
||||
else
|
||||
Logger.debug("No parent object for this comment")
|
||||
|
||||
{:ok, data}
|
||||
else
|
||||
err ->
|
||||
{:error, err}
|
||||
data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||
nil
|
||||
end
|
||||
|
||||
entity = %{
|
||||
%{
|
||||
title: object["name"],
|
||||
description: object["content"],
|
||||
organizer_actor_id: actor_id,
|
||||
@@ -87,11 +87,6 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||
updated_at: object["updated"],
|
||||
publish_at: object["published"]
|
||||
}
|
||||
|
||||
{:ok, entity}
|
||||
else
|
||||
error ->
|
||||
{:error, error}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Flag do
|
||||
|
||||
alias Mobilizon.Actors
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Conversations
|
||||
alias Mobilizon.Events
|
||||
alias Mobilizon.Events.Event
|
||||
alias Mobilizon.Reports.Report
|
||||
@@ -91,7 +92,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Flag do
|
||||
Enum.filter(objects, fn url ->
|
||||
!(url == reported.url || (!is_nil(event) && event.url == url))
|
||||
end),
|
||||
comments <- Enum.map(comments, &Events.get_comment_from_url/1) do
|
||||
comments <- Enum.map(comments, &Conversations.get_comment_from_url/1) do
|
||||
%{
|
||||
"reporter" => reporter,
|
||||
"uri" => object["id"],
|
||||
|
||||
57
lib/federation/activity_stream/converter/member.ex
Normal file
57
lib/federation/activity_stream/converter/member.ex
Normal file
@@ -0,0 +1,57 @@
|
||||
defmodule Mobilizon.Federation.ActivityStream.Converter.Member do
|
||||
@moduledoc """
|
||||
Member converter.
|
||||
|
||||
This module allows to convert members from ActivityStream format to our own
|
||||
internal one, and back.
|
||||
"""
|
||||
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Actors.Member, as: MemberModel
|
||||
alias Mobilizon.Federation.ActivityPub
|
||||
alias Mobilizon.Federation.ActivityPub.Utils
|
||||
|
||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||
|
||||
defimpl Convertible, for: MemberModel do
|
||||
alias Mobilizon.Federation.ActivityStream.Converter.Member, as: MemberConverter
|
||||
|
||||
defdelegate model_to_as(member), to: MemberConverter
|
||||
end
|
||||
|
||||
@doc """
|
||||
Convert an event struct to an ActivityStream representation.
|
||||
"""
|
||||
@spec model_to_as(MemberModel.t()) :: map
|
||||
def model_to_as(%MemberModel{} = member) do
|
||||
%{
|
||||
"type" => "Member",
|
||||
"id" => member.url,
|
||||
"actor" => member.actor.url,
|
||||
"object" => member.parent.url,
|
||||
"role" => member.role
|
||||
}
|
||||
end
|
||||
|
||||
def as_to_model_data(%{
|
||||
"type" => "Member",
|
||||
"actor" => actor,
|
||||
"object" => group,
|
||||
"role" => role,
|
||||
"id" => url
|
||||
}) do
|
||||
with {:ok, %Actor{id: group_id}} <- get_actor(group),
|
||||
{:ok, %Actor{id: actor_id}} <- get_actor(actor) do
|
||||
%{
|
||||
url: url,
|
||||
actor_id: actor_id,
|
||||
parent_id: group_id,
|
||||
role: role
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@spec get_actor(String.t() | map() | nil) :: {:ok, Actor.t()} | {:error, String.t()}
|
||||
defp get_actor(nil), do: {:error, "nil property found for actor data"}
|
||||
defp get_actor(actor), do: actor |> Utils.get_url() |> ActivityPub.get_or_fetch_actor_by_url()
|
||||
end
|
||||
@@ -11,6 +11,10 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Picture do
|
||||
|
||||
alias Mobilizon.Web.Upload
|
||||
|
||||
@http_options [
|
||||
ssl: [{:versions, [:"tlsv1.2"]}]
|
||||
]
|
||||
|
||||
@doc """
|
||||
Convert a picture struct to an ActivityStream representation.
|
||||
"""
|
||||
@@ -35,7 +39,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Picture do
|
||||
actor_id
|
||||
)
|
||||
when is_bitstring(picture_url) do
|
||||
with {:ok, %HTTPoison.Response{body: body}} <- HTTPoison.get(picture_url),
|
||||
with {:ok, %HTTPoison.Response{body: body}} <- HTTPoison.get(picture_url, [], @http_options),
|
||||
{:ok, %{name: name, url: url, content_type: content_type, size: size}} <-
|
||||
Upload.store(%{body: body, name: name}),
|
||||
{:picture_exists, nil} <- {:picture_exists, Media.get_picture_by_url(url)} do
|
||||
|
||||
129
lib/federation/activity_stream/converter/resource.ex
Normal file
129
lib/federation/activity_stream/converter/resource.ex
Normal file
@@ -0,0 +1,129 @@
|
||||
defmodule Mobilizon.Federation.ActivityStream.Converter.Resource do
|
||||
@moduledoc """
|
||||
Resource converter.
|
||||
|
||||
This module allows to convert resources from ActivityStream format to our own
|
||||
internal one, and back.
|
||||
"""
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Federation.ActivityPub
|
||||
alias Mobilizon.Federation.ActivityPub.Utils
|
||||
alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
|
||||
alias Mobilizon.Resources
|
||||
alias Mobilizon.Resources.Resource
|
||||
require Logger
|
||||
|
||||
@behaviour Converter
|
||||
|
||||
defimpl Convertible, for: Resource do
|
||||
alias Mobilizon.Federation.ActivityStream.Converter.Resource, as: ResourceConverter
|
||||
|
||||
defdelegate model_to_as(resource), to: ResourceConverter
|
||||
end
|
||||
|
||||
@doc """
|
||||
Convert an resource struct to an ActivityStream representation
|
||||
"""
|
||||
@impl Converter
|
||||
@spec model_to_as(Resource.t()) :: map
|
||||
def model_to_as(
|
||||
%Resource{actor: %Actor{url: actor_url}, creator: %Actor{url: creator_url}, type: type} =
|
||||
resource
|
||||
) do
|
||||
res = %{
|
||||
"actor" => creator_url,
|
||||
"id" => resource.url,
|
||||
"name" => resource.title,
|
||||
"summary" => resource.summary,
|
||||
"context" => get_context(resource),
|
||||
"attributedTo" => actor_url
|
||||
}
|
||||
|
||||
case type do
|
||||
:folder ->
|
||||
Map.put(res, "type", "ResourceCollection")
|
||||
|
||||
_ ->
|
||||
res
|
||||
|> Map.put("type", "Document")
|
||||
|> Map.put("url", resource.resource_url)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Converts an AP object data to our internal data structure.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map) :: {:ok, map} | {:error, any()}
|
||||
def as_to_model_data(%{"type" => type, "actor" => creator, "attributedTo" => group} = object) do
|
||||
with {:ok, %Actor{id: actor_id, resources_url: resources_url}} <- get_actor(group),
|
||||
{:ok, %Actor{id: creator_id}} <- get_actor(creator),
|
||||
parent_id <- get_parent_id(object["context"], resources_url) do
|
||||
data = %{
|
||||
title: object["name"],
|
||||
summary: object["summary"],
|
||||
url: object["id"],
|
||||
actor_id: actor_id,
|
||||
creator_id: creator_id,
|
||||
parent_id: parent_id
|
||||
}
|
||||
|
||||
case type do
|
||||
"Document" ->
|
||||
data
|
||||
|> Map.put(:type, :link)
|
||||
|> Map.put(:resource_url, object["url"])
|
||||
|
||||
"ResourceCollection" ->
|
||||
data
|
||||
|> Map.put(:type, :folder)
|
||||
end
|
||||
else
|
||||
{:error, err} -> {:error, err}
|
||||
err -> {:error, err}
|
||||
end
|
||||
end
|
||||
|
||||
@spec get_actor(String.t() | map() | nil) :: {:ok, Actor.t()} | {:error, String.t()}
|
||||
defp get_actor(nil), do: {:error, "nil property found for actor data"}
|
||||
defp get_actor(actor), do: actor |> Utils.get_url() |> ActivityPub.get_or_fetch_actor_by_url()
|
||||
|
||||
defp get_context(%Resource{parent_id: nil, actor: %Actor{resources_url: resources_url}}),
|
||||
do: resources_url
|
||||
|
||||
defp get_context(%Resource{parent: %Resource{url: url}}), do: url
|
||||
|
||||
defp get_context(%Resource{parent_id: parent_id}),
|
||||
do: parent_id |> Resources.get_resource() |> Map.get(:url)
|
||||
|
||||
@spec get_parent_id(String.t(), String.t()) :: Resource.t() | map()
|
||||
defp get_parent_id(context, resources_url) do
|
||||
Logger.debug(
|
||||
"Getting parentID for context #{inspect(context)} and with resources_url #{
|
||||
inspect(resources_url)
|
||||
}"
|
||||
)
|
||||
|
||||
case Utils.get_url(context) do
|
||||
nil -> nil
|
||||
^resources_url -> nil
|
||||
context_url -> fetch_resource(context_url)
|
||||
end
|
||||
end
|
||||
|
||||
defp fetch_resource(context_url) do
|
||||
case Resources.get_resource_by_url(context_url) do
|
||||
%Resource{id: resource_id} = _resource ->
|
||||
resource_id
|
||||
|
||||
nil ->
|
||||
case ActivityPub.fetch_object_from_url(context_url) do
|
||||
{:ok, %Resource{id: resource_id} = _resource} ->
|
||||
resource_id
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
70
lib/federation/activity_stream/converter/todo.ex
Normal file
70
lib/federation/activity_stream/converter/todo.ex
Normal file
@@ -0,0 +1,70 @@
|
||||
defmodule Mobilizon.Federation.ActivityStream.Converter.Todo do
|
||||
@moduledoc """
|
||||
TodoList converter.
|
||||
|
||||
This module allows to convert todo lists from ActivityStream format to our own
|
||||
internal one, and back.
|
||||
"""
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Federation.ActivityPub
|
||||
alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
|
||||
alias Mobilizon.Todos
|
||||
alias Mobilizon.Todos.{Todo, TodoList}
|
||||
|
||||
@behaviour Converter
|
||||
|
||||
defimpl Convertible, for: Todo do
|
||||
alias Mobilizon.Federation.ActivityStream.Converter.Todo, as: TodoConverter
|
||||
|
||||
defdelegate model_to_as(todo), to: TodoConverter
|
||||
end
|
||||
|
||||
@doc """
|
||||
Convert an todo list struct to an ActivityStream representation
|
||||
"""
|
||||
@impl Converter
|
||||
@spec model_to_as(Todo.t()) :: map
|
||||
def model_to_as(
|
||||
%Todo{
|
||||
todo_list: %TodoList{actor: %Actor{url: group_url} = _group, url: todo_list_url},
|
||||
creator: %Actor{url: creator_url}
|
||||
} = todo
|
||||
) do
|
||||
%{
|
||||
"type" => "Todo",
|
||||
"actor" => creator_url,
|
||||
"attributedTo" => group_url,
|
||||
"id" => todo.url,
|
||||
"name" => todo.title,
|
||||
"status" => todo.status,
|
||||
"todoList" => todo_list_url
|
||||
}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Converts an AP object data to our internal data structure.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map) :: {:ok, map} | {:error, any()}
|
||||
def as_to_model_data(
|
||||
%{"type" => "Todo", "actor" => actor_url, "todoList" => todo_list_url} = object
|
||||
) do
|
||||
with {:ok, %Actor{id: creator_id} = _creator} <-
|
||||
ActivityPub.get_or_fetch_actor_by_url(actor_url),
|
||||
{:todo_list, %TodoList{id: todo_list_id}} <-
|
||||
{:todo_list, Todos.get_todo_list_by_url(todo_list_url)} do
|
||||
%{
|
||||
title: object["name"],
|
||||
status: object["status"],
|
||||
url: object["id"],
|
||||
todo_list_id: todo_list_id,
|
||||
creator_id: creator_id
|
||||
}
|
||||
else
|
||||
{:todo_list, nil} ->
|
||||
with {:ok, %TodoList{}} <- ActivityPub.fetch_object_from_url(todo_list_url) do
|
||||
as_to_model_data(object)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
53
lib/federation/activity_stream/converter/todo_list.ex
Normal file
53
lib/federation/activity_stream/converter/todo_list.ex
Normal file
@@ -0,0 +1,53 @@
|
||||
defmodule Mobilizon.Federation.ActivityStream.Converter.TodoList do
|
||||
@moduledoc """
|
||||
TodoList converter.
|
||||
|
||||
This module allows to convert todo lists from ActivityStream format to our own
|
||||
internal one, and back.
|
||||
"""
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Federation.ActivityPub
|
||||
alias Mobilizon.Federation.ActivityStream.{Converter, Convertible}
|
||||
alias Mobilizon.Todos.TodoList
|
||||
|
||||
@behaviour Converter
|
||||
|
||||
defimpl Convertible, for: TodoList do
|
||||
alias Mobilizon.Federation.ActivityStream.Converter.TodoList, as: TodoListConverter
|
||||
|
||||
defdelegate model_to_as(report), to: TodoListConverter
|
||||
end
|
||||
|
||||
@doc """
|
||||
Convert an todo list struct to an ActivityStream representation
|
||||
"""
|
||||
@impl Converter
|
||||
@spec model_to_as(TodoList.t()) :: map
|
||||
def model_to_as(%TodoList{actor: %Actor{url: group_url} = _group} = todo_list) do
|
||||
%{
|
||||
"type" => "TodoList",
|
||||
"actor" => group_url,
|
||||
"id" => todo_list.url,
|
||||
"title" => todo_list.title
|
||||
}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Converts an AP object data to our internal data structure.
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map) :: {:ok, map} | {:error, any()}
|
||||
def as_to_model_data(%{"type" => "TodoList", "actor" => actor_url} = object) do
|
||||
case ActivityPub.get_or_fetch_actor_by_url(actor_url) do
|
||||
{:ok, %Actor{type: :Group, id: group_id} = _group} ->
|
||||
%{
|
||||
title: object["name"],
|
||||
url: object["id"],
|
||||
actor_id: group_id
|
||||
}
|
||||
|
||||
_ ->
|
||||
{:error, :group_not_found}
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user