Format the code.
This commit is contained in:
parent
480932c8e5
commit
4afbef39f4
111 changed files with 4912 additions and 2769 deletions
|
|
@ -18,7 +18,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
with nil <- Activity.get_by_ap_id(map["id"]),
|
||||
map <- lazy_put_activity_defaults(map),
|
||||
:ok <- insert_full_object(map) do
|
||||
{:ok, activity} = Repo.insert(%Activity{data: map, local: local, actor: map["actor"], recipients: get_recipients(map)})
|
||||
{:ok, activity} =
|
||||
Repo.insert(%Activity{
|
||||
data: map,
|
||||
local: local,
|
||||
actor: map["actor"],
|
||||
recipients: get_recipients(map)
|
||||
})
|
||||
|
||||
Notification.create_notifications(activity)
|
||||
stream_out(activity)
|
||||
{:ok, activity}
|
||||
|
|
@ -31,8 +38,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
def stream_out(activity) do
|
||||
if activity.data["type"] in ["Create", "Announce"] do
|
||||
Pleroma.Web.Streamer.stream("user", activity)
|
||||
|
||||
if Enum.member?(activity.data["to"], "https://www.w3.org/ns/activitystreams#Public") do
|
||||
Pleroma.Web.Streamer.stream("public", activity)
|
||||
|
||||
if activity.local do
|
||||
Pleroma.Web.Streamer.stream("public:local", activity)
|
||||
end
|
||||
|
|
@ -42,10 +51,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
def create(%{to: to, actor: actor, context: context, object: object} = params) do
|
||||
additional = params[:additional] || %{}
|
||||
local = !(params[:local] == false) # only accept false as false value
|
||||
# only accept false as false value
|
||||
local = !(params[:local] == false)
|
||||
published = params[:published]
|
||||
|
||||
with create_data <- make_create_data(%{to: to, actor: actor, published: published, context: context, object: object}, additional),
|
||||
with create_data <-
|
||||
make_create_data(
|
||||
%{to: to, actor: actor, published: published, context: context, object: object},
|
||||
additional
|
||||
),
|
||||
{:ok, activity} <- insert(create_data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
|
|
@ -53,7 +67,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
def accept(%{to: to, actor: actor, object: object} = params) do
|
||||
local = !(params[:local] == false) # only accept false as false value
|
||||
# only accept false as false value
|
||||
local = !(params[:local] == false)
|
||||
|
||||
with data <- %{"to" => to, "type" => "Accept", "actor" => actor, "object" => object},
|
||||
{:ok, activity} <- insert(data, local),
|
||||
|
|
@ -63,9 +78,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
def update(%{to: to, cc: cc, actor: actor, object: object} = params) do
|
||||
local = !(params[:local] == false) # only accept false as false value
|
||||
# only accept false as false value
|
||||
local = !(params[:local] == false)
|
||||
|
||||
with data <- %{"to" => to, "cc" => cc, "type" => "Update", "actor" => actor, "object" => object},
|
||||
with data <- %{
|
||||
"to" => to,
|
||||
"cc" => cc,
|
||||
"type" => "Update",
|
||||
"actor" => actor,
|
||||
"object" => object
|
||||
},
|
||||
{:ok, activity} <- insert(data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
|
|
@ -73,7 +95,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
# TODO: This is weird, maybe we shouldn't check here if we can make the activity.
|
||||
def like(%User{ap_id: ap_id} = user, %Object{data: %{"id" => _}} = object, activity_id \\ nil, local \\ true) do
|
||||
def like(
|
||||
%User{ap_id: ap_id} = user,
|
||||
%Object{data: %{"id" => _}} = object,
|
||||
activity_id \\ nil,
|
||||
local \\ true
|
||||
) do
|
||||
with nil <- get_existing_like(ap_id, object),
|
||||
like_data <- make_like_data(user, object, activity_id),
|
||||
{:ok, activity} <- insert(like_data, local),
|
||||
|
|
@ -91,11 +118,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
{:ok, _activity} <- Repo.delete(activity),
|
||||
{:ok, object} <- remove_like_from_object(activity, object) do
|
||||
{:ok, object}
|
||||
else _e -> {:ok, object}
|
||||
else
|
||||
_e -> {:ok, object}
|
||||
end
|
||||
end
|
||||
|
||||
def announce(%User{ap_id: _} = user, %Object{data: %{"id" => _}} = object, activity_id \\ nil, local \\ true) do
|
||||
def announce(
|
||||
%User{ap_id: _} = user,
|
||||
%Object{data: %{"id" => _}} = object,
|
||||
activity_id \\ nil,
|
||||
local \\ true
|
||||
) do
|
||||
with true <- is_public?(object),
|
||||
announce_data <- make_announce_data(user, object, activity_id),
|
||||
{:ok, activity} <- insert(announce_data, local),
|
||||
|
|
@ -119,19 +152,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
|
||||
unfollow_data <- make_unfollow_data(follower, followed, follow_activity),
|
||||
{:ok, activity} <- insert(unfollow_data, local),
|
||||
:ok, maybe_federate(activity) do
|
||||
:ok,
|
||||
maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
|
||||
user = User.get_cached_by_ap_id(actor)
|
||||
|
||||
data = %{
|
||||
"type" => "Delete",
|
||||
"actor" => actor,
|
||||
"object" => id,
|
||||
"to" => [user.follower_address, "https://www.w3.org/ns/activitystreams#Public"]
|
||||
}
|
||||
|
||||
with Repo.delete(object),
|
||||
Repo.delete_all(Activity.all_non_create_by_object_ap_id_q(id)),
|
||||
{:ok, activity} <- insert(data, local),
|
||||
|
|
@ -142,112 +178,147 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
def fetch_activities_for_context(context, opts \\ %{}) do
|
||||
public = ["https://www.w3.org/ns/activitystreams#Public"]
|
||||
recipients = if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public
|
||||
|
||||
query = from activity in Activity
|
||||
query = query
|
||||
recipients =
|
||||
if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public
|
||||
|
||||
query = from(activity in Activity)
|
||||
|
||||
query =
|
||||
query
|
||||
|> restrict_blocked(opts)
|
||||
|> restrict_recipients(recipients, opts["user"])
|
||||
|
||||
query = from activity in query,
|
||||
where: fragment("?->>'type' = ? and ?->>'context' = ?", activity.data, "Create", activity.data, ^context),
|
||||
order_by: [desc: :id]
|
||||
query =
|
||||
from(
|
||||
activity in query,
|
||||
where:
|
||||
fragment(
|
||||
"?->>'type' = ? and ?->>'context' = ?",
|
||||
activity.data,
|
||||
"Create",
|
||||
activity.data,
|
||||
^context
|
||||
),
|
||||
order_by: [desc: :id]
|
||||
)
|
||||
|
||||
Repo.all(query)
|
||||
end
|
||||
|
||||
# TODO: Make this work properly with unlisted.
|
||||
def fetch_public_activities(opts \\ %{}) do
|
||||
q = fetch_activities_query(["https://www.w3.org/ns/activitystreams#Public"], opts)
|
||||
|
||||
q
|
||||
|> Repo.all
|
||||
|> Enum.reverse
|
||||
|> Repo.all()
|
||||
|> Enum.reverse()
|
||||
end
|
||||
|
||||
defp restrict_since(query, %{"since_id" => since_id}) do
|
||||
from activity in query, where: activity.id > ^since_id
|
||||
from(activity in query, where: activity.id > ^since_id)
|
||||
end
|
||||
|
||||
defp restrict_since(query, _), do: query
|
||||
|
||||
defp restrict_tag(query, %{"tag" => tag}) do
|
||||
from activity in query,
|
||||
from(
|
||||
activity in query,
|
||||
where: fragment("? <@ (? #> '{\"object\",\"tag\"}')", ^tag, activity.data)
|
||||
)
|
||||
end
|
||||
|
||||
defp restrict_tag(query, _), do: query
|
||||
|
||||
defp restrict_recipients(query, [], user), do: query
|
||||
|
||||
defp restrict_recipients(query, recipients, nil) do
|
||||
from activity in query,
|
||||
where: fragment("? && ?", ^recipients, activity.recipients)
|
||||
from(activity in query, where: fragment("? && ?", ^recipients, activity.recipients))
|
||||
end
|
||||
|
||||
defp restrict_recipients(query, recipients, user) do
|
||||
from activity in query,
|
||||
from(
|
||||
activity in query,
|
||||
where: fragment("? && ?", ^recipients, activity.recipients),
|
||||
or_where: activity.actor == ^user.ap_id
|
||||
)
|
||||
end
|
||||
|
||||
defp restrict_limit(query, %{"limit" => limit}) do
|
||||
from activity in query,
|
||||
limit: ^limit
|
||||
from(activity in query, limit: ^limit)
|
||||
end
|
||||
|
||||
defp restrict_limit(query, _), do: query
|
||||
|
||||
defp restrict_local(query, %{"local_only" => true}) do
|
||||
from activity in query, where: activity.local == true
|
||||
from(activity in query, where: activity.local == true)
|
||||
end
|
||||
|
||||
defp restrict_local(query, _), do: query
|
||||
|
||||
defp restrict_max(query, %{"max_id" => max_id}) do
|
||||
from activity in query, where: activity.id < ^max_id
|
||||
from(activity in query, where: activity.id < ^max_id)
|
||||
end
|
||||
|
||||
defp restrict_max(query, _), do: query
|
||||
|
||||
defp restrict_actor(query, %{"actor_id" => actor_id}) do
|
||||
from activity in query,
|
||||
where: activity.actor == ^actor_id
|
||||
from(activity in query, where: activity.actor == ^actor_id)
|
||||
end
|
||||
|
||||
defp restrict_actor(query, _), do: query
|
||||
|
||||
defp restrict_type(query, %{"type" => type}) when is_binary(type) do
|
||||
restrict_type(query, %{"type" => [type]})
|
||||
end
|
||||
|
||||
defp restrict_type(query, %{"type" => type}) do
|
||||
from activity in query,
|
||||
where: fragment("?->>'type' = ANY(?)", activity.data, ^type)
|
||||
from(activity in query, where: fragment("?->>'type' = ANY(?)", activity.data, ^type))
|
||||
end
|
||||
|
||||
defp restrict_type(query, _), do: query
|
||||
|
||||
defp restrict_favorited_by(query, %{"favorited_by" => ap_id}) do
|
||||
from activity in query,
|
||||
from(
|
||||
activity in query,
|
||||
where: fragment("? <@ (? #> '{\"object\",\"likes\"}')", ^ap_id, activity.data)
|
||||
)
|
||||
end
|
||||
|
||||
defp restrict_favorited_by(query, _), do: query
|
||||
|
||||
defp restrict_media(query, %{"only_media" => val}) when val == "true" or val == "1" do
|
||||
from activity in query,
|
||||
from(
|
||||
activity in query,
|
||||
where: fragment("not (? #> '{\"object\",\"attachment\"}' = ?)", activity.data, ^[])
|
||||
)
|
||||
end
|
||||
|
||||
defp restrict_media(query, _), do: query
|
||||
|
||||
# Only search through last 100_000 activities by default
|
||||
defp restrict_recent(query, %{"whole_db" => true}), do: query
|
||||
|
||||
defp restrict_recent(query, _) do
|
||||
since = (Repo.aggregate(Activity, :max, :id) || 0) - 100_000
|
||||
|
||||
from activity in query,
|
||||
where: activity.id > ^since
|
||||
from(activity in query, where: activity.id > ^since)
|
||||
end
|
||||
|
||||
defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do
|
||||
blocks = info["blocks"] || []
|
||||
from activity in query,
|
||||
where: fragment("not (? = ANY(?))", activity.actor, ^blocks)
|
||||
from(activity in query, where: fragment("not (? = ANY(?))", activity.actor, ^blocks))
|
||||
end
|
||||
|
||||
defp restrict_blocked(query, _), do: query
|
||||
|
||||
def fetch_activities_query(recipients, opts \\ %{}) do
|
||||
base_query = from activity in Activity,
|
||||
limit: 20,
|
||||
order_by: [fragment("? desc nulls last", activity.id)]
|
||||
base_query =
|
||||
from(
|
||||
activity in Activity,
|
||||
limit: 20,
|
||||
order_by: [fragment("? desc nulls last", activity.id)]
|
||||
)
|
||||
|
||||
base_query
|
||||
|> restrict_recipients(recipients, opts["user"])
|
||||
|
|
@ -266,8 +337,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
def fetch_activities(recipients, opts \\ %{}) do
|
||||
fetch_activities_query(recipients, opts)
|
||||
|> Repo.all
|
||||
|> Enum.reverse
|
||||
|> Repo.all()
|
||||
|> Enum.reverse()
|
||||
end
|
||||
|
||||
def upload(file) do
|
||||
|
|
@ -276,15 +347,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
def user_data_from_user_object(data) do
|
||||
avatar = data["icon"]["url"] && %{
|
||||
"type" => "Image",
|
||||
"url" => [%{"href" => data["icon"]["url"]}]
|
||||
}
|
||||
avatar =
|
||||
data["icon"]["url"] &&
|
||||
%{
|
||||
"type" => "Image",
|
||||
"url" => [%{"href" => data["icon"]["url"]}]
|
||||
}
|
||||
|
||||
banner = data["image"]["url"] && %{
|
||||
"type" => "Image",
|
||||
"url" => [%{"href" => data["image"]["url"]}]
|
||||
}
|
||||
banner =
|
||||
data["image"]["url"] &&
|
||||
%{
|
||||
"type" => "Image",
|
||||
"url" => [%{"href" => data["image"]["url"]}]
|
||||
}
|
||||
|
||||
user_data = %{
|
||||
ap_id: data["id"],
|
||||
|
|
@ -304,8 +379,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
def fetch_and_prepare_user_from_ap_id(ap_id) do
|
||||
with {:ok, %{status_code: 200, body: body}} <- @httpoison.get(ap_id, ["Accept": "application/activity+json"]),
|
||||
{:ok, data} <- Jason.decode(body) do
|
||||
with {:ok, %{status_code: 200, body: body}} <-
|
||||
@httpoison.get(ap_id, Accept: "application/activity+json"),
|
||||
{:ok, data} <- Jason.decode(body) do
|
||||
user_data_from_user_object(data)
|
||||
else
|
||||
e -> Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}")
|
||||
|
|
@ -333,32 +409,48 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
def publish(actor, activity) do
|
||||
followers = if actor.follower_address in activity.recipients do
|
||||
{:ok, followers} = User.get_followers(actor)
|
||||
followers |> Enum.filter(&(!&1.local))
|
||||
else
|
||||
[]
|
||||
end
|
||||
followers =
|
||||
if actor.follower_address in activity.recipients do
|
||||
{:ok, followers} = User.get_followers(actor)
|
||||
followers |> Enum.filter(&(!&1.local))
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
remote_inboxes = (Pleroma.Web.Salmon.remote_users(activity) ++ followers)
|
||||
|> Enum.filter(fn (user) -> User.ap_enabled?(user) end)
|
||||
|> Enum.map(fn (%{info: %{"source_data" => data}}) ->
|
||||
(data["endpoints"] && data["endpoints"]["sharedInbox"]) || data["inbox"]
|
||||
end)
|
||||
|> Enum.uniq
|
||||
remote_inboxes =
|
||||
(Pleroma.Web.Salmon.remote_users(activity) ++ followers)
|
||||
|> Enum.filter(fn user -> User.ap_enabled?(user) end)
|
||||
|> Enum.map(fn %{info: %{"source_data" => data}} ->
|
||||
(data["endpoints"] && data["endpoints"]["sharedInbox"]) || data["inbox"]
|
||||
end)
|
||||
|> Enum.uniq()
|
||||
|
||||
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
|
||||
json = Jason.encode!(data)
|
||||
Enum.each remote_inboxes, fn(inbox) ->
|
||||
Federator.enqueue(:publish_single_ap, %{inbox: inbox, json: json, actor: actor, id: activity.data["id"]})
|
||||
end
|
||||
|
||||
Enum.each(remote_inboxes, fn inbox ->
|
||||
Federator.enqueue(:publish_single_ap, %{
|
||||
inbox: inbox,
|
||||
json: json,
|
||||
actor: actor,
|
||||
id: activity.data["id"]
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
def publish_one(%{inbox: inbox, json: json, actor: actor, id: id}) do
|
||||
Logger.info("Federating #{id} to #{inbox}")
|
||||
host = URI.parse(inbox).host
|
||||
signature = Pleroma.Web.HTTPSignatures.sign(actor, %{host: host, "content-length": byte_size(json)})
|
||||
@httpoison.post(inbox, json, [{"Content-Type", "application/activity+json"}, {"signature", signature}], hackney: [pool: :default])
|
||||
|
||||
signature =
|
||||
Pleroma.Web.HTTPSignatures.sign(actor, %{host: host, "content-length": byte_size(json)})
|
||||
|
||||
@httpoison.post(
|
||||
inbox,
|
||||
json,
|
||||
[{"Content-Type", "application/activity+json"}, {"signature", signature}],
|
||||
hackney: [pool: :default]
|
||||
)
|
||||
end
|
||||
|
||||
# TODO:
|
||||
|
|
@ -368,17 +460,34 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
{:ok, object}
|
||||
else
|
||||
Logger.info("Fetching #{id} via AP")
|
||||
|
||||
with true <- String.starts_with?(id, "http"),
|
||||
{:ok, %{body: body, status_code: code}} when code in 200..299 <- @httpoison.get(id, [Accept: "application/activity+json"], follow_redirect: true, timeout: 10000, recv_timeout: 20000),
|
||||
{:ok, %{body: body, status_code: code}} when code in 200..299 <-
|
||||
@httpoison.get(
|
||||
id,
|
||||
[Accept: "application/activity+json"],
|
||||
follow_redirect: true,
|
||||
timeout: 10000,
|
||||
recv_timeout: 20000
|
||||
),
|
||||
{:ok, data} <- Jason.decode(body),
|
||||
nil <- Object.get_by_ap_id(data["id"]),
|
||||
params <- %{"type" => "Create", "to" => data["to"], "cc" => data["cc"], "actor" => data["attributedTo"], "object" => data},
|
||||
params <- %{
|
||||
"type" => "Create",
|
||||
"to" => data["to"],
|
||||
"cc" => data["cc"],
|
||||
"actor" => data["attributedTo"],
|
||||
"object" => data
|
||||
},
|
||||
{:ok, activity} <- Transmogrifier.handle_incoming(params) do
|
||||
{:ok, Object.get_by_ap_id(activity.data["object"]["id"])}
|
||||
else
|
||||
object = %Object{} -> {:ok, object}
|
||||
object = %Object{} ->
|
||||
{:ok, object}
|
||||
|
||||
e ->
|
||||
Logger.info("Couldn't get object via AP, trying out OStatus fetching...")
|
||||
|
||||
case OStatus.fetch_activity_from_url(id) do
|
||||
{:ok, [activity | _]} -> {:ok, Object.get_by_ap_id(activity.data["object"]["id"])}
|
||||
e -> e
|
||||
|
|
@ -388,15 +497,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
def is_public?(activity) do
|
||||
"https://www.w3.org/ns/activitystreams#Public" in (activity.data["to"] ++ (activity.data["cc"] || []))
|
||||
"https://www.w3.org/ns/activitystreams#Public" in (activity.data["to"] ++
|
||||
(activity.data["cc"] || []))
|
||||
end
|
||||
|
||||
def visible_for_user?(activity, nil) do
|
||||
is_public?(activity)
|
||||
end
|
||||
|
||||
def visible_for_user?(activity, user) do
|
||||
x = [user.ap_id | user.following]
|
||||
y = (activity.data["to"] ++ (activity.data["cc"] || []))
|
||||
y = activity.data["to"] ++ (activity.data["cc"] || [])
|
||||
visible_for_user?(activity, nil) || Enum.any?(x, &(&1 in y))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
|
||||
require Logger
|
||||
|
||||
action_fallback :errors
|
||||
action_fallback(:errors)
|
||||
|
||||
def user(conn, %{"nickname" => nickname}) do
|
||||
with %User{} = user <- User.get_cached_by_nickname(nickname),
|
||||
|
|
@ -31,6 +31,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
with %User{} = user <- User.get_cached_by_nickname(nickname),
|
||||
{:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
|
||||
{page, _} = Integer.parse(page)
|
||||
|
||||
conn
|
||||
|> put_resp_header("content-type", "application/activity+json")
|
||||
|> json(UserView.render("following.json", %{user: user, page: page}))
|
||||
|
|
@ -50,6 +51,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
with %User{} = user <- User.get_cached_by_nickname(nickname),
|
||||
{:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do
|
||||
{page, _} = Integer.parse(page)
|
||||
|
||||
conn
|
||||
|> put_resp_header("content-type", "application/activity+json")
|
||||
|> json(UserView.render("followers.json", %{user: user, page: page}))
|
||||
|
|
@ -74,7 +76,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
end
|
||||
end
|
||||
|
||||
def outbox(conn, %{"nickname" => nickname}) do outbox(conn, %{"nickname" => nickname, "max_id" => nil}) end
|
||||
def outbox(conn, %{"nickname" => nickname}) do
|
||||
outbox(conn, %{"nickname" => nickname, "max_id" => nil})
|
||||
end
|
||||
|
||||
# TODO: Ensure that this inbox is a recipient of the message
|
||||
def inbox(%{assigns: %{valid_signature: true}} = conn, params) do
|
||||
|
|
@ -84,7 +88,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
|
||||
def inbox(conn, params) do
|
||||
headers = Enum.into(conn.req_headers, %{})
|
||||
if !(String.contains?(headers["signature"] || "", params["actor"])) do
|
||||
|
||||
if !String.contains?(headers["signature"] || "", params["actor"]) do
|
||||
Logger.info("Signature not from author, relayed message, fetching from source")
|
||||
ActivityPub.fetch_object_from_id(params["object"]["id"])
|
||||
else
|
||||
|
|
|
|||
|
|
@ -25,21 +25,25 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|> fix_tag
|
||||
end
|
||||
|
||||
def fix_in_reply_to(%{"inReplyTo" => in_reply_to_id} = object) when not is_nil(in_reply_to_id) do
|
||||
def fix_in_reply_to(%{"inReplyTo" => in_reply_to_id} = object)
|
||||
when not is_nil(in_reply_to_id) do
|
||||
case ActivityPub.fetch_object_from_id(in_reply_to_id) do
|
||||
{:ok, replied_object} ->
|
||||
activity = Activity.get_create_activity_by_object_ap_id(replied_object.data["id"])
|
||||
|
||||
object
|
||||
|> Map.put("inReplyTo", replied_object.data["id"])
|
||||
|> Map.put("inReplyToAtomUri", object["inReplyToAtomUri"] || in_reply_to_id)
|
||||
|> Map.put("inReplyToStatusId", activity.id)
|
||||
|> Map.put("conversation", replied_object.data["context"] || object["conversation"])
|
||||
|> Map.put("context", replied_object.data["context"] || object["conversation"])
|
||||
|
||||
e ->
|
||||
Logger.error("Couldn't fetch #{object["inReplyTo"]} #{inspect(e)}")
|
||||
object
|
||||
end
|
||||
end
|
||||
|
||||
def fix_in_reply_to(object), do: object
|
||||
|
||||
def fix_context(object) do
|
||||
|
|
@ -48,27 +52,32 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
|
||||
def fix_attachments(object) do
|
||||
attachments = (object["attachment"] || [])
|
||||
|> Enum.map(fn (data) ->
|
||||
url = [%{"type" => "Link", "mediaType" => data["mediaType"], "href" => data["url"]}]
|
||||
Map.put(data, "url", url)
|
||||
end)
|
||||
attachments =
|
||||
(object["attachment"] || [])
|
||||
|> Enum.map(fn data ->
|
||||
url = [%{"type" => "Link", "mediaType" => data["mediaType"], "href" => data["url"]}]
|
||||
Map.put(data, "url", url)
|
||||
end)
|
||||
|
||||
object
|
||||
|> Map.put("attachment", attachments)
|
||||
end
|
||||
|
||||
def fix_emoji(object) do
|
||||
tags = (object["tag"] || [])
|
||||
emoji = tags |> Enum.filter(fn (data) -> data["type"] == "Emoji" and data["icon"] end)
|
||||
emoji = emoji |> Enum.reduce(%{}, fn (data, mapping) ->
|
||||
name = data["name"]
|
||||
if String.starts_with?(name, ":") do
|
||||
name = name |> String.slice(1..-2)
|
||||
end
|
||||
tags = object["tag"] || []
|
||||
emoji = tags |> Enum.filter(fn data -> data["type"] == "Emoji" and data["icon"] end)
|
||||
|
||||
mapping |> Map.put(name, data["icon"]["url"])
|
||||
end)
|
||||
emoji =
|
||||
emoji
|
||||
|> Enum.reduce(%{}, fn data, mapping ->
|
||||
name = data["name"]
|
||||
|
||||
if String.starts_with?(name, ":") do
|
||||
name = name |> String.slice(1..-2)
|
||||
end
|
||||
|
||||
mapping |> Map.put(name, data["icon"]["url"])
|
||||
end)
|
||||
|
||||
# we merge mastodon and pleroma emoji into a single mapping, to allow for both wire formats
|
||||
emoji = Map.merge(object["emoji"] || %{}, emoji)
|
||||
|
|
@ -78,9 +87,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
|
||||
def fix_tag(object) do
|
||||
tags = (object["tag"] || [])
|
||||
|> Enum.filter(fn (data) -> data["type"] == "Hashtag" and data["name"] end)
|
||||
|> Enum.map(fn (data) -> String.slice(data["name"], 1..-1) end)
|
||||
tags =
|
||||
(object["tag"] || [])
|
||||
|> Enum.filter(fn data -> data["type"] == "Hashtag" and data["name"] end)
|
||||
|> Enum.map(fn data -> String.slice(data["name"], 1..-1) end)
|
||||
|
||||
combined = (object["tag"] || []) ++ tags
|
||||
|
||||
|
|
@ -103,13 +113,13 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
context: object["conversation"],
|
||||
local: false,
|
||||
published: data["published"],
|
||||
additional: Map.take(data, [
|
||||
"cc",
|
||||
"id"
|
||||
])
|
||||
additional:
|
||||
Map.take(data, [
|
||||
"cc",
|
||||
"id"
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
ActivityPub.create(params)
|
||||
else
|
||||
%Activity{} = activity -> {:ok, activity}
|
||||
|
|
@ -117,11 +127,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
end
|
||||
|
||||
def handle_incoming(%{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = data) do
|
||||
def handle_incoming(
|
||||
%{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = data
|
||||
) do
|
||||
with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
|
||||
%User{} = follower <- User.get_or_fetch_by_ap_id(follower),
|
||||
{:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do
|
||||
ActivityPub.accept(%{to: [follower.ap_id], actor: followed.ap_id, object: data, local: true})
|
||||
|
||||
User.follow(follower, followed)
|
||||
{:ok, activity}
|
||||
else
|
||||
|
|
@ -129,7 +142,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
end
|
||||
|
||||
def handle_incoming(%{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = data) do
|
||||
def handle_incoming(
|
||||
%{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = data
|
||||
) do
|
||||
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
||||
{:ok, object} <- get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
|
||||
{:ok, activity, object} <- ActivityPub.like(actor, object, id, false) do
|
||||
|
|
@ -139,7 +154,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
end
|
||||
|
||||
def handle_incoming(%{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data) do
|
||||
def handle_incoming(
|
||||
%{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data
|
||||
) do
|
||||
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
||||
{:ok, object} <- get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
|
||||
{:ok, activity, object} <- ActivityPub.announce(actor, object, id, false) do
|
||||
|
|
@ -149,20 +166,31 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
end
|
||||
|
||||
def handle_incoming(%{"type" => "Update", "object" => %{"type" => "Person"} = object, "actor" => actor_id} = data) do
|
||||
def handle_incoming(
|
||||
%{"type" => "Update", "object" => %{"type" => "Person"} = object, "actor" => actor_id} =
|
||||
data
|
||||
) do
|
||||
with %User{ap_id: ^actor_id} = actor <- User.get_by_ap_id(object["id"]) do
|
||||
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
|
||||
|
||||
banner = new_user_data[:info]["banner"]
|
||||
update_data = new_user_data
|
||||
|> Map.take([:name, :bio, :avatar])
|
||||
|> Map.put(:info, Map.merge(actor.info, %{"banner" => banner}))
|
||||
|
||||
update_data =
|
||||
new_user_data
|
||||
|> Map.take([:name, :bio, :avatar])
|
||||
|> Map.put(:info, Map.merge(actor.info, %{"banner" => banner}))
|
||||
|
||||
actor
|
||||
|> User.upgrade_changeset(update_data)
|
||||
|> User.update_and_set_cache()
|
||||
|
||||
ActivityPub.update(%{local: false, to: data["to"] || [], cc: data["cc"] || [], object: object, actor: actor_id})
|
||||
ActivityPub.update(%{
|
||||
local: false,
|
||||
to: data["to"] || [],
|
||||
cc: data["cc"] || [],
|
||||
object: object,
|
||||
actor: actor_id
|
||||
})
|
||||
else
|
||||
e ->
|
||||
Logger.error(e)
|
||||
|
|
@ -171,11 +199,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
|
||||
# TODO: Make secure.
|
||||
def handle_incoming(%{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => id} = data) do
|
||||
object_id = case object_id do
|
||||
%{"id" => id} -> id
|
||||
id -> id
|
||||
end
|
||||
def handle_incoming(
|
||||
%{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => id} = data
|
||||
) do
|
||||
object_id =
|
||||
case object_id do
|
||||
%{"id" => id} -> id
|
||||
id -> id
|
||||
end
|
||||
|
||||
with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
|
||||
{:ok, object} <- get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
|
||||
{:ok, activity} <- ActivityPub.delete(object, false) do
|
||||
|
|
@ -203,6 +235,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
_e -> object
|
||||
end
|
||||
end
|
||||
|
||||
def set_reply_to_uri(obj), do: obj
|
||||
|
||||
# Prepares the object of an outgoing create activity.
|
||||
|
|
@ -222,20 +255,25 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
"""
|
||||
internal -> Mastodon
|
||||
"""
|
||||
|
||||
def prepare_outgoing(%{"type" => "Create", "object" => %{"type" => "Note"} = object} = data) do
|
||||
object = object
|
||||
|> prepare_object
|
||||
data = data
|
||||
|> Map.put("object", object)
|
||||
|> Map.put("@context", "https://www.w3.org/ns/activitystreams")
|
||||
object =
|
||||
object
|
||||
|> prepare_object
|
||||
|
||||
data =
|
||||
data
|
||||
|> Map.put("object", object)
|
||||
|> Map.put("@context", "https://www.w3.org/ns/activitystreams")
|
||||
|
||||
{:ok, data}
|
||||
end
|
||||
|
||||
def prepare_outgoing(%{"type" => type} = data) do
|
||||
data = data
|
||||
|> maybe_fix_object_url
|
||||
|> Map.put("@context", "https://www.w3.org/ns/activitystreams")
|
||||
data =
|
||||
data
|
||||
|> maybe_fix_object_url
|
||||
|> Map.put("@context", "https://www.w3.org/ns/activitystreams")
|
||||
|
||||
{:ok, data}
|
||||
end
|
||||
|
|
@ -245,11 +283,13 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
case ActivityPub.fetch_object_from_id(data["object"]) do
|
||||
{:ok, relative_object} ->
|
||||
if relative_object.data["external_url"] do
|
||||
data = data
|
||||
|> Map.put("object", relative_object.data["external_url"])
|
||||
data =
|
||||
data
|
||||
|> Map.put("object", relative_object.data["external_url"])
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
e ->
|
||||
Logger.error("Couldn't fetch #{data["object"]} #{inspect(e)}")
|
||||
data
|
||||
|
|
@ -260,8 +300,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
|
||||
def add_hashtags(object) do
|
||||
tags = (object["tag"] || [])
|
||||
|> Enum.map fn (tag) -> %{"href" => Pleroma.Web.Endpoint.url() <> "/tags/#{tag}", "name" => "##{tag}", "type" => "Hashtag"} end
|
||||
tags =
|
||||
(object["tag"] || [])
|
||||
|> Enum.map(fn tag ->
|
||||
%{
|
||||
"href" => Pleroma.Web.Endpoint.url() <> "/tags/#{tag}",
|
||||
"name" => "##{tag}",
|
||||
"type" => "Hashtag"
|
||||
}
|
||||
end)
|
||||
|
||||
object
|
||||
|> Map.put("tag", tags)
|
||||
|
|
@ -269,10 +316,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
def add_mention_tags(object) do
|
||||
recipients = object["to"] ++ (object["cc"] || [])
|
||||
mentions = recipients
|
||||
|> Enum.map(fn (ap_id) -> User.get_cached_by_ap_id(ap_id) end)
|
||||
|> Enum.filter(&(&1))
|
||||
|> Enum.map(fn(user) -> %{"type" => "Mention", "href" => user.ap_id, "name" => "@#{user.nickname}"} end)
|
||||
|
||||
mentions =
|
||||
recipients
|
||||
|> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end)
|
||||
|> Enum.filter(& &1)
|
||||
|> Enum.map(fn user ->
|
||||
%{"type" => "Mention", "href" => user.ap_id, "name" => "@#{user.nickname}"}
|
||||
end)
|
||||
|
||||
tags = object["tag"] || []
|
||||
|
||||
|
|
@ -284,13 +335,18 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
def add_emoji_tags(object) do
|
||||
tags = object["tag"] || []
|
||||
emoji = object["emoji"] || []
|
||||
out = emoji |> Enum.map(fn {name, url} ->
|
||||
%{"icon" => %{"url" => url, "type" => "Image"},
|
||||
"name" => ":" <> name <> ":",
|
||||
"type" => "Emoji",
|
||||
"updated" => "1970-01-01T00:00:00Z",
|
||||
"id" => url}
|
||||
end)
|
||||
|
||||
out =
|
||||
emoji
|
||||
|> Enum.map(fn {name, url} ->
|
||||
%{
|
||||
"icon" => %{"url" => url, "type" => "Image"},
|
||||
"name" => ":" <> name <> ":",
|
||||
"type" => "Emoji",
|
||||
"updated" => "1970-01-01T00:00:00Z",
|
||||
"id" => url
|
||||
}
|
||||
end)
|
||||
|
||||
object
|
||||
|> Map.put("tag", tags ++ out)
|
||||
|
|
@ -313,11 +369,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
|
||||
def prepare_attachments(object) do
|
||||
attachments = (object["attachment"] || [])
|
||||
|> Enum.map(fn (data) ->
|
||||
[%{"mediaType" => media_type, "href" => href} | _] = data["url"]
|
||||
%{"url" => href, "mediaType" => media_type, "name" => data["name"], "type" => "Document"}
|
||||
end)
|
||||
attachments =
|
||||
(object["attachment"] || [])
|
||||
|> Enum.map(fn data ->
|
||||
[%{"mediaType" => media_type, "href" => href} | _] = data["url"]
|
||||
%{"url" => href, "mediaType" => media_type, "name" => data["name"], "type" => "Document"}
|
||||
end)
|
||||
|
||||
object
|
||||
|> Map.put("attachment", attachments)
|
||||
|
|
@ -325,9 +382,24 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
defp user_upgrade_task(user) do
|
||||
old_follower_address = User.ap_followers(user)
|
||||
q = from u in User,
|
||||
where: ^old_follower_address in u.following,
|
||||
update: [set: [following: fragment("array_replace(?,?,?)", u.following, ^old_follower_address, ^user.follower_address)]]
|
||||
|
||||
q =
|
||||
from(
|
||||
u in User,
|
||||
where: ^old_follower_address in u.following,
|
||||
update: [
|
||||
set: [
|
||||
following:
|
||||
fragment(
|
||||
"array_replace(?,?,?)",
|
||||
u.following,
|
||||
^old_follower_address,
|
||||
^user.follower_address
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
Repo.update_all(q, [])
|
||||
|
||||
maybe_retire_websub(user.ap_id)
|
||||
|
|
@ -335,22 +407,40 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
# Only do this for recent activties, don't go through the whole db.
|
||||
# Only look at the last 1000 activities.
|
||||
since = (Repo.aggregate(Activity, :max, :id) || 0) - 1_000
|
||||
q = from a in Activity,
|
||||
where: ^old_follower_address in a.recipients,
|
||||
where: a.id > ^since,
|
||||
update: [set: [recipients: fragment("array_replace(?,?,?)", a.recipients, ^old_follower_address, ^user.follower_address)]]
|
||||
|
||||
q =
|
||||
from(
|
||||
a in Activity,
|
||||
where: ^old_follower_address in a.recipients,
|
||||
where: a.id > ^since,
|
||||
update: [
|
||||
set: [
|
||||
recipients:
|
||||
fragment(
|
||||
"array_replace(?,?,?)",
|
||||
a.recipients,
|
||||
^old_follower_address,
|
||||
^user.follower_address
|
||||
)
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
Repo.update_all(q, [])
|
||||
end
|
||||
|
||||
def upgrade_user_from_ap_id(ap_id, async \\ true) do
|
||||
with %User{local: false} = user <- User.get_by_ap_id(ap_id),
|
||||
{:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id) do
|
||||
data = data
|
||||
|> Map.put(:info, Map.merge(user.info, data[:info]))
|
||||
data =
|
||||
data
|
||||
|> Map.put(:info, Map.merge(user.info, data[:info]))
|
||||
|
||||
already_ap = User.ap_enabled?(user)
|
||||
{:ok, user} = User.upgrade_changeset(user, data)
|
||||
|> Repo.update()
|
||||
|
||||
{:ok, user} =
|
||||
User.upgrade_changeset(user, data)
|
||||
|> Repo.update()
|
||||
|
||||
if !already_ap do
|
||||
# This could potentially take a long time, do it in the background
|
||||
|
|
@ -371,9 +461,13 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
def maybe_retire_websub(ap_id) do
|
||||
# some sanity checks
|
||||
if is_binary(ap_id) && (String.length(ap_id) > 8) do
|
||||
q = from ws in Pleroma.Web.Websub.WebsubClientSubscription,
|
||||
where: fragment("? like ?", ws.topic, ^"#{ap_id}%")
|
||||
if is_binary(ap_id) && String.length(ap_id) > 8 do
|
||||
q =
|
||||
from(
|
||||
ws in Pleroma.Web.Websub.WebsubClientSubscription,
|
||||
where: fragment("? like ?", ws.topic, ^"#{ap_id}%")
|
||||
)
|
||||
|
||||
Repo.delete_all(q)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
end
|
||||
|
||||
def make_date do
|
||||
DateTime.utc_now() |> DateTime.to_iso8601
|
||||
DateTime.utc_now() |> DateTime.to_iso8601()
|
||||
end
|
||||
|
||||
def generate_activity_id do
|
||||
|
|
@ -38,25 +38,28 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
end
|
||||
|
||||
def generate_object_id do
|
||||
Helpers.o_status_url(Endpoint, :object, UUID.generate)
|
||||
Helpers.o_status_url(Endpoint, :object, UUID.generate())
|
||||
end
|
||||
|
||||
def generate_id(type) do
|
||||
"#{Web.base_url()}/#{type}/#{UUID.generate}"
|
||||
"#{Web.base_url()}/#{type}/#{UUID.generate()}"
|
||||
end
|
||||
|
||||
@doc """
|
||||
Enqueues an activity for federation if it's local
|
||||
"""
|
||||
def maybe_federate(%Activity{local: true} = activity) do
|
||||
priority = case activity.data["type"] do
|
||||
"Delete" -> 10
|
||||
"Create" -> 1
|
||||
_ -> 5
|
||||
end
|
||||
priority =
|
||||
case activity.data["type"] do
|
||||
"Delete" -> 10
|
||||
"Create" -> 1
|
||||
_ -> 5
|
||||
end
|
||||
|
||||
Pleroma.Web.Federator.enqueue(:publish, activity, priority)
|
||||
:ok
|
||||
end
|
||||
|
||||
def maybe_federate(_), do: :ok
|
||||
|
||||
@doc """
|
||||
|
|
@ -64,9 +67,10 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
also adds it to an included object
|
||||
"""
|
||||
def lazy_put_activity_defaults(map) do
|
||||
map = map
|
||||
|> Map.put_new_lazy("id", &generate_activity_id/0)
|
||||
|> Map.put_new_lazy("published", &make_date/0)
|
||||
map =
|
||||
map
|
||||
|> Map.put_new_lazy("id", &generate_activity_id/0)
|
||||
|> Map.put_new_lazy("published", &make_date/0)
|
||||
|
||||
if is_map(map["object"]) do
|
||||
object = lazy_put_object_defaults(map["object"])
|
||||
|
|
@ -88,11 +92,13 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
@doc """
|
||||
Inserts a full object if it is contained in an activity.
|
||||
"""
|
||||
def insert_full_object(%{"object" => %{"type" => type} = object_data}) when is_map(object_data) and type in ["Note"] do
|
||||
def insert_full_object(%{"object" => %{"type" => type} = object_data})
|
||||
when is_map(object_data) and type in ["Note"] do
|
||||
with {:ok, _} <- Object.create(object_data) do
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def insert_full_object(_), do: :ok
|
||||
|
||||
def update_object_in_activities(%{data: %{"id" => id}} = object) do
|
||||
|
|
@ -101,7 +107,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
# Alternatively, just don't do this and fetch the current object each time. Most
|
||||
# could probably be taken from cache.
|
||||
relevant_activities = Activity.all_by_object_ap_id(id)
|
||||
Enum.map(relevant_activities, fn (activity) ->
|
||||
|
||||
Enum.map(relevant_activities, fn activity ->
|
||||
new_activity_data = activity.data |> Map.put("object", object.data)
|
||||
changeset = Changeset.change(activity, data: new_activity_data)
|
||||
Repo.update(changeset)
|
||||
|
|
@ -114,11 +121,20 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
Returns an existing like if a user already liked an object
|
||||
"""
|
||||
def get_existing_like(actor, %{data: %{"id" => id}}) do
|
||||
query = from activity in Activity,
|
||||
where: fragment("(?)->>'actor' = ?", activity.data, ^actor),
|
||||
# this is to use the index
|
||||
where: fragment("coalesce((?)->'object'->>'id', (?)->>'object') = ?", activity.data, activity.data, ^id),
|
||||
where: fragment("(?)->>'type' = 'Like'", activity.data)
|
||||
query =
|
||||
from(
|
||||
activity in Activity,
|
||||
where: fragment("(?)->>'actor' = ?", activity.data, ^actor),
|
||||
# this is to use the index
|
||||
where:
|
||||
fragment(
|
||||
"coalesce((?)->'object'->>'id', (?)->>'object') = ?",
|
||||
activity.data,
|
||||
activity.data,
|
||||
^id
|
||||
),
|
||||
where: fragment("(?)->>'type' = 'Like'", activity.data)
|
||||
)
|
||||
|
||||
Repo.one(query)
|
||||
end
|
||||
|
|
@ -137,10 +153,12 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
end
|
||||
|
||||
def update_element_in_object(property, element, object) do
|
||||
with new_data <- object.data |> Map.put("#{property}_count", length(element)) |> Map.put("#{property}s", element),
|
||||
with new_data <-
|
||||
object.data |> Map.put("#{property}_count", length(element))
|
||||
|> Map.put("#{property}s", element),
|
||||
changeset <- Changeset.change(object, data: new_data),
|
||||
{:ok, object} <- Repo.update(changeset),
|
||||
_ <- update_object_in_activities(object) do
|
||||
_ <- update_object_in_activities(object) do
|
||||
{:ok, object}
|
||||
end
|
||||
end
|
||||
|
|
@ -150,7 +168,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
end
|
||||
|
||||
def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do
|
||||
with likes <- [actor | (object.data["likes"] || [])] |> Enum.uniq do
|
||||
with likes <- [actor | object.data["likes"] || []] |> Enum.uniq() do
|
||||
update_likes_in_object(likes, object)
|
||||
end
|
||||
end
|
||||
|
|
@ -178,13 +196,20 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
if activity_id, do: Map.put(data, "id", activity_id), else: data
|
||||
end
|
||||
|
||||
def fetch_latest_follow(%User{ap_id: follower_id},
|
||||
%User{ap_id: followed_id}) do
|
||||
query = from activity in Activity,
|
||||
where: fragment("? @> ?", activity.data, ^%{type: "Follow", actor: follower_id,
|
||||
object: followed_id}),
|
||||
order_by: [desc: :id],
|
||||
limit: 1
|
||||
def fetch_latest_follow(%User{ap_id: follower_id}, %User{ap_id: followed_id}) do
|
||||
query =
|
||||
from(
|
||||
activity in Activity,
|
||||
where:
|
||||
fragment(
|
||||
"? @> ?",
|
||||
activity.data,
|
||||
^%{type: "Follow", actor: follower_id, object: followed_id}
|
||||
),
|
||||
order_by: [desc: :id],
|
||||
limit: 1
|
||||
)
|
||||
|
||||
Repo.one(query)
|
||||
end
|
||||
|
||||
|
|
@ -193,7 +218,11 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
@doc """
|
||||
Make announce activity data for the given actor and object
|
||||
"""
|
||||
def make_announce_data(%User{ap_id: ap_id} = user, %Object{data: %{"id" => id}} = object, activity_id) do
|
||||
def make_announce_data(
|
||||
%User{ap_id: ap_id} = user,
|
||||
%Object{data: %{"id" => id}} = object,
|
||||
activity_id
|
||||
) do
|
||||
data = %{
|
||||
"type" => "Announce",
|
||||
"actor" => ap_id,
|
||||
|
|
@ -207,7 +236,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
end
|
||||
|
||||
def add_announce_to_object(%Activity{data: %{"actor" => actor}}, object) do
|
||||
with announcements <- [actor | (object.data["announcements"] || [])] |> Enum.uniq do
|
||||
with announcements <- [actor | object.data["announcements"] || []] |> Enum.uniq() do
|
||||
update_element_in_object("announcement", announcements, object)
|
||||
end
|
||||
end
|
||||
|
|
@ -223,14 +252,14 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
}
|
||||
end
|
||||
|
||||
|
||||
#### Create-related helpers
|
||||
|
||||
def make_create_data(params, additional) do
|
||||
published = params.published || make_date()
|
||||
|
||||
%{
|
||||
"type" => "Create",
|
||||
"to" => params.to |> Enum.uniq,
|
||||
"to" => params.to |> Enum.uniq(),
|
||||
"actor" => params.actor.ap_id,
|
||||
"object" => params.object,
|
||||
"published" => published,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
{:ok, _, public_key} = Salmon.keys_from_pem(user.info["keys"])
|
||||
public_key = :public_key.pem_entry_encode(:RSAPublicKey, public_key)
|
||||
public_key = :public_key.pem_encode([public_key])
|
||||
|
||||
%{
|
||||
"id" => user.ap_id,
|
||||
"type" => "Person",
|
||||
|
|
@ -30,7 +31,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"publicKeyPem" => public_key
|
||||
},
|
||||
"endpoints" => %{
|
||||
"sharedInbox" => "#{Pleroma.Web.Endpoint.url}/inbox"
|
||||
"sharedInbox" => "#{Pleroma.Web.Endpoint.url()}/inbox"
|
||||
},
|
||||
"icon" => %{
|
||||
"type" => "Image",
|
||||
|
|
@ -47,7 +48,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
def collection(collection, iri, page) do
|
||||
offset = (page - 1) * 10
|
||||
items = Enum.slice(collection, offset, 10)
|
||||
items = Enum.map(items, fn (user) -> user.ap_id end)
|
||||
items = Enum.map(items, fn user -> user.ap_id end)
|
||||
|
||||
map = %{
|
||||
"id" => "#{iri}?page=#{page}",
|
||||
"type" => "OrderedCollectionPage",
|
||||
|
|
@ -55,19 +57,22 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"totalItems" => length(collection),
|
||||
"orderedItems" => items
|
||||
}
|
||||
|
||||
if offset < length(collection) do
|
||||
Map.put(map, "next", "#{iri}?page=#{page+1}")
|
||||
Map.put(map, "next", "#{iri}?page=#{page + 1}")
|
||||
end
|
||||
end
|
||||
|
||||
def render("following.json", %{user: user, page: page}) do
|
||||
{:ok, following} = User.get_friends(user)
|
||||
|
||||
collection(following, "#{user.ap_id}/following", page)
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
def render("following.json", %{user: user}) do
|
||||
{:ok, following} = User.get_friends(user)
|
||||
|
||||
%{
|
||||
"id" => "#{user.ap_id}/following",
|
||||
"type" => "OrderedCollection",
|
||||
|
|
@ -79,12 +84,14 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
|
||||
def render("followers.json", %{user: user, page: page}) do
|
||||
{:ok, followers} = User.get_followers(user)
|
||||
|
||||
collection(followers, "#{user.ap_id}/followers", page)
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
def render("followers.json", %{user: user}) do
|
||||
{:ok, followers} = User.get_followers(user)
|
||||
|
||||
%{
|
||||
"id" => "#{user.ap_id}/followers",
|
||||
"type" => "OrderedCollection",
|
||||
|
|
@ -115,19 +122,21 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
activities = Enum.reverse(activities)
|
||||
max_id = Enum.at(activities, 0).id
|
||||
|
||||
collection = Enum.map(activities, fn (act) ->
|
||||
{:ok, data} = Transmogrifier.prepare_outgoing(act.data)
|
||||
data
|
||||
end)
|
||||
collection =
|
||||
Enum.map(activities, fn act ->
|
||||
{:ok, data} = Transmogrifier.prepare_outgoing(act.data)
|
||||
data
|
||||
end)
|
||||
|
||||
iri = "#{user.ap_id}/outbox"
|
||||
|
||||
page = %{
|
||||
"id" => "#{iri}?max_id=#{max_id}",
|
||||
"type" => "OrderedCollectionPage",
|
||||
"partOf" => iri,
|
||||
"totalItems" => info.note_count,
|
||||
"orderedItems" => collection,
|
||||
"next" => "#{iri}?max_id=#{min_id-1}",
|
||||
"next" => "#{iri}?max_id=#{min_id - 1}"
|
||||
}
|
||||
|
||||
if max_qid == nil do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue