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