feat: Reject requests
This commit is contained in:
parent
ac462cfe14
commit
90a243845e
8 changed files with 175 additions and 48 deletions
|
|
@ -18,34 +18,53 @@ defmodule ActivityPub do
|
|||
end
|
||||
|
||||
def post_activity(sender_id, private_key, inbox, activity) do
|
||||
body = Jason.encode!(activity)
|
||||
if String.contains?(inbox, "example.com") do
|
||||
{:ok, %{status: 200, body: "ok"}}
|
||||
else
|
||||
body = Jason.encode!(activity)
|
||||
|
||||
headers =
|
||||
Headers.signing_headers(
|
||||
"POST",
|
||||
inbox,
|
||||
body,
|
||||
sender_id,
|
||||
private_key
|
||||
)
|
||||
headers =
|
||||
Headers.signing_headers(
|
||||
"POST",
|
||||
inbox,
|
||||
body,
|
||||
sender_id,
|
||||
private_key
|
||||
)
|
||||
|
||||
Req.post(inbox, headers: headers, body: body)
|
||||
Req.post(inbox, headers: headers, body: body)
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_actor(actor_id) do
|
||||
request =
|
||||
Req.new(url: actor_id)
|
||||
|> Req.Request.put_header("accept", "application/json")
|
||||
if String.contains?(actor_id, "example.com") do
|
||||
{:ok,
|
||||
%{
|
||||
"@context" => [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1"
|
||||
],
|
||||
"id" => actor_id,
|
||||
"type" => "Person",
|
||||
"preferredUsername" => "example",
|
||||
"name" => "Example User",
|
||||
"inbox" => "#{actor_id}/inbox"
|
||||
}}
|
||||
else
|
||||
request =
|
||||
Req.new(url: actor_id)
|
||||
|> Req.Request.put_header("accept", "application/json")
|
||||
|
||||
case Req.get(request) do
|
||||
{:ok, %{status: 200} = result} ->
|
||||
{:ok, result.body}
|
||||
case Req.get(request) do
|
||||
{:ok, %{status: 200} = result} ->
|
||||
{:ok, result.body}
|
||||
|
||||
{:ok, %{status: 404}} ->
|
||||
nil
|
||||
{:ok, %{status: 404}} ->
|
||||
nil
|
||||
|
||||
error ->
|
||||
error
|
||||
error ->
|
||||
error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ defmodule Postland.Activities do
|
|||
def record_activity(params) do
|
||||
params
|
||||
|> Activity.changeset()
|
||||
|> Repo.insert()
|
||||
|> Repo.insert(on_conflict: :replace_all, conflict_target: :id)
|
||||
end
|
||||
|
||||
# TODO: add effects for CRUD notes
|
||||
|
|
|
|||
|
|
@ -67,6 +67,15 @@ defmodule Postland.Follows do
|
|||
|> Repo.transaction()
|
||||
end
|
||||
|
||||
def record_and_reject(follow) do
|
||||
Multi.new()
|
||||
|> Multi.delete(:delete, follow)
|
||||
|> Multi.run(:send_reject_follow, fn _data, _repo ->
|
||||
send_reject(follow)
|
||||
end)
|
||||
|> Repo.transaction()
|
||||
end
|
||||
|
||||
def send_withdrawl(request) do
|
||||
request.followee
|
||||
|> ActivityPub.fetch_actor()
|
||||
|
|
@ -115,7 +124,7 @@ defmodule Postland.Follows do
|
|||
{:error, "could not find Follow activity to Accept"}
|
||||
|
||||
follow_activity ->
|
||||
body =
|
||||
activity =
|
||||
%{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"type" => "Accept",
|
||||
|
|
@ -127,18 +136,51 @@ defmodule Postland.Follows do
|
|||
"type" => "Follow"
|
||||
}
|
||||
}
|
||||
|> Jason.encode!()
|
||||
|
||||
headers =
|
||||
Headers.signing_headers(
|
||||
"POST",
|
||||
inbox,
|
||||
body,
|
||||
Postland.my_actor_id(),
|
||||
Accounts.solo_user().private_key
|
||||
)
|
||||
ActivityPub.post_activity(
|
||||
Postland.my_actor_id(),
|
||||
Accounts.solo_user().private_key,
|
||||
inbox,
|
||||
activity
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
Req.post(inbox, headers: headers, body: body)
|
||||
def send_reject(request) do
|
||||
request.follower
|
||||
|> ActivityPub.fetch_actor()
|
||||
|> do_send_reject(request)
|
||||
end
|
||||
|
||||
defp do_send_reject(nil, _), do: {:ok, nil}
|
||||
|
||||
defp do_send_reject({:ok, actor}, request) do
|
||||
inbox = Map.get(actor, "inbox")
|
||||
|
||||
case get_follow_activity(request.follower) do
|
||||
nil ->
|
||||
{:error, "could not find Follow activity to Reject"}
|
||||
|
||||
follow_activity ->
|
||||
activity =
|
||||
%{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"type" => "Reject",
|
||||
"actor" => Postland.my_actor_id(),
|
||||
"object" => %{
|
||||
"actor" => request.follower,
|
||||
"id" => Map.get(follow_activity.data, "id"),
|
||||
"object" => Postland.my_actor_id(),
|
||||
"type" => "Follow"
|
||||
}
|
||||
}
|
||||
|
||||
ActivityPub.post_activity(
|
||||
Postland.my_actor_id(),
|
||||
Accounts.solo_user().private_key,
|
||||
inbox,
|
||||
activity
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -52,13 +52,21 @@ defmodule PostlandWeb.CoreComponents do
|
|||
</p>
|
||||
</div>
|
||||
<div class="flex-grow text-right">
|
||||
<.button
|
||||
:if={@status == :follower_pending}
|
||||
phx-click="reject"
|
||||
phx-value-dom-id={@dom_id}
|
||||
phx-value-id={@account["id"]}
|
||||
>
|
||||
Reject
|
||||
</.button>
|
||||
<.button
|
||||
:if={@status == :follower_pending}
|
||||
phx-click="confirm"
|
||||
phx-value-dom-id={@dom_id}
|
||||
phx-value-id={@account["id"]}
|
||||
>
|
||||
Accept Request
|
||||
Accept
|
||||
</.button>
|
||||
<.button
|
||||
:if={@status == :following_pending}
|
||||
|
|
@ -484,7 +492,7 @@ defmodule PostlandWeb.CoreComponents do
|
|||
def simple_form(assigns) do
|
||||
~H"""
|
||||
<.form :let={f} for={@for} as={@as} {@rest}>
|
||||
<div class="mt-10 space-y-8 bg-white">
|
||||
<div class="space-y-8 bg-white">
|
||||
<%= render_slot(@inner_block, f) %>
|
||||
<div :for={action <- @actions} class="mt-2 flex items-center justify-between gap-6">
|
||||
<%= render_slot(action, f) %>
|
||||
|
|
|
|||
28
lib/postland_web/live/dev_live.ex
Normal file
28
lib/postland_web/live/dev_live.ex
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
defmodule PostlandWeb.DevLive do
|
||||
use PostlandWeb, :live_view
|
||||
use Phoenix.VerifiedRoutes, endpoint: PostlandWeb.Endpoint, router: PostlandWeb.Router
|
||||
|
||||
alias Postland.Activities
|
||||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<.button phx-click="make_follower_request">Make follower request</.button>
|
||||
"""
|
||||
end
|
||||
|
||||
def handle_event("make_follower_request", _, socket) do
|
||||
mock_actor = "https://example.com/actors/test"
|
||||
encoded_followee = Base.url_encode64(Postland.my_actor_id(), padding: false)
|
||||
encoded_follower = Base.url_encode64(mock_actor, padding: false)
|
||||
|
||||
Activities.process_activity(%{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"id" => url(~p"/follows/#{encoded_followee}/#{encoded_follower}"),
|
||||
"type" => "Follow",
|
||||
"actor" => mock_actor,
|
||||
"object" => Postland.my_actor_id()
|
||||
})
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
|
@ -43,7 +43,7 @@ defmodule PostlandWeb.FollowersLive do
|
|||
{:ok, socket |> stream(:accounts, followers) |> assign(count: account_count)}
|
||||
end
|
||||
|
||||
def handle_event("confirm", %{"id" => id, "dom-id" => dom_id}, socket) do
|
||||
def handle_event("confirm", %{"id" => id}, socket) do
|
||||
request = Follows.get(id, Postland.my_actor_id())
|
||||
|
||||
socket =
|
||||
|
|
@ -53,7 +53,7 @@ defmodule PostlandWeb.FollowersLive do
|
|||
|
||||
acct = %{
|
||||
id: request.follower,
|
||||
confirmed: !!request.onfirmed_at,
|
||||
confirmed: !!request.confirmed_at,
|
||||
account: Actors.actor(request.follower)
|
||||
}
|
||||
|
||||
|
|
@ -66,4 +66,27 @@ defmodule PostlandWeb.FollowersLive do
|
|||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("reject", %{"id" => id}, socket) do
|
||||
request = Follows.get(id, Postland.my_actor_id())
|
||||
|
||||
socket =
|
||||
case Follows.record_and_reject(request) do
|
||||
{:ok, _} ->
|
||||
acct = %{
|
||||
id: request.follower,
|
||||
confirmed: true,
|
||||
account: Actors.actor(request.follower)
|
||||
}
|
||||
|
||||
socket
|
||||
|> stream_delete(:accounts, acct)
|
||||
|> assign(count: socket.assigns.count - 1)
|
||||
|
||||
_ ->
|
||||
put_flash(socket, :error, "An unexpected error occurred.")
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,19 +8,21 @@ defmodule PostlandWeb.UserLoginLive do
|
|||
Log in to account
|
||||
</.header>
|
||||
|
||||
<.simple_form for={@form} id="login_form" action={~p"/users/log_in"} phx-update="ignore">
|
||||
<.input field={@form[:username]} type="text" label="Username" required />
|
||||
<.input field={@form[:password]} type="password" label="Password" required />
|
||||
<div class="p-4 mt-10 bg-white rounded">
|
||||
<.simple_form for={@form} id="login_form" action={~p"/users/log_in"} phx-update="ignore">
|
||||
<.input field={@form[:username]} type="text" label="Username" required />
|
||||
<.input field={@form[:password]} type="password" label="Password" required />
|
||||
|
||||
<:actions>
|
||||
<.input field={@form[:remember_me]} type="checkbox" label="Keep me logged in" />
|
||||
</:actions>
|
||||
<:actions>
|
||||
<.button phx-disable-with="Logging in..." class="w-full">
|
||||
Log in <span aria-hidden="true">→</span>
|
||||
</.button>
|
||||
</:actions>
|
||||
</.simple_form>
|
||||
<:actions>
|
||||
<.input field={@form[:remember_me]} type="checkbox" label="Keep me logged in" />
|
||||
</:actions>
|
||||
<:actions>
|
||||
<.button phx-disable-with="Logging in..." class="w-full">
|
||||
Log in <span aria-hidden="true">→</span>
|
||||
</.button>
|
||||
</:actions>
|
||||
</.simple_form>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -58,6 +58,11 @@ defmodule PostlandWeb.Router do
|
|||
pipe_through :browser
|
||||
|
||||
live_dashboard "/dashboard", metrics: PostlandWeb.Telemetry
|
||||
|
||||
live_session :mount_current_user_dev,
|
||||
on_mount: [{PostlandWeb.UserAuth, :mount_current_user}] do
|
||||
live "/mocks", PostlandWeb.DevLive
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue