From 75421b74460bacbb5a0ebab89b7d0faba656706a Mon Sep 17 00:00:00 2001
From: Ro
Date: Sun, 3 Nov 2024 10:17:42 -0600
Subject: [PATCH] feat: Withdraw follow request
---
README.md | 13 +++-
lib/postland/follow.ex | 10 ++-
lib/postland/follows.ex | 34 ++++++++++
.../components/core_components.ex | 12 +++-
lib/postland_web/live/following_live copy.ex | 25 --------
lib/postland_web/live/following_live.ex | 63 +++++++++++++++++++
6 files changed, 129 insertions(+), 28 deletions(-)
delete mode 100644 lib/postland_web/live/following_live copy.ex
create mode 100644 lib/postland_web/live/following_live.ex
diff --git a/README.md b/README.md
index c157691..50ec6e8 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@
- [x] Sending follow request
- [x] View following list
-- [ ] Withdrawing follow request
+- [x] Withdrawing follow request
- [ ] Unfollowing
- [ ] Proactively check the outbox of newly-accepted follows
@@ -45,12 +45,23 @@
- [ ] Displaying polls
- [ ] Voting in polls
+## Individual Post Page
+
+- [ ] Show post
+- [ ] Show replies to post (chronological order)
+
## DMs
- [ ] Receiving DMs
- [ ] Replying to DMs
- [ ] Sending new DMs
+## Notifications
+
+- [ ] Like notifications
+- [ ] Reply notifications
+- [ ] Boost notifications
+
## Allowlist
- [ ] Manage approved instance list
diff --git a/lib/postland/follow.ex b/lib/postland/follow.ex
index cc5f6bc..78d3498 100644
--- a/lib/postland/follow.ex
+++ b/lib/postland/follow.ex
@@ -1,5 +1,6 @@
defmodule Postland.Follow do
use Ecto.Schema
+ use Phoenix.VerifiedRoutes, endpoint: PostlandWeb.Endpoint, router: PostlandWeb.Router
import Ecto.Changeset
@@ -10,11 +11,18 @@ defmodule Postland.Follow do
field :confirmed_at, :naive_datetime
end
+ def id(follow) do
+ encoded_followee = Base.url_encode64(follow.followee, padding: false)
+ encoded_follower = Base.url_encode64(follow.follower, padding: false)
+
+ url(~p"/follows/#{encoded_followee}/#{encoded_follower}")
+ end
+
def changeset(follower, followee, confirmed \\ false) do
attrs = %{
follower: follower,
followee: followee,
- confirmed_at: (if confirmed, do: NaiveDateTime.utc_now())
+ confirmed_at: if(confirmed, do: NaiveDateTime.utc_now())
}
%__MODULE__{}
diff --git a/lib/postland/follows.ex b/lib/postland/follows.ex
index c02f5bd..d435243 100644
--- a/lib/postland/follows.ex
+++ b/lib/postland/follows.ex
@@ -49,6 +49,40 @@ defmodule Postland.Follows do
|> Repo.transaction()
end
+ def record_and_send_withdrawl(request) do
+ Multi.new()
+ |> Multi.delete(:delete, request)
+ |> Multi.run(:send_acceptance, fn _data, _repo ->
+ send_withdrawl(request)
+ end)
+ |> Repo.transaction()
+ end
+
+ def send_withdrawl(request) do
+ {:ok, actor} = ActivityPub.fetch_actor(request.followee)
+ inbox = Map.get(actor, "inbox")
+
+ body =
+ %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "type" => "Undo",
+ "actor" => Postland.my_actor_id(),
+ "object" => Follow.id(request)
+ }
+ |> 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
+
def send_acceptance(request) do
{:ok, actor} = ActivityPub.fetch_actor(request.follower)
inbox = Map.get(actor, "inbox")
diff --git a/lib/postland_web/components/core_components.ex b/lib/postland_web/components/core_components.ex
index ad43340..7cab861 100644
--- a/lib/postland_web/components/core_components.ex
+++ b/lib/postland_web/components/core_components.ex
@@ -44,12 +44,22 @@ defmodule PostlandWeb.CoreComponents do
@<%= @account["preferredUsername"] %>@<%= @host %>
+
+ Pending follow request.
+
<%= {:safe, Earmark.as_html!(@account["summary"] || "")} %>
- <.button disabled>Pending
+ <.button
+ :if={@status == :following_pending}
+ phx-click="withdraw"
+ phx-value-dom-id={@dom_id}
+ phx-value-id={@account["id"]}
+ >
+ Withdraw Request
+
diff --git a/lib/postland_web/live/following_live copy.ex b/lib/postland_web/live/following_live copy.ex
deleted file mode 100644
index 5dfb173..0000000
--- a/lib/postland_web/live/following_live copy.ex
+++ /dev/null
@@ -1,25 +0,0 @@
-defmodule PostlandWeb.FollowingLive do
- use PostlandWeb, :live_view
-
- alias Postland.Actors
- alias Postland.Follows
-
- def render(assigns) do
- ~H"""
-
-
Following
-
- You aren't following anyone.
-
-
- <.profile_card account={acct} />
-
-
- """
- end
-
- def mount(_params, _session, socket) do
- follows = Follows.all_following() |> Enum.map(fn follow -> Actors.actor(follow.followee) end)
- {:ok, assign(socket, :accounts, follows)}
- end
-end
diff --git a/lib/postland_web/live/following_live.ex b/lib/postland_web/live/following_live.ex
new file mode 100644
index 0000000..f730059
--- /dev/null
+++ b/lib/postland_web/live/following_live.ex
@@ -0,0 +1,63 @@
+defmodule PostlandWeb.FollowingLive do
+ use PostlandWeb, :live_view
+
+ alias Postland.Actors
+ alias Postland.Follows
+
+ def render(assigns) do
+ ~H"""
+
+
Following
+
+ You aren't following anyone.
+
+
+ <.profile_card
+ id={dom_id}
+ account={acct}
+ dom_id={dom_id}
+ status={if confirmed, do: :following_confirmed, else: :following_pending}
+ />
+
+
+ """
+ end
+
+ def mount(_params, _session, socket) do
+ follows =
+ Follows.all_following()
+ |> Enum.map(fn follow ->
+ %{
+ id: follow.followee,
+ confirmed: !!follow.confirmed_at,
+ account: Actors.actor(follow.followee)
+ }
+ end)
+
+ account_count = Enum.count(follows)
+
+ socket =
+ socket
+ |> stream(:accounts, follows)
+ |> assign(:count, account_count)
+
+ {:ok, socket}
+ end
+
+ def handle_event("withdraw", %{"id" => id, "dom-id" => dom_id}, socket) do
+ request = Follows.get(Postland.my_actor_id(), id)
+
+ socket =
+ case Follows.record_and_send_withdrawl(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