mobilizon.chapril.org-mobil.../lib/federation/activity_pub/types/todos.ex

132 lines
4.4 KiB
Elixir

defmodule Mobilizon.Federation.ActivityPub.Types.Todos do
@moduledoc """
ActivityPub type handler for Todos
"""
alias Mobilizon.{Actors, Todos}
alias Mobilizon.Actors.Actor
alias Mobilizon.Federation.ActivityPub.Permission
alias Mobilizon.Federation.ActivityPub.Types.Entity
alias Mobilizon.Federation.ActivityStream
alias Mobilizon.Federation.ActivityStream.Convertible
alias Mobilizon.Todos.{Todo, TodoList}
import Mobilizon.Federation.ActivityPub.Utils, only: [make_create_data: 2, make_update_data: 2]
require Logger
@behaviour Entity
@impl Entity
@spec create(map(), map()) ::
{:ok, Todo.t(), ActivityStream.t()} | {:error, Ecto.Changeset.t() | atom()}
def create(args, additional) do
with {:ok, %Todo{todo_list_id: todo_list_id, creator_id: creator_id} = todo} <-
Todos.create_todo(args),
{:ok, %Actor{} = creator, %TodoList{} = todo_list, %Actor{} = group} <-
creator_todo_list_and_group(creator_id, todo_list_id) do
todo = %{todo | todo_list: %{todo_list | actor: group}, creator: creator}
todo_as_data = Convertible.model_to_as(todo)
audience = %{"to" => [group.members_url], "cc" => []}
create_data = make_create_data(todo_as_data, Map.merge(audience, additional))
{:ok, todo, create_data}
end
end
@impl Entity
@spec update(Todo.t(), map, map) ::
{:ok, Todo.t(), ActivityStream.t()}
| {:error, atom() | Ecto.Changeset.t()}
def update(%Todo{} = old_todo, args, additional) do
with {:ok, %Todo{todo_list_id: todo_list_id} = todo} <- Todos.update_todo(old_todo, args),
{:ok, %TodoList{} = todo_list, %Actor{} = group} <- todo_list_and_group(todo_list_id) do
todo_as_data = Convertible.model_to_as(%{todo | todo_list: %{todo_list | actor: group}})
audience = %{"to" => [group.members_url], "cc" => []}
update_data = make_update_data(todo_as_data, Map.merge(audience, additional))
{:ok, todo, update_data}
end
end
@spec creator_todo_list_and_group(integer(), String.t()) ::
{:ok, Actor.t(), TodoList.t(), Actor.t()}
| {:error, :creator_not_found | :group_not_found | :todo_list_not_found}
defp creator_todo_list_and_group(creator_id, todo_list_id) do
case Actors.get_actor(creator_id) do
%Actor{} = creator ->
case todo_list_and_group(todo_list_id) do
{:ok, %TodoList{} = todo_list, %Actor{} = group} ->
{:ok, creator, todo_list, group}
{:error, err} ->
{:error, err}
end
nil ->
{:error, :creator_not_found}
end
end
@spec todo_list_and_group(String.t()) ::
{:ok, TodoList.t(), Actor.t()} | {:error, :group_not_found | :todo_list_not_found}
defp todo_list_and_group(todo_list_id) do
case Todos.get_todo_list(todo_list_id) do
%TodoList{actor_id: group_id} = todo_list ->
case Actors.get_group_by_actor_id(group_id) do
{:ok, %Actor{} = group} ->
{:ok, todo_list, group}
{:error, :group_not_found} ->
{:error, :group_not_found}
end
nil ->
{:error, :todo_list_not_found}
end
end
@impl Entity
@spec delete(Todo.t(), Actor.t(), any(), any()) ::
{:ok, ActivityStream.t(), Actor.t(), Todo.t()} | {:error, Ecto.Changeset.t()}
def delete(
%Todo{url: url, creator: %Actor{url: group_url}} = todo,
%Actor{url: actor_url} = actor,
_local,
_additionnal
) do
Logger.debug("Building Delete Todo activity")
activity_data = %{
"actor" => actor_url,
"type" => "Delete",
"object" => Convertible.model_to_as(url),
"id" => "#{url}/delete",
"to" => [group_url]
}
case Todos.delete_todo(todo) do
{:ok, _todo} ->
Cachex.del(:activity_pub, "todo_#{todo.id}")
{:ok, activity_data, actor, todo}
{:error, %Ecto.Changeset{} = err} ->
{:error, err}
end
end
@spec actor(Todo.t()) :: Actor.t() | nil
def actor(%Todo{creator_id: creator_id}), do: Actors.get_actor(creator_id)
@spec group_actor(Todo.t()) :: Actor.t() | nil
def group_actor(%Todo{todo_list_id: todo_list_id}) do
case Todos.get_todo_list(todo_list_id) do
%TodoList{actor_id: group_id} ->
Actors.get_actor(group_id)
_ ->
nil
end
end
@spec permissions(Todo.t()) :: Permission.t()
def permissions(%Todo{}) do
%Permission{access: :member, create: :member, update: :member, delete: :member}
end
end