This commit is contained in:
Mirai Kumiko 2025-06-18 09:13:59 +02:00
parent 3a57d74357
commit df548a4943
Signed by: miraikumiko
GPG key ID: 3F178B1B5E0CB278
12 changed files with 137 additions and 179 deletions

View file

@ -1,4 +1,9 @@
defmodule Nulla.ActivityPub do defmodule Nulla.ActivityPub do
alias Nulla.Models.Actor
alias Nulla.Models.Activity
alias Nulla.Models.Note
alias Nulla.Models.InstanceSettings
@spec context() :: list() @spec context() :: list()
defp context do defp context do
[ [
@ -25,7 +30,7 @@ defmodule Nulla.ActivityPub do
] ]
end end
@spec actor(Nulla.Models.Actor.t()) :: Jason.OrderedObject.t() @spec actor(Actor.t()) :: Jason.OrderedObject.t()
def actor(actor) do def actor(actor) do
Jason.OrderedObject.new( Jason.OrderedObject.new(
"@context": context(), "@context": context(),
@ -57,7 +62,7 @@ defmodule Nulla.ActivityPub do
) )
end end
@spec note(String.t(), Nulla.Models.Note.t()) :: Jason.OrderedObject.t() @spec note(String.t(), Note.t()) :: Jason.OrderedObject.t()
def note(domain, note) do def note(domain, note) do
attachment = attachment =
case note.media_attachments do case note.media_attachments do
@ -102,7 +107,7 @@ defmodule Nulla.ActivityPub do
) )
end end
@spec activity(String.t(), Nulla.Models.Activity.t()) :: Jason.OrderedObject.t() @spec activity(String.t(), Activity.t()) :: Jason.OrderedObject.t()
def activity(domain, activity) do def activity(domain, activity) do
Jason.OrderedObject.new( Jason.OrderedObject.new(
"@context": "https://www.w3.org/ns/activitystreams", "@context": "https://www.w3.org/ns/activitystreams",
@ -113,35 +118,28 @@ defmodule Nulla.ActivityPub do
) )
end end
@spec following(String.t(), Nulla.Models.Actor.t(), Integer.t()) :: Jason.OrderedObject.t() @spec following(Actor.t(), Integer.t()) :: Jason.OrderedObject.t()
def following(domain, actor, total) do def following(actor, total) do
Jason.OrderedObject.new( Jason.OrderedObject.new(
"@context": "https://www.w3.org/ns/activitystreams", "@context": "https://www.w3.org/ns/activitystreams",
id: "https://#{domain}/users/#{actor.preferredUsername}/following", id: "https://#{actor.domain}/users/#{actor.preferredUsername}/following",
type: "OrderedCollection", type: "OrderedCollection",
totalItems: total, totalItems: total,
first: "https://#{domain}/users/#{actor.preferredUsername}/following?page=1" first: "https://#{actor.domain}/users/#{actor.preferredUsername}/following?page=1"
) )
end end
@spec following( @spec following(Actor.t(), Integer.t(), List.t(), Integer.t(), Integer.t()) ::
String.t(), Jason.OrderedObject.t()
Nulla.Models.Actor.t(), def following(actor, total, following_list, page, limit) when is_integer(page) and page > 0 do
Integer.t(),
List.t(),
Integer.t(),
Integer.t()
) :: Jason.OrderedObject.t()
def following(domain, actor, total, following_list, page, offset)
when is_integer(page) and page > 0 do
data = [ data = [
"@context": "https://www.w3.org/ns/activitystreams", "@context": "https://www.w3.org/ns/activitystreams",
id: "https://#{domain}/@#{actor.preferredUsername}/following?page=#{page}", id: "https://#{actor.domain}/@#{actor.preferredUsername}/following?page=#{page}",
type: "OrderedCollectionPage", type: "OrderedCollectionPage",
totalItems: total, totalItems: total,
next: "https://#{domain}/users/#{actor.preferredUsername}/following?page=#{page + 1}", next: "https://#{actor.domain}/users/#{actor.preferredUsername}/following?page=#{page + 1}",
prev: "https://#{domain}/users/#{actor.preferredUsername}/following?page=#{page - 1}", prev: "https://#{actor.domain}/users/#{actor.preferredUsername}/following?page=#{page - 1}",
partOf: "https://#{domain}/users/#{actor.preferredUsername}/following", partOf: "https://#{actor.domain}/users/#{actor.preferredUsername}/following",
orderedItems: following_list orderedItems: following_list
] ]
@ -153,7 +151,7 @@ defmodule Nulla.ActivityPub do
end end
data = data =
if page * offset > total do if page * limit > total do
data data
|> Keyword.delete(:next) |> Keyword.delete(:next)
|> Keyword.delete(:prev) |> Keyword.delete(:prev)
@ -164,35 +162,29 @@ defmodule Nulla.ActivityPub do
Jason.OrderedObject.new(data) Jason.OrderedObject.new(data)
end end
@spec followers(String.t(), Nulla.Models.Actor.t(), Integer.t()) :: Jason.OrderedObject.t() @spec followers(Actor.t(), Integer.t()) :: Jason.OrderedObject.t()
def followers(domain, actor, total) do def followers(actor, total) do
Jason.OrderedObject.new( Jason.OrderedObject.new(
"@context": "https://www.w3.org/ns/activitystreams", "@context": "https://www.w3.org/ns/activitystreams",
id: "https://#{domain}/users/#{actor.preferredUsername}/followers", id: "https://#{actor.domain}/users/#{actor.preferredUsername}/followers",
type: "OrderedCollection", type: "OrderedCollection",
totalItems: total, totalItems: total,
first: "https://#{domain}/users/#{actor.preferredUsername}/followers?page=1" first: "https://#{actor.domain}/users/#{actor.preferredUsername}/followers?page=1"
) )
end end
@spec followers( @spec followers(Actor.t(), Integer.t(), List.t(), Integer.t(), Integer.t()) ::
String.t(), Jason.OrderedObject.t()
Nulla.Models.Actor.t(), def followers(actor, total, followers_list, page, limit)
Integer.t(),
List.t(),
Integer.t(),
Integer.t()
) :: Jason.OrderedObject.t()
def followers(domain, actor, total, followers_list, page, offset)
when is_integer(page) and page > 0 do when is_integer(page) and page > 0 do
data = [ data = [
"@context": "https://www.w3.org/ns/activitystreams", "@context": "https://www.w3.org/ns/activitystreams",
id: "https://#{domain}/users#{actor.preferredUsername}/followers?page=#{page}", id: "https://#{actor.domain}/users#{actor.preferredUsername}/followers?page=#{page}",
type: "OrderedCollectionPage", type: "OrderedCollectionPage",
totalItems: total, totalItems: total,
next: "https://#{domain}/users/#{actor.preferredUsername}/followers?page=#{page + 1}", next: "https://#{actor.domain}/users/#{actor.preferredUsername}/followers?page=#{page + 1}",
prev: "https://#{domain}/users/#{actor.preferredUsername}/followers?page=#{page - 1}", prev: "https://#{actor.domain}/users/#{actor.preferredUsername}/followers?page=#{page - 1}",
partOf: "https://#{domain}/users/#{actor.preferredUsername}/followers", partOf: "https://#{actor.domain}/users/#{actor.preferredUsername}/followers",
orderedItems: followers_list orderedItems: followers_list
] ]
@ -204,7 +196,7 @@ defmodule Nulla.ActivityPub do
end end
data = data =
if page * offset > total do if page * limit > total do
data data
|> Keyword.delete(:next) |> Keyword.delete(:next)
|> Keyword.delete(:prev) |> Keyword.delete(:prev)
@ -215,7 +207,7 @@ defmodule Nulla.ActivityPub do
Jason.OrderedObject.new(data) Jason.OrderedObject.new(data)
end end
@spec webfinger(Nulla.Models.Actor.t()) :: Jason.OrderedObject.t() @spec webfinger(Actor.t()) :: Jason.OrderedObject.t()
def webfinger(actor) do def webfinger(actor) do
Jason.OrderedObject.new( Jason.OrderedObject.new(
subject: "#{actor.preferredUsername}@#{actor.domain}", subject: "#{actor.preferredUsername}@#{actor.domain}",
@ -255,8 +247,7 @@ defmodule Nulla.ActivityPub do
) )
end end
@spec nodeinfo(String.t(), Map.t(), Nulla.Models.InstanceSettings.t()) :: @spec nodeinfo(String.t(), Map.t(), InstanceSettings.t()) :: Jason.OrderedObject.t()
Jason.OrderedObject.t()
def nodeinfo(version, users, instance) do def nodeinfo(version, users, instance) do
Jason.OrderedObject.new( Jason.OrderedObject.new(
version: "2.0", version: "2.0",
@ -323,7 +314,7 @@ defmodule Nulla.ActivityPub do
) )
end end
@spec activity_note(Nulla.Models.Note.t()) :: Jason.OrderedObject.t() @spec activity_note(Note.t()) :: Jason.OrderedObject.t()
def activity_note(note) do def activity_note(note) do
Jason.OrderedObject.new( Jason.OrderedObject.new(
id: id:
@ -349,7 +340,7 @@ defmodule Nulla.ActivityPub do
) )
end end
@spec follow_accept(Nulla.Models.Activity.t()) :: Jason.OrderedObject.t() @spec follow_accept(Activity.t()) :: Jason.OrderedObject.t()
def follow_accept(activity) do def follow_accept(activity) do
Jason.OrderedObject.new( Jason.OrderedObject.new(
"@context": "https://www.w3.org/ns/activitystreams", "@context": "https://www.w3.org/ns/activitystreams",

View file

@ -28,7 +28,7 @@ defmodule Nulla.Models.Activity do
%__MODULE__{} %__MODULE__{}
|> __MODULE__.changeset(attrs) |> __MODULE__.changeset(attrs)
|> Changeset.put_change(:id, id) |> put_change(:id, id)
|> Repo.insert() |> Repo.insert()
end end
end end

View file

@ -106,7 +106,7 @@ defmodule Nulla.Models.Actor do
%__MODULE__{} %__MODULE__{}
|> changeset(attrs) |> changeset(attrs)
|> Changeset.put_change(:id, id) |> put_change(:id, id)
|> Repo.insert() |> Repo.insert()
end end

View file

@ -11,7 +11,7 @@ defmodule Nulla.Models.InstanceSettings do
field :registration, :boolean, default: false field :registration, :boolean, default: false
field :max_characters, :integer, default: 5000 field :max_characters, :integer, default: 5000
field :max_upload_size, :integer, default: 50 field :max_upload_size, :integer, default: 50
field :api_offset, :integer, default: 100 field :api_limit, :integer, default: 100
field :public_key, :string field :public_key, :string
field :private_key, :string field :private_key, :string
end end
@ -26,7 +26,7 @@ defmodule Nulla.Models.InstanceSettings do
:registration, :registration,
:max_characters, :max_characters,
:max_upload_size, :max_upload_size,
:api_offset, :api_limit,
:public_key, :public_key,
:private_key :private_key
]) ])
@ -37,7 +37,7 @@ defmodule Nulla.Models.InstanceSettings do
:registration, :registration,
:max_characters, :max_characters,
:max_upload_size, :max_upload_size,
:api_offset, :api_limit,
:public_key, :public_key,
:private_key :private_key
]) ])

View file

@ -1,6 +1,7 @@
defmodule Nulla.Models.Relation do defmodule Nulla.Models.Relation do
use Ecto.Schema use Ecto.Schema
import Ecto.Changeset import Ecto.Changeset
import Ecto.Query
alias Nulla.Repo alias Nulla.Repo
alias Nulla.Snowflake alias Nulla.Snowflake
alias Nulla.Models.Actor alias Nulla.Models.Actor
@ -21,8 +22,8 @@ defmodule Nulla.Models.Relation do
field :requested, :boolean, default: false field :requested, :boolean, default: false
field :note, :string field :note, :string
belongs_to :local_actor_id, Actor belongs_to :local_actor, Actor
belongs_to :remote_actor_id, Actor belongs_to :remote_actor, Actor
timestamps() timestamps()
end end
@ -44,8 +45,8 @@ defmodule Nulla.Models.Relation do
:domain_blocking, :domain_blocking,
:requested, :requested,
:note, :note,
:source_id, :local_actor_id,
:target_id :remote_actor_id
]) ])
|> validate_required([:id, :local_actor_id, :remote_actor_id]) |> validate_required([:id, :local_actor_id, :remote_actor_id])
|> unique_constraint([:local_actor_id, :remote_actor_id]) |> unique_constraint([:local_actor_id, :remote_actor_id])
@ -56,7 +57,53 @@ defmodule Nulla.Models.Relation do
%__MODULE__{} %__MODULE__{}
|> __MODULE__.changeset(attrs) |> __MODULE__.changeset(attrs)
|> Changeset.put_change(:id, id) |> put_change(:id, id)
|> Repo.insert() |> Repo.insert()
end end
def count_following(local_actor_id) do
__MODULE__
|> where([r], r.local_actor_id == ^local_actor_id and r.following == true)
|> select([r], count(r.id))
|> Repo.one()
end
def get_following(local_actor_id, page, limit) when is_integer(page) and page > 0 do
offset = (page - 1) * limit
query =
from r in __MODULE__,
join: a in Actor,
on: a.id == r.remote_actor_id,
where: r.local_actor_id == ^local_actor_id and r.following == true,
order_by: [asc: a.published],
offset: ^offset,
limit: ^limit,
select: a
Repo.all(query)
end
def count_followers(local_actor_id) do
__MODULE__
|> where([r], r.local_actor_id == ^local_actor_id and r.followed_by == true)
|> select([r], count(r.id))
|> Repo.one()
end
def get_followers(local_actor_id, page, limit) when is_integer(page) and page > 0 do
offset = (page - 1) * limit
query =
from r in __MODULE__,
join: a in Actor,
on: a.id == r.remote_actor_id,
where: r.local_actor_id == ^local_actor_id and r.followed_by == true,
order_by: [asc: a.published],
offset: ^offset,
limit: ^limit,
select: a
Repo.all(query)
end
end end

View file

@ -69,7 +69,7 @@ defmodule Nulla.Models.User do
def update_last_active(user) do def update_last_active(user) do
user user
|> Changeset.change(last_active_at: DateTime.utc_now()) |> change(last_active_at: DateTime.utc_now())
|> Repo.update() |> Repo.update()
end end
end end

View file

@ -1,102 +1,16 @@
defmodule Nulla.Utils do defmodule Nulla.Utils do
import Ecto.Query alias Nulla.Models.Actor
alias Nulla.Repo
alias Nulla.Models.User
alias Nulla.Models.Follow
alias Nulla.Models.InstanceSettings alias Nulla.Models.InstanceSettings
def count_following_by_username!(username) do
case Repo.get_by(User, username: username) do
nil ->
{:error, :user_not_found}
%User{id: user_id} ->
count =
Follow
|> where([f], f.user_id == ^user_id)
|> select([f], count(f.id))
|> Repo.one()
count
end
end
def get_following_users_by_username!(username, page) when is_integer(page) and page > 0 do
case Repo.get_by(User, username: username) do
nil ->
{:error, :user_not_found}
%User{id: user_id} ->
instance_settings = InstanceSettings.get_instance_settings!()
per_page = instance_settings.api_offset
offset = (page - 1) * per_page
query =
from(
[f, u] in from(f in Follow,
join: u in User,
on: u.id == f.target_id,
where: f.user_id == ^user_id,
order_by: [asc: u.inserted_at],
offset: ^offset,
limit: ^per_page,
select: u
)
)
users = Repo.all(query)
users
end
end
def count_followers_by_username!(username) do
case Repo.get_by(User, username: username) do
nil ->
0
%User{id: user_id} ->
from(f in Follow, where: f.target_id == ^user_id)
|> select([f], count(f.id))
|> Repo.one()
end
end
def get_followers_by_username!(username, page) when is_integer(page) and page > 0 do
case Repo.get_by(User, username: username) do
nil ->
{:error, :user_not_found}
%User{id: user_id} ->
instance_settings = InstanceSettings.get_instance_settings!()
per_page = instance_settings.api_offset
offset = (page - 1) * per_page
query =
from f in Follow,
where: f.target_id == ^user_id,
join: u in User,
on: u.id == f.user_id,
order_by: [asc: u.inserted_at],
offset: ^offset,
limit: ^per_page,
select: u
users = Repo.all(query)
users
end
end
def resolve_local_actor("https://" <> _ = uri) do def resolve_local_actor("https://" <> _ = uri) do
case URI.parse(uri).path do case URI.parse(uri).path do
"/@" <> username -> "/@" <> username ->
instance_settings = InstanceSettings.get_instance_settings!() instance_settings = InstanceSettings.get_instance_settings!()
domain = instance_settings.domain domain = instance_settings.domain
case User.get_user_by_username_and_domain(username, domain) do case Actor.get_actor(username, domain) do
nil -> {:error, :not_found} nil -> {:error, :not_found}
user -> {:ok, user} user -> user
end end
_ -> _ ->
@ -110,7 +24,7 @@ defmodule Nulla.Utils do
{"Accept", "application/activity+json"} {"Accept", "application/activity+json"}
]) ])
case Finch.request(request, MyApp.Finch) do case Finch.request(request, Finch) do
{:ok, %Finch.Response{status: 200, body: body}} -> {:ok, %Finch.Response{status: 200, body: body}} ->
case Jason.decode(body) do case Jason.decode(body) do
{:ok, data} -> {:ok, data} {:ok, data} -> {:ok, data}

View file

@ -36,6 +36,7 @@ defmodule NullaWeb.ActorHTML do
month_diff = now.month - date.month month_diff = now.month - date.month
day_correction = if now.day < date.day, do: -1, else: 0 day_correction = if now.day < date.day, do: -1, else: 0
months = year_diff * 12 + month_diff + day_correction months = year_diff * 12 + month_diff + day_correction
if months == 1 do if months == 1 do
"#{formatted} (1 month ago)" "#{formatted} (1 month ago)"
else else
@ -44,7 +45,10 @@ defmodule NullaWeb.ActorHTML do
true -> true ->
year_diff = now.year - date.year year_diff = now.year - date.year
years = if {now.month, now.day} < {date.month, date.day}, do: year_diff - 1, else: year_diff
years =
if {now.month, now.day} < {date.month, date.day}, do: year_diff - 1, else: year_diff
if years == 1 do if years == 1 do
"#{formatted} (1 year ago)" "#{formatted} (1 year ago)"
else else

View file

@ -19,7 +19,8 @@
<img src={@actor.image["url"]} class="w-full h-full object-cover" /> <img src={@actor.image["url"]} class="w-full h-full object-cover" />
<div class="absolute inset-0 flex items-end justify-between px-4 pb-2 pointer-events-none"> <div class="absolute inset-0 flex items-end justify-between px-4 pb-2 pointer-events-none">
<img <img
src={@actor.icon["url"]}} src={@actor.icon["url"]}
}
class="translate-y-1/2 rounded-full border-4 border-white w-[8.33vw] h-[8.33vw] min-w-[80px] min-h-[80px] max-w-[160px] max-h-[160px] pointer-events-auto" class="translate-y-1/2 rounded-full border-4 border-white w-[8.33vw] h-[8.33vw] min-w-[80px] min-h-[80px] max-w-[160px] max-h-[160px] pointer-events-auto"
/> />
<button class="px-8 py-2 rounded-full text-sm font-semibold border transition bg-black text-white border-black hover:bg-gray-900 pointer-events-auto"> <button class="px-8 py-2 rounded-full text-sm font-semibold border transition bg-black text-white border-black hover:bg-gray-900 pointer-events-auto">
@ -81,7 +82,7 @@
<%= for note <- @notes do %> <%= for note <- @notes do %>
<div class="p-4 border-b border-gray-300"> <div class="p-4 border-b border-gray-300">
<div class="flex items-start space-x-4"> <div class="flex items-start space-x-4">
<img src={@actor.icon["url"]}} class="rounded-full w-[58px] h-[58px]" /> <img src={@actor.icon["url"]} } class="rounded-full w-[58px] h-[58px]" />
<div class="flex-1"> <div class="flex-1">
<div class="flex justify-between items-start"> <div class="flex justify-between items-start">
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">

View file

@ -1,16 +1,16 @@
defmodule NullaWeb.FollowController do defmodule NullaWeb.FollowController do
use NullaWeb, :controller use NullaWeb, :controller
alias Nulla.ActivityPub alias Nulla.ActivityPub
alias Nulla.Utils
alias Nulla.Models.Actor alias Nulla.Models.Actor
alias Nulla.Models.Relation
alias Nulla.Models.InstanceSettings alias Nulla.Models.InstanceSettings
def following(conn, %{"username" => username, "page" => page_param}) do def following(conn, %{"username" => username, "page" => page_param}) do
instance_settings = InstanceSettings.get_instance_settings!() instance_settings = InstanceSettings.get_instance_settings!()
domain = instance_settings.domain domain = instance_settings.domain
offset = instance_settings.offset limit = instance_settings.limit
actor = Actor.get_actor(username, domain) actor = Actor.get_actor(username, domain)
total = Utils.count_following_by_username!(actor.preferredUsername) total = Relation.count_following(actor.id)
page = page =
case Integer.parse(page_param) do case Integer.parse(page_param) do
@ -18,30 +18,30 @@ defmodule NullaWeb.FollowController do
_ -> 1 _ -> 1
end end
following_list = Utils.get_following_users_by_username!(actor.preferredUsername, page) following_list = Relation.get_following(actor.id, page, limit)
conn conn
|> put_resp_content_type("application/activity+json") |> put_resp_content_type("application/activity+json")
|> json(ActivityPub.following(domain, actor, total, following_list, page, offset)) |> json(ActivityPub.following(actor, total, following_list, page, limit))
end end
def following(conn, %{"username" => username}) do def following(conn, %{"username" => username}) do
instance_settings = InstanceSettings.get_instance_settings!() instance_settings = InstanceSettings.get_instance_settings!()
domain = instance_settings.domain domain = instance_settings.domain
actor = Actor.get_actor(username, domain) actor = Actor.get_actor(username, domain)
total = Utils.count_following_by_username!(actor.preferredUsername) total = Relation.count_following(actor.id)
conn conn
|> put_resp_content_type("application/activity+json") |> put_resp_content_type("application/activity+json")
|> json(ActivityPub.following(domain, actor, total)) |> json(ActivityPub.following(actor, total))
end end
def followers(conn, %{"username" => username, "page" => page_param}) do def followers(conn, %{"username" => username, "page" => page_param}) do
instance_settings = InstanceSettings.get_instance_settings!() instance_settings = InstanceSettings.get_instance_settings!()
domain = instance_settings.domain domain = instance_settings.domain
offset = instance_settings.offset limit = instance_settings.limit
actor = Actor.get_actor(username, domain) actor = Actor.get_actor(username, domain)
total = Utils.count_followers_by_username!(actor.preferredUsername) total = Relation.count_followers(actor.id)
page = page =
case Integer.parse(page_param) do case Integer.parse(page_param) do
@ -49,21 +49,21 @@ defmodule NullaWeb.FollowController do
_ -> 1 _ -> 1
end end
followers_list = Utils.get_followers_by_username!(actor.preferredUsername, page) followers_list = Relation.get_followers(actor.id, page, limit)
conn conn
|> put_resp_content_type("application/activity+json") |> put_resp_content_type("application/activity+json")
|> json(ActivityPub.followers(domain, actor, total, followers_list, page, offset)) |> json(ActivityPub.followers(actor, total, followers_list, page, limit))
end end
def followers(conn, %{"username" => username}) do def followers(conn, %{"username" => username}) do
instance_settings = InstanceSettings.get_instance_settings!() instance_settings = InstanceSettings.get_instance_settings!()
domain = instance_settings.domain domain = instance_settings.domain
actor = Actor.get_actor(username, domain) actor = Actor.get_actor(username, domain)
total = Utils.count_followers_by_username!(actor.preferredUsername) total = Relation.count_followers(actor.id)
conn conn
|> put_resp_content_type("application/activity+json") |> put_resp_content_type("application/activity+json")
|> json(ActivityPub.followers(domain, actor, total)) |> json(ActivityPub.followers(actor, total))
end end
end end

View file

@ -11,7 +11,7 @@ defmodule NullaWeb.InboxController do
conn, conn,
%{"id" => follow_id, "type" => "Follow", "actor" => actor_uri, "object" => target_uri} %{"id" => follow_id, "type" => "Follow", "actor" => actor_uri, "object" => target_uri}
) do ) do
with {:ok, target_actor} <- Utils.resolve_local_actor(target_uri), with {:ok, local_actor} <- Utils.resolve_local_actor(target_uri),
{:ok, remote_actor_json} <- Utils.fetch_remote_actor(actor_uri), {:ok, remote_actor_json} <- Utils.fetch_remote_actor(actor_uri),
:ok <- HTTPSignature.verify(conn, remote_actor_json), :ok <- HTTPSignature.verify(conn, remote_actor_json),
remote_actor <- remote_actor <-
@ -31,12 +31,13 @@ defmodule NullaWeb.InboxController do
accept_activity <- accept_activity <-
Activity.create_activity(%{ Activity.create_activity(%{
type: "Accept", type: "Accept",
actor: target_actor.id, actor: local_actor.id,
object: follow_activity object: follow_activity
}), }),
relation <- Relation.create_relation(%{ _ <-
Relation.create_relation(%{
followed_by: true, followed_by: true,
local_actor_id: target_actor.id, local_actor_id: local_actor.id,
remote_actor_id: remote_actor.id remote_actor_id: remote_actor.id
}) do }) do
conn conn

View file

@ -10,7 +10,7 @@ defmodule Nulla.Repo.Migrations.CreateInstanceSettings do
add :registration, :boolean, default: false, null: false add :registration, :boolean, default: false, null: false
add :max_characters, :integer, default: 5000, null: false add :max_characters, :integer, default: 5000, null: false
add :max_upload_size, :integer, default: 50, null: false add :max_upload_size, :integer, default: 50, null: false
add :api_offset, :integer, default: 100, null: false add :api_limit, :integer, default: 100, null: false
add :public_key, :text add :public_key, :text
add :private_key, :text add :private_key, :text
@ -35,7 +35,7 @@ defmodule Nulla.Repo.Migrations.CreateInstanceSettings do
sql = """ sql = """
INSERT INTO instance_settings ( INSERT INTO instance_settings (
id, name, description, domain, registration, id, name, description, domain, registration,
max_characters, max_upload_size, api_offset, max_characters, max_upload_size, api_limit,
public_key, private_key, inserted_at, updated_at public_key, private_key, inserted_at, updated_at
) VALUES ( ) VALUES (
1, 'Nulla', 'Freedom Social Network', '#{domain}', false, 1, 'Nulla', 'Freedom Social Network', '#{domain}', false,