Some things that I've long since forgotten. Let's hope they work
This commit is contained in:
parent
de495059d5
commit
b6d7f45c60
|
@ -2,7 +2,7 @@ defmodule Clacks.Activity do
|
||||||
require Logger
|
require Logger
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
alias Clacks.Repo
|
alias Clacks.{Repo, Object}
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
@type t() :: %__MODULE__{}
|
@type t() :: %__MODULE__{}
|
||||||
|
@ -34,9 +34,16 @@ defmodule Clacks.Activity do
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec get(id :: String.t()) :: t() | nil
|
@spec get(id :: String.t(), opts :: Keyword.t()) :: t() | nil
|
||||||
def get(id) do
|
def get(id, opts \\ []) do
|
||||||
Repo.get(__MODULE__, id)
|
if Keyword.get(opts, :with_object, false) do
|
||||||
|
__MODULE__
|
||||||
|
|> where([a], a.id == ^id)
|
||||||
|
|> preload_object()
|
||||||
|
|> Repo.one()
|
||||||
|
else
|
||||||
|
Repo.get(__MODULE__, id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec get_by_ap_id(ap_id :: String.t(), force_refetch :: boolean()) :: t() | nil
|
@spec get_by_ap_id(ap_id :: String.t(), force_refetch :: boolean()) :: t() | nil
|
||||||
|
@ -55,10 +62,32 @@ defmodule Clacks.Activity do
|
||||||
|
|
||||||
@spec get_by_object_ap_id(object_id :: String.t()) :: t() | nil
|
@spec get_by_object_ap_id(object_id :: String.t()) :: t() | nil
|
||||||
def get_by_object_ap_id(object_id) do
|
def get_by_object_ap_id(object_id) do
|
||||||
Repo.one(
|
__MODULE__
|
||||||
from a in __MODULE__,
|
|> where(
|
||||||
where: fragment("?->'object'->>'id'", a.data) == ^object_id
|
[a],
|
||||||
|
fragment("COALESCE(?->'object'->>'id', ?->>'object')", a.data, a.data) == ^object_id
|
||||||
)
|
)
|
||||||
|
|> preload_object()
|
||||||
|
|> Repo.one()
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec join_with_object(Ecto.Queryable.t()) :: Ecto.Query.t()
|
||||||
|
def join_with_object(query) do
|
||||||
|
join(query, :inner, [a], o in Object,
|
||||||
|
as: :object,
|
||||||
|
on:
|
||||||
|
fragment("?->>'id' = COALESCE(?->'object'->>'id', ?->>'object')", o.data, a.data, a.data)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec preload_object(Ecto.Queryable.t()) :: Ecto.Query.t()
|
||||||
|
def preload_object(query) do
|
||||||
|
if Ecto.Query.has_named_binding?(query, :object) do
|
||||||
|
query
|
||||||
|
else
|
||||||
|
join_with_object(query)
|
||||||
|
end
|
||||||
|
|> preload([_a, object: object], object: object)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec fetch(ap_id :: String.t()) :: t() | nil
|
@spec fetch(ap_id :: String.t()) :: t() | nil
|
||||||
|
@ -91,4 +120,15 @@ defmodule Clacks.Activity do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec data_with_object(activity :: Activity.t()) :: map()
|
||||||
|
def data_with_object(%__MODULE__{
|
||||||
|
data: %{"object" => object_id} = data,
|
||||||
|
object: %Object{data: object_data}
|
||||||
|
})
|
||||||
|
when is_binary(object_id) do
|
||||||
|
Map.put(data, "object", object_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def data_with_object(%___MODULE__{data: data}), do: data
|
||||||
end
|
end
|
||||||
|
|
|
@ -78,20 +78,20 @@ defmodule Clacks.ActivityPub do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec create(
|
@spec internal_create(
|
||||||
object :: map(),
|
object :: map(),
|
||||||
id :: String.t() | nil,
|
id :: String.t() | nil,
|
||||||
actor :: String.t() | nil,
|
actor :: String.t() | nil,
|
||||||
to :: [String.t()] | nil,
|
to :: [String.t()] | nil,
|
||||||
cc :: [String.t()] | nil
|
cc :: [String.t()] | nil
|
||||||
) :: map()
|
) :: map()
|
||||||
def create(object, id \\ nil, actor \\ nil, to \\ nil, cc \\ nil) do
|
def internal_create(object, id \\ nil, actor \\ nil, to \\ nil, cc \\ nil) do
|
||||||
%{
|
%{
|
||||||
"@context" => @context,
|
"@context" => @context,
|
||||||
"id" => id || activity_id(Ecto.UUID.generate()),
|
"id" => id || activity_id(Ecto.UUID.generate()),
|
||||||
"actor" => actor || object["actor"],
|
"actor" => actor || object["actor"],
|
||||||
"type" => "Create",
|
"type" => "Create",
|
||||||
"object" => object,
|
"object" => object["id"],
|
||||||
"to" => to || object["to"],
|
"to" => to || object["to"],
|
||||||
"cc" => cc || object["cc"]
|
"cc" => cc || object["cc"]
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ defmodule Clacks.ActivityPub do
|
||||||
%{
|
%{
|
||||||
"@context" => @context,
|
"@context" => @context,
|
||||||
"type" => "Create",
|
"type" => "Create",
|
||||||
"object" => object,
|
"object" => object["id"],
|
||||||
"actor" => object["actor"] || object["attributedTo"],
|
"actor" => object["actor"] || object["attributedTo"],
|
||||||
"to" => object["to"],
|
"to" => object["to"],
|
||||||
"cc" => object["cc"]
|
"cc" => object["cc"]
|
||||||
|
|
|
@ -1,19 +1,39 @@
|
||||||
defmodule Clacks.ActivityPub.Federator do
|
defmodule Clacks.ActivityPub.Federator do
|
||||||
require Logger
|
require Logger
|
||||||
alias Clacks.{Repo, Actor, User, Keys}
|
alias Clacks.{Repo, Actor, User, Keys, Activity}
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
@public "https://www.w3.org/ns/activitystreams#Public"
|
@public "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
|
||||||
@spec federate_to_followers(activity :: map(), actor :: Actor.t()) :: :ok | {:error, any()}
|
@spec federate_to_involved(activity :: Activity.t(), actor :: Actor.t()) ::
|
||||||
def federate_to_followers(activity, actor) do
|
:ok | {:error, any()}
|
||||||
Repo.all(
|
def federate_to_involved(%Activity{data: %{"to" => to, "cc" => cc}} = activity, actor) do
|
||||||
from a in Actor, where: fragment("?->>'id'", a.data) in ^actor.followers, select: a.data
|
activity_for_federating = Activity.data_with_object(activity)
|
||||||
)
|
|
||||||
|> Enum.map(&inbox_for(activity, &1))
|
addressed =
|
||||||
|
(to ++ cc)
|
||||||
|
|> Enum.uniq()
|
||||||
|
|> List.delete(@public)
|
||||||
|
|
||||||
|
addressed_actors =
|
||||||
|
if actor.data["followers"] in addressed do
|
||||||
|
addressed = List.delete(addressed, actor.data["followers"])
|
||||||
|
[actor.followers | addressed]
|
||||||
|
else
|
||||||
|
addressed
|
||||||
|
end
|
||||||
|
|
||||||
|
Actor
|
||||||
|
|> where([a], a.ap_id in ^addressed_actors)
|
||||||
|
|> select([a], %{
|
||||||
|
shared_inbox: fragment("?->'endpoints'->>'sharedInbox'", a.data),
|
||||||
|
inbox: fragment("?->>'inbox'", a.data)
|
||||||
|
})
|
||||||
|
|> Repo.all()
|
||||||
|
|> Enum.map(&inbox_for(activity_for_federating, &1))
|
||||||
|> Enum.uniq()
|
|> Enum.uniq()
|
||||||
|> Enum.reduce_while(:ok, fn inbox, _acc ->
|
|> Enum.reduce_while(:ok, fn inbox, _acc ->
|
||||||
case federate(activity, inbox) do
|
case do_federate(activity_for_federating, inbox) do
|
||||||
{:error, _} = err ->
|
{:error, _} = err ->
|
||||||
{:halt, err}
|
{:halt, err}
|
||||||
|
|
||||||
|
@ -23,8 +43,14 @@ defmodule Clacks.ActivityPub.Federator do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec federate(activity :: map(), inbox :: String.t()) :: :ok | {:error, any()}
|
@spec federate(Activity.t(), String.t()) :: :ok | {:error, any()}
|
||||||
def federate(%{"actor" => actor_id} = activity, inbox) do
|
def federate(activity, inbox) do
|
||||||
|
activity_for_federating = Activity.data_with_object(activity)
|
||||||
|
do_federate(activity_for_federating, inbox)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec do_federate(activity :: map(), inbox :: String.t()) :: :ok | {:error, any()}
|
||||||
|
defp do_federate(%{"actor" => actor_id} = activity, inbox) do
|
||||||
Logger.debug("Federating #{activity["id"]} to #{inbox}")
|
Logger.debug("Federating #{activity["id"]} to #{inbox}")
|
||||||
%{host: inbox_host, path: inbox_path} = URI.parse(inbox)
|
%{host: inbox_host, path: inbox_path} = URI.parse(inbox)
|
||||||
|
|
||||||
|
@ -71,13 +97,13 @@ defmodule Clacks.ActivityPub.Federator do
|
||||||
shared_inbox_for(actor)
|
shared_inbox_for(actor)
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
actor["inbox"]
|
actor.inbox
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec shared_inbox_for(actor :: map()) :: String.t()
|
@spec shared_inbox_for(actor :: map()) :: String.t()
|
||||||
defp shared_inbox_for(%{"endpoints" => %{"sharedInbox" => shared}}), do: shared
|
defp shared_inbox_for(%{shared_inbox: shared}) when not is_nil(shared), do: shared
|
||||||
defp shared_inbox_for(%{"inbox" => inbox}), do: inbox
|
defp shared_inbox_for(%{inbox: inbox}), do: inbox
|
||||||
|
|
||||||
@spec signature_timestamp() :: String.t()
|
@spec signature_timestamp() :: String.t()
|
||||||
defp signature_timestamp(date \\ NaiveDateTime.utc_now()) do
|
defp signature_timestamp(date \\ NaiveDateTime.utc_now()) do
|
||||||
|
|
|
@ -44,7 +44,7 @@ defmodule Clacks.ActivityPub.Fetcher do
|
||||||
data
|
data
|
||||||
else
|
else
|
||||||
{:error, reason} ->
|
{:error, reason} ->
|
||||||
Logger.warn("Couldn't fetch AP object at #{uri}: #{inspect(reason)}")
|
Logger.warn("Couldn't fetch AP object at #{uri}: #{reason}")
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,14 @@ defmodule Clacks.Actor do
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
alias Clacks.Repo
|
alias Clacks.Repo
|
||||||
|
|
||||||
@type t() :: %__MODULE__{}
|
@type t() :: %__MODULE__{
|
||||||
|
ap_id: String.t(),
|
||||||
|
nickname: String.t(),
|
||||||
|
local: boolean(),
|
||||||
|
data: map(),
|
||||||
|
followers: [String.t()],
|
||||||
|
user: Clacks.User.t()
|
||||||
|
}
|
||||||
|
|
||||||
@primary_key {:id, FlakeId.Ecto.Type, autogenerate: true}
|
@primary_key {:id, FlakeId.Ecto.Type, autogenerate: true}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,18 @@ defmodule Clacks.Inbox do
|
||||||
|
|
||||||
defp store_activity(%{"actor" => actor, "id" => ap_id} = activity, local \\ false)
|
defp store_activity(%{"actor" => actor, "id" => ap_id} = activity, local \\ false)
|
||||||
when is_binary(actor) do
|
when is_binary(actor) do
|
||||||
|
activity_without_embedded_object =
|
||||||
|
case Map.get(activity, "object") do
|
||||||
|
%{"id" => object_id} ->
|
||||||
|
Map.put(activity, "object", object_id)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
activity
|
||||||
|
end
|
||||||
|
|
||||||
changeset =
|
changeset =
|
||||||
Activity.changeset(Activity.get_cached_by_ap_id(ap_id) || %Activity{}, %{
|
Activity.changeset(Activity.get_cached_by_ap_id(ap_id) || %Activity{}, %{
|
||||||
data: activity,
|
data: activity_without_embedded_object,
|
||||||
local: local,
|
local: local,
|
||||||
actor: actor
|
actor: actor
|
||||||
})
|
})
|
||||||
|
@ -61,7 +70,7 @@ defmodule Clacks.Inbox do
|
||||||
Logger.error("Couldn't store Accept activity: #{inspect(changeset)}")
|
Logger.error("Couldn't store Accept activity: #{inspect(changeset)}")
|
||||||
{:error, "Couldn't store Accept activity"}
|
{:error, "Couldn't store Accept activity"}
|
||||||
|
|
||||||
{:ok, _accept} ->
|
{:ok, accept} ->
|
||||||
ActivityPub.Federator.federate(accept, follower.data["inbox"])
|
ActivityPub.Federator.federate(accept, follower.data["inbox"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -53,15 +53,15 @@ defmodule Clacks.Object do
|
||||||
Repo.one(from o in __MODULE__, where: fragment("?->>'id'", o.data) == ^ap_id)
|
Repo.one(from o in __MODULE__, where: fragment("?->>'id'", o.data) == ^ap_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec fetch(ap_id :: String.t(), synthesize_create :: boolean(), return :: :object | :activity) ::
|
@spec fetch(url :: String.t(), synthesize_create :: boolean(), return :: :object | :activity) ::
|
||||||
t() | Activity.t() | nil
|
t() | Activity.t() | nil
|
||||||
def fetch(ap_id, synthesize_create \\ true, return \\ :object) do
|
def fetch(url, synthesize_create \\ true, return \\ :object) do
|
||||||
case Clacks.ActivityPub.Fetcher.fetch_object(ap_id) do
|
case Clacks.ActivityPub.Fetcher.fetch_object(url) do
|
||||||
nil ->
|
nil ->
|
||||||
nil
|
nil
|
||||||
|
|
||||||
data ->
|
%{"id" => ap_id} = data ->
|
||||||
existing = get_cached_by_ap_id(data["id"])
|
existing = get_cached_by_ap_id(ap_id)
|
||||||
|
|
||||||
changeset =
|
changeset =
|
||||||
changeset(existing || %__MODULE__{}, %{
|
changeset(existing || %__MODULE__{}, %{
|
||||||
|
@ -87,7 +87,7 @@ defmodule Clacks.Object do
|
||||||
})
|
})
|
||||||
|
|
||||||
{:ok, create} = Repo.insert_or_update(changeset)
|
{:ok, create} = Repo.insert_or_update(changeset)
|
||||||
create
|
%Clacks.Activity{create | object: object}
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,6 +21,7 @@ defmodule Clacks.Timeline do
|
||||||
|> restrict_to_public(only_public)
|
|> restrict_to_public(only_public)
|
||||||
|> paginate(params)
|
|> paginate(params)
|
||||||
|> limit(^Map.get(params, "limit", 20))
|
|> limit(^Map.get(params, "limit", 20))
|
||||||
|
|> Activity.preload_object()
|
||||||
|> join_with_announced_or_liked()
|
|> join_with_announced_or_liked()
|
||||||
|> select(
|
|> select(
|
||||||
[activity, announced, announced_actor],
|
[activity, announced, announced_actor],
|
||||||
|
@ -52,6 +53,7 @@ defmodule Clacks.Timeline do
|
||||||
|> restrict_to_types(@timeline_types)
|
|> restrict_to_types(@timeline_types)
|
||||||
|> paginate(params)
|
|> paginate(params)
|
||||||
|> limit(^Map.get(params, "limit", 20))
|
|> limit(^Map.get(params, "limit", 20))
|
||||||
|
|> Activity.preload_object()
|
||||||
|> join_with_announced_or_liked()
|
|> join_with_announced_or_liked()
|
||||||
|> select(
|
|> select(
|
||||||
[activity, actor, announced, announced_actor],
|
[activity, actor, announced, announced_actor],
|
||||||
|
@ -70,6 +72,7 @@ defmodule Clacks.Timeline do
|
||||||
|> restrict_to_types(@timeline_types)
|
|> restrict_to_types(@timeline_types)
|
||||||
|> paginate(params)
|
|> paginate(params)
|
||||||
|> limit(^Map.get(params, "limit", 20))
|
|> limit(^Map.get(params, "limit", 20))
|
||||||
|
|> Activity.preload_object()
|
||||||
|> join_with_actors()
|
|> join_with_actors()
|
||||||
|> join_with_announced_or_liked()
|
|> join_with_announced_or_liked()
|
||||||
|> select(
|
|> select(
|
||||||
|
|
|
@ -3,7 +3,12 @@ defmodule Clacks.User do
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
alias Clacks.Repo
|
alias Clacks.Repo
|
||||||
|
|
||||||
@type t() :: %__MODULE__{}
|
@type t() :: %__MODULE__{
|
||||||
|
username: String.t(),
|
||||||
|
private_key: String.t(),
|
||||||
|
password_hash: String.t(),
|
||||||
|
actor: Clacks.Actor.t()
|
||||||
|
}
|
||||||
|
|
||||||
schema "users" do
|
schema "users" do
|
||||||
field :username, :string
|
field :username, :string
|
||||||
|
|
|
@ -17,7 +17,9 @@ defmodule Clacks.UserActionsHelper do
|
||||||
|
|
||||||
def post_status(author, content, content_type, in_reply_to_ap_id)
|
def post_status(author, content, content_type, in_reply_to_ap_id)
|
||||||
when is_binary(in_reply_to_ap_id) do
|
when is_binary(in_reply_to_ap_id) do
|
||||||
case Activity.get_by_ap_id(in_reply_to_ap_id) do
|
activity = Activity.get_by_ap_id(in_reply_to_ap_id) |> Activity.preload_object()
|
||||||
|
|
||||||
|
case activity do
|
||||||
nil ->
|
nil ->
|
||||||
{:error, "Could find post to reply to with AP ID '#{in_reply_to_ap_id}'"}
|
{:error, "Could find post to reply to with AP ID '#{in_reply_to_ap_id}'"}
|
||||||
|
|
||||||
|
@ -33,7 +35,7 @@ defmodule Clacks.UserActionsHelper do
|
||||||
note_changeset = Object.changeset_for_creating(note)
|
note_changeset = Object.changeset_for_creating(note)
|
||||||
{:ok, _object} = Repo.insert(note_changeset)
|
{:ok, _object} = Repo.insert(note_changeset)
|
||||||
|
|
||||||
%{"id" => ap_id} = create = ActivityPub.create(note)
|
%{"id" => create_ap_id} = create = ActivityPub.internal_create(note, author.actor.ap_id)
|
||||||
|
|
||||||
case ActivityPub.Helper.save_and_federate(create, author.actor) do
|
case ActivityPub.Helper.save_and_federate(create, author.actor) do
|
||||||
{:ok, activity} ->
|
{:ok, activity} ->
|
||||||
|
@ -42,7 +44,7 @@ defmodule Clacks.UserActionsHelper do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
|
|
||||||
:error ->
|
:error ->
|
||||||
{:error, "Unable to save and federate activity with ID '#{ap_id}'"}
|
{:error, "Unable to save and federate activity with ID '#{create_ap_id}'"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -75,7 +77,9 @@ defmodule Clacks.UserActionsHelper do
|
||||||
{nil, nil, nil}
|
{nil, nil, nil}
|
||||||
|
|
||||||
%Activity{
|
%Activity{
|
||||||
data: %{"id" => in_reply_to_ap_id, "context" => context, "actor" => in_reply_to_actor}
|
object: %Object{
|
||||||
|
data: %{"id" => in_reply_to_ap_id, "context" => context, "actor" => in_reply_to_actor}
|
||||||
|
}
|
||||||
} ->
|
} ->
|
||||||
{context, in_reply_to_ap_id, in_reply_to_actor}
|
{context, in_reply_to_ap_id, in_reply_to_actor}
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,9 +7,9 @@ defmodule Clacks.Worker.Federate do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
def perform(%{"id" => activity_id, "actor_id" => actor_id}, _job) do
|
def perform(%{"id" => activity_id, "actor_id" => actor_id}, _job) do
|
||||||
%Activity{data: activity_data} = Repo.get(Activity, activity_id)
|
activity = Repo.get(Activity, activity_id)
|
||||||
actor = Repo.get(Actor, actor_id)
|
actor = Repo.get(Actor, actor_id)
|
||||||
|
|
||||||
:ok = ActivityPub.Federator.federate_to_followers(activity_data, actor)
|
:ok = ActivityPub.Federator.federate_to_involved(activity, actor)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,10 +6,7 @@ defmodule Clacks.Worker.SendWebmention do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@spec enqueue_for_activity(Activity.t()) :: :ok
|
@spec enqueue_for_activity(Activity.t()) :: :ok
|
||||||
def enqueue_for_activity(
|
def enqueue_for_activity(%Activity{object: %{"content" => content} = note} = activity) do
|
||||||
%Activity{data: %{"type" => "Create", "object" => %{"content" => content} = note}} =
|
|
||||||
activity
|
|
||||||
) do
|
|
||||||
tags = Map.get(note, "tag", [])
|
tags = Map.get(note, "tag", [])
|
||||||
tag_hrefs = Enum.map(tags, fn %{"href" => href} -> href end)
|
tag_hrefs = Enum.map(tags, fn %{"href" => href} -> href end)
|
||||||
|
|
||||||
|
|
|
@ -57,16 +57,12 @@ defmodule ClacksWeb.FrontendController do
|
||||||
|
|
||||||
with %Activity{
|
with %Activity{
|
||||||
local: true,
|
local: true,
|
||||||
data:
|
object: %Object{data: %{"type" => "Note", "attributedTo" => author_id}}
|
||||||
%{
|
} = activity <- Activity.get(id, with_object: true),
|
||||||
"type" => "Create",
|
|
||||||
"object" => %{"type" => "Note", "attributedTo" => author_id}
|
|
||||||
} = data
|
|
||||||
} = activity <- Activity.get(id),
|
|
||||||
%Actor{} = author <- Actor.get_by_ap_id(author_id) do
|
%Actor{} = author <- Actor.get_by_ap_id(author_id) do
|
||||||
case conn.assigns[:format] do
|
case conn.assigns[:format] do
|
||||||
"activity+json" ->
|
"activity+json" ->
|
||||||
json(conn, data)
|
json(conn, Activity.data_with_object(activity))
|
||||||
|
|
||||||
"html" ->
|
"html" ->
|
||||||
render(conn, "status.html", %{
|
render(conn, "status.html", %{
|
||||||
|
@ -177,7 +173,7 @@ defmodule ClacksWeb.FrontendController do
|
||||||
redirect(conn, to: ClacksWeb.FrontendView.local_actor_link(followee))
|
redirect(conn, to: ClacksWeb.FrontendView.local_actor_link(followee))
|
||||||
else
|
else
|
||||||
follow = ActivityPub.follow(current_user.actor.ap_id, followee.ap_id)
|
follow = ActivityPub.follow(current_user.actor.ap_id, followee.ap_id)
|
||||||
ActivityPub.Helper.save_and_federate(follow, current_user.actor)
|
{:ok, _activity} = ActivityPub.Helper.save_and_federate(follow, current_user.actor)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Follow request sent")
|
|> put_flash(:info, "Follow request sent")
|
||||||
|
@ -235,7 +231,7 @@ defmodule ClacksWeb.FrontendController do
|
||||||
status_results =
|
status_results =
|
||||||
with %Activity{
|
with %Activity{
|
||||||
actor: actor_id,
|
actor: actor_id,
|
||||||
data: %{"type" => "Create", "object" => %{"type" => "Note"}}
|
object: %Object{}
|
||||||
} = activity <- Object.fetch(q, true, :activity),
|
} = activity <- Object.fetch(q, true, :activity),
|
||||||
actor <- Actor.get_by_ap_id(actor_id) do
|
actor <- Actor.get_by_ap_id(actor_id) do
|
||||||
[{activity, actor}]
|
[{activity, actor}]
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
<li>
|
<li>
|
||||||
<%= if status.data["type"] == "Announce" do %>
|
<%= if status.data["type"] == "Announce" do %>
|
||||||
<% {announced_status, announced_actor} = announced %>
|
<% {announced_status, announced_actor} = announced %>
|
||||||
<%= render "_action_status.html", conn: @conn, action: :announce, action_activity: status, action_actor: author, original_activity: announced_status, original_note: announced_status.data["object"], original_actor: announced_actor %>
|
<%= render "_action_status.html", conn: @conn, action: :announce, action_activity: status, action_actor: author, original_activity: announced_status, original_note: announced_status.object.data, original_actor: announced_actor %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= render "_status.html", conn: @conn, author: author, status: status, note: status.data["object"] %>
|
<%= render "_status.html", conn: @conn, author: author, status: status, note: status.object.data %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -26,6 +26,6 @@
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<%= for {status, author} <- @status_results do %>
|
<%= for {status, author} <- @status_results do %>
|
||||||
<%= render "_status.html", conn: @conn, author: author, status: status, note: status.data["object"] %>
|
<%= render "_status.html", conn: @conn, author: author, status: status, note: status.object.data %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<%= render "_status.html", conn: @conn, author: @author, status: @status, note: @status.data["object"] %>
|
<%= render "_status.html", conn: @conn, author: @author, status: @status, note: @status.object.data %>
|
||||||
|
|
||||||
<%= unless is_nil(@current_user) do %>
|
<%= unless is_nil(@current_user) do %>
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<%= render "_post_form.html", conn: @conn, in_reply_to: @status.data["object"]["id"], placeholder: "Reply", content: mentions_for_replying_to(@conn, @status) %>
|
<%= render "_post_form.html", conn: @conn, in_reply_to: @status.object.data["id"], placeholder: "Reply", content: mentions_for_replying_to(@conn, @status) %>
|
||||||
<hr>
|
<hr>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
defmodule ClacksWeb.FrontendView do
|
defmodule ClacksWeb.FrontendView do
|
||||||
use ClacksWeb, :view
|
use ClacksWeb, :view
|
||||||
alias Clacks.{Actor, Activity, Repo, Notification}
|
alias Clacks.{Actor, Activity, Repo, Notification, Object}
|
||||||
alias ClacksWeb.Router.Helpers, as: Routes
|
alias ClacksWeb.Router.Helpers, as: Routes
|
||||||
alias ClacksWeb.Endpoint
|
alias ClacksWeb.Endpoint
|
||||||
require Logger
|
require Logger
|
||||||
|
@ -98,7 +98,7 @@ defmodule ClacksWeb.FrontendView do
|
||||||
|
|
||||||
@spec mentions_for_replying_to(Activity.t()) :: String.t()
|
@spec mentions_for_replying_to(Activity.t()) :: String.t()
|
||||||
defp mentions_for_replying_to(conn, %Activity{
|
defp mentions_for_replying_to(conn, %Activity{
|
||||||
data: %{"object" => %{"actor" => actor, "tag" => tags}}
|
object: %Object{data: %{"actor" => actor, "tag" => tags}}
|
||||||
}) do
|
}) do
|
||||||
current_user = conn.assigns[:user] |> Repo.preload(:actor)
|
current_user = conn.assigns[:user] |> Repo.preload(:actor)
|
||||||
|
|
||||||
|
@ -135,10 +135,7 @@ defmodule ClacksWeb.FrontendView do
|
||||||
|
|
||||||
@spec render_status_content(activity :: Activity.t()) :: String.t()
|
@spec render_status_content(activity :: Activity.t()) :: String.t()
|
||||||
defp render_status_content(%Activity{
|
defp render_status_content(%Activity{
|
||||||
data: %{
|
object: %Object{data: %{"type" => "Note", "content" => content} = note}
|
||||||
"type" => "Create",
|
|
||||||
"object" => %{"type" => "Note", "content" => content} = note
|
|
||||||
}
|
|
||||||
}) do
|
}) do
|
||||||
with %{"tag" => tags} <- note,
|
with %{"tag" => tags} <- note,
|
||||||
{:ok, tree} <- Floki.parse_fragment(content) do
|
{:ok, tree} <- Floki.parse_fragment(content) do
|
||||||
|
|
Loading…
Reference in New Issue