feat: Support unfollowing
This commit is contained in:
parent
dc7c855095
commit
e89cc78274
8 changed files with 97 additions and 9 deletions
|
|
@ -73,7 +73,7 @@
|
|||
## Protocol Support
|
||||
|
||||
- [x] Check that signature header (digest) matches digest of body contents
|
||||
- [ ] Check the domain of the public key against the domain of the object being CRUDed
|
||||
- [x] Check the domain of the public key against the domain of the object being CRUDed
|
||||
|
||||
## Testing
|
||||
|
||||
|
|
|
|||
|
|
@ -38,9 +38,12 @@ defmodule ActivityPub do
|
|||
|> Req.Request.put_header("accept", "application/json")
|
||||
|
||||
case Req.get(request) do
|
||||
{:ok, result} ->
|
||||
{:ok, %{status: 200} = result} ->
|
||||
{:ok, result.body}
|
||||
|
||||
{:ok, %{status: 404}} ->
|
||||
nil
|
||||
|
||||
error ->
|
||||
error
|
||||
end
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ defmodule ActivityPub.Headers do
|
|||
{:ok, public_key} ->
|
||||
:public_key.verify(to_verify, :sha256, signature, public_key)
|
||||
|
||||
nil ->
|
||||
false
|
||||
|
||||
error ->
|
||||
error
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,9 +6,13 @@ defmodule Postland.Actors do
|
|||
def actor(actor_id) do
|
||||
result =
|
||||
Cachex.fetch(:main_cache, "actor:#{actor_id}", fn _key ->
|
||||
{:ok, actor} = ActivityPub.fetch_actor(actor_id)
|
||||
case ActivityPub.fetch_actor(actor_id) do
|
||||
{:ok, actor} ->
|
||||
{:commit, actor, expire: :timer.seconds(300)}
|
||||
|
||||
{:commit, actor, expire: :timer.seconds(300)}
|
||||
nil ->
|
||||
{:commit, nil, expire: :timer.seconds(300)}
|
||||
end
|
||||
end)
|
||||
|
||||
case result do
|
||||
|
|
|
|||
|
|
@ -52,14 +52,30 @@ defmodule Postland.Follows do
|
|||
def record_and_send_withdrawl(request) do
|
||||
Multi.new()
|
||||
|> Multi.delete(:delete, request)
|
||||
|> Multi.run(:send_acceptance, fn _data, _repo ->
|
||||
|> Multi.run(:send_withdrawl, fn _data, _repo ->
|
||||
send_withdrawl(request)
|
||||
end)
|
||||
|> Repo.transaction()
|
||||
end
|
||||
|
||||
def record_and_unfollow(follow) do
|
||||
Multi.new()
|
||||
|> Multi.delete(:delete, follow)
|
||||
|> Multi.run(:send_delete_follow, fn _data, _repo ->
|
||||
send_delete_follow(follow)
|
||||
end)
|
||||
|> Repo.transaction()
|
||||
end
|
||||
|
||||
def send_withdrawl(request) do
|
||||
{:ok, actor} = ActivityPub.fetch_actor(request.followee)
|
||||
request.followee
|
||||
|> ActivityPub.fetch_actor()
|
||||
|> do_send_withdrawl(request)
|
||||
end
|
||||
|
||||
defp do_send_withdrawl(nil, _), do: {:ok, nil}
|
||||
|
||||
defp do_send_withdrawl({:ok, actor}, request) do
|
||||
inbox = Map.get(actor, "inbox")
|
||||
|
||||
body =
|
||||
|
|
@ -84,7 +100,14 @@ defmodule Postland.Follows do
|
|||
end
|
||||
|
||||
def send_acceptance(request) do
|
||||
{:ok, actor} = ActivityPub.fetch_actor(request.follower)
|
||||
request.follower
|
||||
|> ActivityPub.fetch_actor()
|
||||
|> do_send_acceptance(request)
|
||||
end
|
||||
|
||||
defp do_send_acceptance(nil, _), do: {:ok, nil}
|
||||
|
||||
defp do_send_acceptance({:ok, actor}, request) do
|
||||
inbox = Map.get(actor, "inbox")
|
||||
|
||||
case get_follow_activity(request.follower) do
|
||||
|
|
@ -180,6 +203,34 @@ defmodule Postland.Follows do
|
|||
Req.post(inbox, headers: headers, body: follow_request)
|
||||
end
|
||||
|
||||
def send_delete_follow(follow) do
|
||||
encoded_followee = Base.url_encode64(follow.followee, padding: false)
|
||||
encoded_follower = Base.url_encode64(follow.follower, padding: false)
|
||||
|
||||
{:ok, actor} = ActivityPub.fetch_actor(follow.followee)
|
||||
inbox = Map.get(actor, "inbox")
|
||||
|
||||
follow_request =
|
||||
%{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"type" => "Delete",
|
||||
"actor" => Postland.my_actor_id(),
|
||||
"object" => url(~p"/follows/#{encoded_followee}/#{encoded_follower}")
|
||||
}
|
||||
|> 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()
|
||||
|
|
|
|||
|
|
@ -60,6 +60,14 @@ defmodule PostlandWeb.CoreComponents do
|
|||
>
|
||||
Withdraw Request
|
||||
</.button>
|
||||
<.button
|
||||
:if={@status == :following_confirmed}
|
||||
phx-click="unfollow"
|
||||
phx-value-dom-id={@dom_id}
|
||||
phx-value-id={@account["id"]}
|
||||
>
|
||||
Unfollow
|
||||
</.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -177,7 +185,7 @@ defmodule PostlandWeb.CoreComponents do
|
|||
end
|
||||
|
||||
def post_card(assigns) do
|
||||
author = Postland.Timeline.attribution(assigns.post) || %{}
|
||||
author = Postland.Timeline.attribution(assigns.post)
|
||||
|
||||
%{host: host} =
|
||||
case author do
|
||||
|
|
@ -201,7 +209,7 @@ defmodule PostlandWeb.CoreComponents do
|
|||
|> Map.put(:cw, cw)
|
||||
|
||||
~H"""
|
||||
<div class="flex items-start space-x-4 w-full">
|
||||
<div :if={@author} class="flex items-start space-x-4 w-full">
|
||||
<div class="flex-shrink-0">
|
||||
<img
|
||||
class="inline-block h-16 w-16 rounded-full drop-shadow-lg"
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ defmodule PostlandWeb.FollowersLive do
|
|||
account: Actors.actor(follow.follower)
|
||||
}
|
||||
end)
|
||||
|> Enum.reject(&is_nil(&1.account))
|
||||
|
||||
account_count = Enum.count(followers)
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ defmodule PostlandWeb.FollowingLive do
|
|||
account: Actors.actor(follow.followee)
|
||||
}
|
||||
end)
|
||||
|> Enum.reject(&is_nil(&1.account))
|
||||
|
||||
account_count = Enum.count(follows)
|
||||
|
||||
|
|
@ -60,4 +61,21 @@ defmodule PostlandWeb.FollowingLive do
|
|||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("unfollow", %{"id" => id, "dom-id" => dom_id}, socket) do
|
||||
request = Follows.get(Postland.my_actor_id(), id)
|
||||
|
||||
socket =
|
||||
case Follows.record_and_unfollow(request) do
|
||||
{:ok, _} ->
|
||||
socket
|
||||
|> stream_delete_by_dom_id(:accounts, dom_id)
|
||||
|> assign(:count, socket.assigns.count - 1)
|
||||
|
||||
_ ->
|
||||
put_flash(socket, :error, "An unexpected error occurred.")
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue