feat: Send follow requests

This commit is contained in:
Ro 2024-10-10 00:01:44 +00:00
parent 1259d3202d
commit 90a158c380
5 changed files with 73 additions and 7 deletions

View file

@ -1,2 +1,15 @@
defmodule ActivityPub do
def fetch_actor(actor_id) do
request =
Req.new(url: actor_id)
|> Req.Request.put_header("accept", "application/json")
case Req.get(request) do
{:ok, result} ->
{:ok, result.body}
error ->
error
end
end
end

View file

@ -85,13 +85,9 @@ defmodule ActivityPub.Headers do
end
def fetch_actor_key(key_id) do
request =
Req.new(url: key_id)
|> Req.Request.put_header("accept", "application/json")
case Req.get(request) do
{:ok, result} ->
key_map = result.body["publicKey"]
case ActivityPub.fetch_actor(key_id) do
{:ok, body} ->
key_map = body["publicKey"]
if key_map["id"] == key_id do
[public_key | _] =

View file

@ -1,8 +1,11 @@
defmodule Postland.Activities do
use Phoenix.VerifiedRoutes, endpoint: PostlandWeb.Endpoint, router: PostlandWeb.Router
require Logger
alias Postland.Activity
alias Postland.Repo
alias Postland.Follows
def process_activity(params) do
case record_activity(params) do
@ -20,6 +23,20 @@ defmodule Postland.Activities do
|> Repo.insert()
end
def cause_effects(%Activity{actor_id: actor_id, type: "Accept", data: %{"object" => %{"type" => "Follow"}}} = activity) do
case Follows.get(Postland.my_actor_id(), actor_id) do
nil ->
Logger.warning("Got accept for a follow we don't have in the db: #{actor_id}")
{:ok, activity}
request ->
Follows.confirm_request(request)
end
{:ok, activity}
end
def cause_effects(%Activity{actor_id: actor_id, type: "Follow", data: %{"object" => object}} = activity) do
if object == Postland.my_actor_id() do
case Postland.Follows.record_inbound_request(actor_id) do

View file

@ -3,6 +3,7 @@ defmodule Postland.Follow do
import Ecto.Changeset
@primary_key false
schema "follows" do
field :follower, :string, primary_key: true
field :followee, :string, primary_key: true

View file

@ -1,8 +1,47 @@
defmodule Postland.Follows do
use Phoenix.VerifiedRoutes, endpoint: PostlandWeb.Endpoint, router: PostlandWeb.Router
import Ecto.Query, warn: false
alias Postland.Accounts
alias Postland.Follow
alias Postland.Repo
alias ActivityPub.Headers
alias Ecto.Multi
def record_and_send_follow_request(to_actor_id) do
Multi.new()
|> Multi.run(:follow_record, fn _data, _repo -> record_outbound_request(to_actor_id) end)
|> Multi.run(:send_request, fn _data, _repo ->
send_follow_request(to_actor_id)
end)
|> Repo.transaction()
end
def send_follow_request(to_actor_id) do
encoded_followee = Base.url_encode64(to_actor_id)
encoded_follower = Base.url_encode64(Postland.my_actor_id())
actor = ActivityPub.fetch_actor(to_actor_id)
inbox = Map.get(actor, "inbox")
follow_request = %{
"@context" => "https://www.w3.org/ns/activitystreams",
"id" => url(~p"/follows/#{encoded_followee}/#{encoded_follower}"),
"type" => "Follow",
"actor" => Postland.my_actor_id(),
"object" => to_actor_id
}
|> Jason.encode!()
headers = Headers.signing_headers("POST", inbox, follow_request, Postland.my_actor_id(), Accounts.solo_user().private_key)
Req.post(inbox, headers: headers, body: follow_request)
end
def get(follower, followee) do
from(f in Follow, where: f.followee == ^followee, where: f.follower == ^follower) |> Repo.one()
end
def pending_inbound_requests() do
my_actor_id = Postland.my_actor_id()