This commit is contained in:
Mirai Kumiko 2025-06-17 12:06:36 +02:00
parent 58049c93d4
commit 894866ca03
Signed by: miraikumiko
GPG key ID: 3F178B1B5E0CB278
22 changed files with 344 additions and 213 deletions

View file

@ -0,0 +1,43 @@
defmodule NullaWeb.ActorController do
use NullaWeb, :controller
alias Nulla.ActivityPub
alias Nulla.Utils
alias Nulla.Models.Actor
alias Nulla.Models.Note
alias Nulla.Models.InstanceSettings
def show(conn, %{"username" => username}) do
accept = List.first(get_req_header(conn, "accept"))
instance_settings = InstanceSettings.get_instance_settings!()
domain = instance_settings.domain
case Actor.get_actor(username, domain) do
nil ->
conn
|> put_status(:not_found)
|> json(%{error: "Not Found"})
%Actor{} = actor ->
if accept in ["application/activity+json", "application/ld+json"] do
conn
|> put_resp_content_type("application/activity+json")
|> send_resp(200, Jason.encode!(ActivityPub.actor(actor)))
else
notes = Note.get_latest_notes(actor.id)
following = Utils.count_following_by_username!(actor.preferredUsername)
followers = Utils.count_followers_by_username!(actor.preferredUsername)
render(
conn,
:show,
domain: domain,
actor: actor,
notes: notes,
following: following,
followers: followers,
layout: false
)
end
end
end
end

View file

@ -0,0 +1,12 @@
defmodule NullaWeb.AuthController do
use NullaWeb, :controller
def sign_in do
end
def sign_out do
end
def sign_up do
end
end

View file

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

View file

@ -1,19 +1,49 @@
defmodule NullaWeb.InboxController do
use NullaWeb, :controller
alias Nulla.Models.Follow
alias Nulla.HTTPSignature
alias Nulla.ActivityPub
alias Nulla.Utils
alias Nulla.Models.Actor
alias Nulla.Models.Relation
def inbox(
conn,
%{"type" => "Follow", "actor" => actor_uri, "object" => target_uri} = activity
%{"id" => follow_id, "type" => "Follow", "actor" => actor_uri, "object" => target_uri}
) do
with {:ok, target_user} <- Utils.resolve_local_actor(target_uri),
{:ok, remote_actor} <- Utils.fetch_remote_actor(actor_uri),
:ok <- HTTPSignature.verify(conn, remote_actor),
remote_user <- Follow.create_remote_user(remote_actor),
follow <- Follow.create_follow(%{user: remote_user, target: target_user}),
:ok <- Utils.send_accept_activity(remote_actor, target_user, follow, activity) do
json(conn, %{"status" => "Follow accepted"})
with {:ok, target_actor} <- Utils.resolve_local_actor(target_uri),
{:ok, remote_actor_json} <- Utils.fetch_remote_actor(actor_uri),
:ok <- HTTPSignature.verify(conn, remote_actor_json),
remote_actor <-
Actor.create_actor(
remote_actor_json
|> Map.put("ap_id", remote_actor_json["id"])
|> Map.delete("id")
|> Map.put("domain", URI.parse(remote_actor_json["id"]).host)
),
follow_activity <-
Activity.create_activity(%{
ap_id: follow_id,
type: "Follow",
actor: actor_uri,
object: target_uri
}),
accept_activity <-
Activity.create_activity(%{
type: "Accept",
actor: target_uri,
object: follow_activity
}),
relation <- Relation.create_relation(%{
id: 1,
follower: remote_actor.id,
followed: target_actor.id
}) do
conn
|> put_resp_content_type("application/activity+json")
|> send_resp(
200,
Jason.encode!(ActivityPub.follow_accept(accept_activity))
)
else
error ->
IO.inspect(error, label: "Follow error")

View file

@ -1,6 +1,5 @@
defmodule NullaWeb.NodeinfoController do
use NullaWeb, :controller
alias Nulla.Repo
alias Nulla.ActivityPub
alias Nulla.Models.User
alias Nulla.Models.InstanceSettings

View file

@ -1,7 +1,7 @@
defmodule NullaWeb.OutboxController do
use NullaWeb, :controller
alias Nulla.ActivityPub
alias Nulla.Models.User
alias Nulla.Models.Actor
alias Nulla.Models.Note
alias Nulla.Models.InstanceSettings
@ -10,17 +10,17 @@ defmodule NullaWeb.OutboxController do
"true" ->
instance_settings = InstanceSettings.get_instance_settings!()
domain = instance_settings.domain
user = User.get_user_by_username!(username)
actor = Actor.get_actor(username, domain)
max_id = params["max_id"] && String.to_integer(params["max_id"])
notes =
if max_id do
Note.get_before_notes(user.id, max_id)
Note.get_before_notes(actor.id, max_id)
else
Note.get_latest_notes(user.id)
Note.get_latest_notes(actor.id)
end
items = Enum.map(notes, &ActivityPub.render_activity(&1, domain))
items = Enum.map(notes, &ActivityPub.activity_note(&1))
next_max_id =
case List.last(notes) do
@ -44,8 +44,8 @@ defmodule NullaWeb.OutboxController do
_ ->
instance_settings = InstanceSettings.get_instance_settings!()
domain = instance_settings.domain
user = User.get_user_by_username!(username)
total = Note.get_total_notes_count(user.id)
actor = Actor.get_actor(username, domain)
total = Note.get_total_notes_count(actor.id)
conn
|> put_resp_content_type("application/activity+json")

View file

@ -1,36 +1,3 @@
defmodule NullaWeb.UserController do
use NullaWeb, :controller
alias Nulla.ActivityPub
alias Nulla.Utils
alias Nulla.Models.User
alias Nulla.Models.Note
alias Nulla.Models.InstanceSettings
def show(conn, %{"username" => username}) do
accept = List.first(get_req_header(conn, "accept"))
instance_settings = InstanceSettings.get_instance_settings!()
domain = instance_settings.domain
user = User.get_user_by_username!(username)
notes = Note.get_notes(user.id)
if accept in ["application/activity+json", "application/ld+json"] do
conn
|> put_resp_content_type("application/activity+json")
|> send_resp(200, Jason.encode!(ActivityPub.user(domain, user)))
else
following = Utils.count_following_by_username!(user.username)
followers = Utils.count_followers_by_username!(user.username)
render(
conn,
:show,
domain: domain,
user: user,
notes: notes,
following: following,
followers: followers,
layout: false
)
end
end
end

View file

@ -1,24 +1,23 @@
defmodule NullaWeb.WebfingerController do
use NullaWeb, :controller
alias Nulla.Repo
alias Nulla.ActivityPub
alias Nulla.Models.User
alias Nulla.Models.Actor
alias Nulla.Models.InstanceSettings
def index(conn, %{"resource" => resource}) do
case Regex.run(~r/^acct:([^@]+)@(.+)$/, resource) do
[_, username, domain] ->
case User.get_user_by_username(username) do
case Actor.get_actor(username, domain) do
nil ->
conn
|> put_status(:not_found)
|> json(%{error: "Not Found"})
user ->
%Actor{} = actor ->
instance_settings = InstanceSettings.get_instance_settings!()
if domain == instance_settings.domain do
json(conn, ActivityPub.webfinger(domain, username, resource))
json(conn, ActivityPub.webfinger(actor))
else
conn
|> put_status(:not_found)