feat: Accept follow requests
This commit is contained in:
parent
4bb55c08a5
commit
7824edbec0
6 changed files with 72 additions and 6 deletions
17
README.md
17
README.md
|
|
@ -1,10 +1,25 @@
|
||||||
# Postland
|
# Postland
|
||||||
|
|
||||||
|
## Backend
|
||||||
|
|
||||||
- [ ] Posting
|
- [ ] Posting
|
||||||
- [ ] Timeline
|
- [ ] Timeline
|
||||||
- [ ] Deleting posts
|
- [ ] Deleting posts
|
||||||
- [x] Following
|
- [x] Following
|
||||||
- [ ] Unfollowing
|
- [ ] Unfollowing
|
||||||
- [ ] Being followed
|
- [x] Being followed
|
||||||
|
- [x] Accepting follows
|
||||||
|
- [ ] Liking
|
||||||
|
- [ ] Unliking
|
||||||
|
|
||||||
|
## UX
|
||||||
|
|
||||||
|
- [ ] Posting
|
||||||
|
- [ ] Timeline
|
||||||
|
- [ ] Deleting posts
|
||||||
|
- [x] Following
|
||||||
|
- [ ] Unfollowing
|
||||||
|
- [x] Being followed
|
||||||
|
- [ ] Accepting follows
|
||||||
- [ ] Liking
|
- [ ] Liking
|
||||||
- [ ] Unliking
|
- [ ] Unliking
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,9 @@ defmodule ActivityPub.Headers do
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify(method, path, headers, actor_fetcher \\ &fetch_actor_key/1) do
|
def verify(method, path, headers, actor_fetcher \\ &fetch_actor_key/1) do
|
||||||
dbg(headers)
|
|
||||||
|
|
||||||
{_key, signature_header} = Enum.find(headers, fn {key, _} -> key == "signature" end)
|
{_key, signature_header} = Enum.find(headers, fn {key, _} -> key == "signature" end)
|
||||||
|
|
||||||
signature_kv = SignatureSplitter.split(signature_header) |> dbg()
|
signature_kv = SignatureSplitter.split(signature_header)
|
||||||
key_id = find_value(signature_kv, "keyId")
|
key_id = find_value(signature_kv, "keyId")
|
||||||
signature = signature_kv |> find_value("signature") |> Base.decode64!()
|
signature = signature_kv |> find_value("signature") |> Base.decode64!()
|
||||||
signing_text_headers = signature_kv |> find_value("headers") |> String.split(" ")
|
signing_text_headers = signature_kv |> find_value("headers") |> String.split(" ")
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ defmodule Postland.Activities do
|
||||||
|
|
||||||
actor_id = case Regex.run(pattern, follow_id) do
|
actor_id = case Regex.run(pattern, follow_id) do
|
||||||
[_, encoded_actor_id] ->
|
[_, encoded_actor_id] ->
|
||||||
dbg(encoded_actor_id)
|
|
||||||
Base.url_decode64!(encoded_actor_id, padding: false)
|
Base.url_decode64!(encoded_actor_id, padding: false)
|
||||||
|
|
||||||
_other ->
|
_other ->
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,15 @@ defmodule Postland.Activity do
|
||||||
|
|
||||||
def changeset(attrs) do
|
def changeset(attrs) do
|
||||||
attrs = %{
|
attrs = %{
|
||||||
|
"id" => Map.get(attrs, "id", Ecto.UUID.autogenerate()),
|
||||||
"actor_id" => Map.get(attrs, "actor"),
|
"actor_id" => Map.get(attrs, "actor"),
|
||||||
"type" => Map.get(attrs, "type"),
|
"type" => Map.get(attrs, "type"),
|
||||||
"data" => attrs
|
"data" => attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
%__MODULE__{}
|
%__MODULE__{}
|
||||||
|> cast(attrs, [:actor_id, :type, :data])
|
|> cast(attrs, [:id, :actor_id, :type, :data])
|
||||||
|
|> validate_required(:id)
|
||||||
|> validate_required(:data)
|
|> validate_required(:data)
|
||||||
|> validate_required(:type)
|
|> validate_required(:type)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,55 @@ defmodule Postland.Follows do
|
||||||
import Ecto.Query, warn: false
|
import Ecto.Query, warn: false
|
||||||
|
|
||||||
alias Postland.Accounts
|
alias Postland.Accounts
|
||||||
|
alias Postland.Activity
|
||||||
alias Postland.Follow
|
alias Postland.Follow
|
||||||
alias Postland.Repo
|
alias Postland.Repo
|
||||||
alias ActivityPub.Headers
|
alias ActivityPub.Headers
|
||||||
|
|
||||||
alias Ecto.Multi
|
alias Ecto.Multi
|
||||||
|
|
||||||
|
def record_and_send_acceptance(request) do
|
||||||
|
Multi.new()
|
||||||
|
|> Multi.run(:confirm_timestamp, fn _data, _repo -> confirm_request(request) end)
|
||||||
|
|> Multi.run(:send_acceptance, fn _data, _repo ->
|
||||||
|
send_acceptance(request)
|
||||||
|
end)
|
||||||
|
|> Repo.transaction()
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_acceptance(request) do
|
||||||
|
{:ok, actor} = ActivityPub.fetch_actor(request.follower)
|
||||||
|
inbox = Map.get(actor, "inbox")
|
||||||
|
|
||||||
|
case get_follow_activity(request.follower) do
|
||||||
|
nil ->
|
||||||
|
{:error, "could not find Follow activity to Accept"}
|
||||||
|
|
||||||
|
follow_activity ->
|
||||||
|
body =
|
||||||
|
%{
|
||||||
|
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type" => "Accept",
|
||||||
|
"actor" => Postland.my_actor_id(),
|
||||||
|
"object" => %{
|
||||||
|
"actor" => request.follower,
|
||||||
|
"id" => Map.get(follow_activity.data, "id"),
|
||||||
|
"object" => Postland.my_actor_id(),
|
||||||
|
"type" => "Follow"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> Jason.encode!()
|
||||||
|
|
||||||
|
headers = Headers.signing_headers("POST", inbox, body, Postland.my_actor_id(), Accounts.solo_user().private_key)
|
||||||
|
|
||||||
|
Req.post(inbox, headers: headers, body: body)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_follow_activity(follower) do
|
||||||
|
from(a in Activity, where: a.type == "Follow", where: a.actor_id == ^follower, limit: 1, order_by: [desc: :inserted_at]) |> Repo.one()
|
||||||
|
end
|
||||||
|
|
||||||
def record_and_send_follow_request(to_actor_id) do
|
def record_and_send_follow_request(to_actor_id) do
|
||||||
Multi.new()
|
Multi.new()
|
||||||
|> Multi.run(:follow_record, fn _data, _repo -> record_outbound_request(to_actor_id) end)
|
|> Multi.run(:follow_record, fn _data, _repo -> record_outbound_request(to_actor_id) end)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
defmodule Postland.Repo.Migrations.AddTimestampsToActivities do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
alter table("activities") do
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue