Add following and followers
This commit is contained in:
parent
f8bedff913
commit
0b88881934
8 changed files with 261 additions and 4 deletions
|
@ -139,4 +139,90 @@ defmodule Nulla.ActivityPub do
|
|||
to: activity.to
|
||||
)
|
||||
end
|
||||
|
||||
@spec following(String.t(), Nulla.Models.User.t(), Integer.t()) :: Jason.OrderedObject.t()
|
||||
def following(domain, user, total) do
|
||||
Jason.OrderedObject.new(
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
id: "https://#{domain}/@#{user.username}/following",
|
||||
type: "OrderedCollection",
|
||||
totalItems: total,
|
||||
first: "https://#{domain}/@#{user.username}/following?page=1"
|
||||
)
|
||||
end
|
||||
|
||||
@spec following(String.t(), Nulla.Models.User.t(), Integer.t(), List.t(), Integer.t(), Integer.t()) :: Jason.OrderedObject.t()
|
||||
def following(domain, user, total, following_list, page, offset) when is_integer(page) and page > 0 do
|
||||
data = [
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
id: "https://#{domain}/@#{user.username}/following?page=#{page}",
|
||||
type: "OrderedCollectionPage",
|
||||
totalItems: total,
|
||||
next: "https://#{domain}/@#{user.username}/following?page=#{page + 1}",
|
||||
prev: "https://#{domain}/@#{user.username}/following?page=#{page - 1}",
|
||||
partOf: "https://#{domain}/@#{user.username}/following",
|
||||
orderedItems: following_list
|
||||
]
|
||||
|
||||
data =
|
||||
if page <= 1 do
|
||||
Keyword.delete(data, :prev)
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
data =
|
||||
if page * offset > total do
|
||||
data
|
||||
|> Keyword.delete(:next)
|
||||
|> Keyword.delete(:prev)
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
Jason.OrderedObject.new(data)
|
||||
end
|
||||
|
||||
@spec followers(String.t(), Nulla.Models.User.t(), Integer.t()) :: Jason.OrderedObject.t()
|
||||
def followers(domain, user, total) do
|
||||
Jason.OrderedObject.new(
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
id: "https://#{domain}/@#{user.username}/followers",
|
||||
type: "OrderedCollection",
|
||||
totalItems: total,
|
||||
first: "https://#{domain}/@#{user.username}/followers?page=1"
|
||||
)
|
||||
end
|
||||
|
||||
@spec followers(String.t(), Nulla.Models.User.t(), Integer.t(), List.t(), Integer.t(), Integer.t()) :: Jason.OrderedObject.t()
|
||||
def followers(domain, user, total, followers_list, page, offset) when is_integer(page) and page > 0 do
|
||||
data = [
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
id: "https://#{domain}/@#{user.username}/followers?page=#{page}",
|
||||
type: "OrderedCollectionPage",
|
||||
totalItems: total,
|
||||
next: "https://#{domain}/@#{user.username}/followers?page=#{page + 1}",
|
||||
prev: "https://#{domain}/@#{user.username}/followers?page=#{page - 1}",
|
||||
partOf: "https://#{domain}/@#{user.username}/followers",
|
||||
orderedItems: followers_list
|
||||
]
|
||||
|
||||
data =
|
||||
if page <= 1 do
|
||||
Keyword.delete(data, :prev)
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
data =
|
||||
if page * offset > total do
|
||||
data
|
||||
|> Keyword.delete(:next)
|
||||
|> Keyword.delete(:prev)
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
Jason.OrderedObject.new(data)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,6 +11,7 @@ defmodule Nulla.Models.InstanceSettings do
|
|||
field :registration, :boolean, default: false
|
||||
field :max_characters, :integer, default: 5000
|
||||
field :max_upload_size, :integer, default: 50
|
||||
field :offset, :integer, default: 100
|
||||
field :public_key, :string
|
||||
field :private_key, :string
|
||||
end
|
||||
|
@ -25,6 +26,7 @@ defmodule Nulla.Models.InstanceSettings do
|
|||
:registration,
|
||||
:max_characters,
|
||||
:max_upload_size,
|
||||
:offset,
|
||||
:public_key,
|
||||
:private_key
|
||||
])
|
||||
|
@ -35,6 +37,7 @@ defmodule Nulla.Models.InstanceSettings do
|
|||
:registration,
|
||||
:max_characters,
|
||||
:max_upload_size,
|
||||
:offset,
|
||||
:public_key,
|
||||
:private_key
|
||||
])
|
||||
|
|
87
lib/nulla/utils.ex
Normal file
87
lib/nulla/utils.ex
Normal file
|
@ -0,0 +1,87 @@
|
|||
defmodule Nulla.Utils do
|
||||
import Ecto.Query
|
||||
alias Nulla.Repo
|
||||
alias Nulla.Models.User
|
||||
alias Nulla.Models.Follow
|
||||
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.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.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
|
||||
end
|
|
@ -66,9 +66,9 @@
|
|||
</dl>
|
||||
<% end %>
|
||||
<div class="flex mt-5 gap-3">
|
||||
<a href={~p"/@#{@user.username}"}>1.7K Posts</a>
|
||||
<a href={~p"/@#{@user.username}/following"}>33 Following</a>
|
||||
<a href={~p"/@#{@user.username}/followers"}>31 Followers</a>
|
||||
<a href={~p"/@#{@user.username}"}>{length(@notes)} Posts</a>
|
||||
<a href={~p"/@#{@user.username}/following"}>{@following} Following</a>
|
||||
<a href={~p"/@#{@user.username}/followers"}>{@followers} Followers</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between px-20 py-2 mt-5 border-y border-gray-300">
|
||||
|
|
65
lib/nulla_web/controllers/follow_controller.ex
Normal file
65
lib/nulla_web/controllers/follow_controller.ex
Normal file
|
@ -0,0 +1,65 @@
|
|||
defmodule NullaWeb.FollowController do
|
||||
use NullaWeb, :controller
|
||||
alias Nulla.Models.User
|
||||
alias Nulla.Models.InstanceSettings
|
||||
alias Nulla.ActivityPub
|
||||
alias Nulla.Utils
|
||||
|
||||
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)
|
||||
page =
|
||||
case Integer.parse(page_param) do
|
||||
{int, _} when int > 0 -> int
|
||||
_ -> 1
|
||||
end
|
||||
following_list = Utils.get_following_users_by_username!(user.username, page)
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> json(ActivityPub.following(domain, user, 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)
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> json(ActivityPub.following(domain, user, 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)
|
||||
page =
|
||||
case Integer.parse(page_param) do
|
||||
{int, _} when int > 0 -> int
|
||||
_ -> 1
|
||||
end
|
||||
followers_list = Utils.get_followers_by_username!(user.username, page)
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> json(ActivityPub.followers(domain, user, 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)
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/activity+json")
|
||||
|> json(ActivityPub.followers(domain, user, total))
|
||||
end
|
||||
end
|
|
@ -4,6 +4,7 @@ defmodule NullaWeb.UserController do
|
|||
alias Nulla.Models.Note
|
||||
alias Nulla.Models.InstanceSettings
|
||||
alias Nulla.ActivityPub
|
||||
alias Nulla.Utils
|
||||
|
||||
def show(conn, %{"username" => username}) do
|
||||
accept = List.first(get_req_header(conn, "accept"))
|
||||
|
@ -17,7 +18,19 @@ defmodule NullaWeb.UserController do
|
|||
|> put_resp_content_type("application/activity+json")
|
||||
|> json(ActivityPub.user(domain, user))
|
||||
else
|
||||
render(conn, :show, domain: domain, user: user, notes: notes, layout: false)
|
||||
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
|
||||
|
|
|
@ -22,6 +22,8 @@ defmodule NullaWeb.Router do
|
|||
pipe_through :browser
|
||||
|
||||
get "/@:username", UserController, :show
|
||||
get "/@:username/following", FollowController, :following
|
||||
get "/@:username/followers", FollowController, :followers
|
||||
get "/@:username/:note_id", NoteController, :show
|
||||
end
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ defmodule Nulla.Repo.Migrations.CreateInstanceSettings do
|
|||
add :registration, :boolean, default: false, null: false
|
||||
add :max_characters, :integer, default: 5000, null: false
|
||||
add :max_upload_size, :integer, default: 50, null: false
|
||||
add :offset, :integer, default: 100, null: false
|
||||
add :public_key, :string
|
||||
add :private_key, :string
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue