Update
This commit is contained in:
parent
3a57d74357
commit
df548a4943
12 changed files with 137 additions and 179 deletions
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
])
|
])
|
||||||
|
|
|
@ -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,19 +45,65 @@ 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])
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_relation(attrs) do
|
def create_relation(attrs) do
|
||||||
id = Snowflake.next_id()
|
id = Snowflake.next_id()
|
||||||
|
|
||||||
%__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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,14 +31,15 @@ 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(%{
|
_ <-
|
||||||
followed_by: true,
|
Relation.create_relation(%{
|
||||||
local_actor_id: target_actor.id,
|
followed_by: true,
|
||||||
remote_actor_id: remote_actor.id
|
local_actor_id: local_actor.id,
|
||||||
}) do
|
remote_actor_id: remote_actor.id
|
||||||
|
}) do
|
||||||
conn
|
conn
|
||||||
|> put_resp_content_type("application/activity+json")
|
|> put_resp_content_type("application/activity+json")
|
||||||
|> send_resp(
|
|> send_resp(
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue