feat: Withdraw follow request
This commit is contained in:
parent
f27dd6a9a7
commit
75421b7446
6 changed files with 129 additions and 28 deletions
13
README.md
13
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
|
||||
|
|
|
|||
|
|
@ -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__{}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -44,12 +44,22 @@ defmodule PostlandWeb.CoreComponents do
|
|||
@<%= @account["preferredUsername"] %>@<%= @host %>
|
||||
</span>
|
||||
</p>
|
||||
<p :if={@status == :following_pending} class="font-semibold text-violet-600">
|
||||
Pending follow request.
|
||||
</p>
|
||||
<p class="text-gray-500 text-sm">
|
||||
<%= {:safe, Earmark.as_html!(@account["summary"] || "")} %>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex-grow text-right">
|
||||
<.button disabled>Pending</.button>
|
||||
<.button
|
||||
:if={@status == :following_pending}
|
||||
phx-click="withdraw"
|
||||
phx-value-dom-id={@dom_id}
|
||||
phx-value-id={@account["id"]}
|
||||
>
|
||||
Withdraw Request
|
||||
</.button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
defmodule PostlandWeb.FollowingLive do
|
||||
use PostlandWeb, :live_view
|
||||
|
||||
alias Postland.Actors
|
||||
alias Postland.Follows
|
||||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div class="py-4">
|
||||
<h3 class="text-base font-semibold">Following</h3>
|
||||
<p :if={@accounts == []} class="text-gray-400">
|
||||
You aren't following anyone.
|
||||
</p>
|
||||
<div :for={acct <- @accounts} class="mt-2">
|
||||
<.profile_card account={acct} />
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
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
|
||||
63
lib/postland_web/live/following_live.ex
Normal file
63
lib/postland_web/live/following_live.ex
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
defmodule PostlandWeb.FollowingLive do
|
||||
use PostlandWeb, :live_view
|
||||
|
||||
alias Postland.Actors
|
||||
alias Postland.Follows
|
||||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div class="py-4">
|
||||
<h3 class="text-base font-semibold">Following</h3>
|
||||
<p :if={@count == 0} class="text-gray-400">
|
||||
You aren't following anyone.
|
||||
</p>
|
||||
<div :for={{dom_id, %{confirmed: confirmed, account: acct}} <- @streams.accounts} class="mt-2">
|
||||
<.profile_card
|
||||
id={dom_id}
|
||||
account={acct}
|
||||
dom_id={dom_id}
|
||||
status={if confirmed, do: :following_confirmed, else: :following_pending}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
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
|
||||
Loading…
Reference in a new issue