feat: Handle follows

This commit is contained in:
Ro 2024-10-09 22:45:28 +00:00
parent 2959a86f8f
commit 1259d3202d
9 changed files with 121 additions and 2 deletions

13
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,13 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [
]
}

2
lib/activity_pub.ex Normal file
View file

@ -0,0 +1,2 @@
defmodule ActivityPub do
end

View file

@ -7,6 +7,8 @@ defmodule Postland do
if it comes from the database, an external API or others. if it comes from the database, an external API or others.
""" """
use Phoenix.VerifiedRoutes, endpoint: PostlandWeb.Endpoint, router: PostlandWeb.Router
alias Postland.Accounts alias Postland.Accounts
def temporary_password() do def temporary_password() do
@ -51,4 +53,8 @@ defmodule Postland do
def setup?() do def setup?() do
Accounts.solo_user() != nil Accounts.solo_user() != nil
end end
def my_actor_id do
url(~p"/actor")
end
end end

View file

@ -1,10 +1,37 @@
defmodule Postland.Activities do defmodule Postland.Activities do
use Phoenix.VerifiedRoutes, endpoint: PostlandWeb.Endpoint, router: PostlandWeb.Router
alias Postland.Activity alias Postland.Activity
alias Postland.Repo alias Postland.Repo
def process_activity(params) do
case record_activity(params) do
{:ok, activity} ->
cause_effects(activity)
other ->
other
end
end
def record_activity(params) do def record_activity(params) do
params params
|> Activity.changeset() |> Activity.changeset()
|> Repo.insert() |> Repo.insert()
end end
def cause_effects(%Activity{actor_id: actor_id, type: "Follow", data: %{"object" => object}} = activity) do
if object == Postland.my_actor_id() do
case Postland.Follows.record_inbound_request(actor_id) do
{:ok, _follow} ->
{:ok, activity}
other ->
other
end
else
{:ok, activity}
end
end
def cause_effects(activity), do: activity
end end

29
lib/postland/follow.ex Normal file
View file

@ -0,0 +1,29 @@
defmodule Postland.Follow do
use Ecto.Schema
import Ecto.Changeset
schema "follows" do
field :follower, :string, primary_key: true
field :followee, :string, primary_key: true
field :confirmed_at, :naive_datetime
end
def changeset(follower, followee, confirmed \\ false) do
attrs = %{
follower: follower,
followee: followee,
confirmed_at: (if confirmed, do: NaiveDateTime.utc_now())
}
%__MODULE__{}
|> cast(attrs, [:follower, :followee, :confirmed_at])
|> validate_required(:followee)
|> validate_required(:follower)
end
def confirm_changeset(request) do
request
|> cast(%{confirmed_at: NaiveDateTime.utc_now()}, [:confirmed_at])
end
end

31
lib/postland/follows.ex Normal file
View file

@ -0,0 +1,31 @@
defmodule Postland.Follows do
import Ecto.Query, warn: false
alias Postland.Follow
alias Postland.Repo
def pending_inbound_requests() do
my_actor_id = Postland.my_actor_id()
from(f in Follow, where: f.followee == ^my_actor_id, where: is_nil(f.confirmed_at))
|> Repo.all()
end
def record_outbound_request(to_actor_id) do
Postland.my_actor_id()
|> Follow.changeset(to_actor_id)
|> Repo.insert(conflict_target: [:followee, :follower], on_conflict: :nothing)
end
def record_inbound_request(from_actor_id) do
from_actor_id
|> Follow.changeset(Postland.my_actor_id())
|> Repo.insert(conflict_target: [:followee, :follower], on_conflict: :nothing)
end
def confirm_request(request) do
request
|> Follow.confirm_changeset()
|> Repo.update()
end
end

View file

@ -8,7 +8,7 @@ defmodule PostlandWeb.InboxController do
def post(conn, params) do def post(conn, params) do
if Headers.verify(conn.method, conn.request_path, conn.req_headers) do if Headers.verify(conn.method, conn.request_path, conn.req_headers) do
case Activities.record_activity(params) do case Activities.process_activity(params) do
{:ok, _activity} -> {:ok, _activity} ->
render(conn, :ok) render(conn, :ok)
error -> error ->

View file

@ -18,7 +18,7 @@
"finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"}, "finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"},
"floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"}, "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"},
"gettext": {:hex, :gettext, "0.26.1", "38e14ea5dcf962d1fc9f361b63ea07c0ce715a8ef1f9e82d3dfb8e67e0416715", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "01ce56f188b9dc28780a52783d6529ad2bc7124f9744e571e1ee4ea88bf08734"}, "gettext": {:hex, :gettext, "0.26.1", "38e14ea5dcf962d1fc9f361b63ea07c0ce715a8ef1f9e82d3dfb8e67e0416715", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "01ce56f188b9dc28780a52783d6529ad2bc7124f9744e571e1ee4ea88bf08734"},
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized"]}, "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized", depth: 1]},
"hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},

View file

@ -0,0 +1,11 @@
defmodule Postland.Repo.Migrations.AddActors do
use Ecto.Migration
def change do
create table("follows", primary_key: false) do
add :follower, :string, primary_key: true
add :followee, :string, primary_key: true
add :confirmed_at, :naive_datetime
end
end
end