diff --git a/lib/nulla/activitypub.ex b/lib/nulla/activitypub.ex
index 16183a4..838aae4 100644
--- a/lib/nulla/activitypub.ex
+++ b/lib/nulla/activitypub.ex
@@ -1,4 +1,9 @@
defmodule Nulla.ActivityPub do
+ alias Nulla.Models.Actor
+ alias Nulla.Models.Activity
+ alias Nulla.Models.Note
+ alias Nulla.Models.InstanceSettings
+
@spec context() :: list()
defp context do
[
@@ -25,7 +30,7 @@ defmodule Nulla.ActivityPub do
]
end
- @spec actor(Nulla.Models.Actor.t()) :: Jason.OrderedObject.t()
+ @spec actor(Actor.t()) :: Jason.OrderedObject.t()
def actor(actor) do
Jason.OrderedObject.new(
"@context": context(),
@@ -57,7 +62,7 @@ defmodule Nulla.ActivityPub do
)
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
attachment =
case note.media_attachments do
@@ -102,7 +107,7 @@ defmodule Nulla.ActivityPub do
)
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
Jason.OrderedObject.new(
"@context": "https://www.w3.org/ns/activitystreams",
@@ -113,35 +118,28 @@ defmodule Nulla.ActivityPub do
)
end
- @spec following(String.t(), Nulla.Models.Actor.t(), Integer.t()) :: Jason.OrderedObject.t()
- def following(domain, actor, total) do
+ @spec following(Actor.t(), Integer.t()) :: Jason.OrderedObject.t()
+ def following(actor, total) do
Jason.OrderedObject.new(
"@context": "https://www.w3.org/ns/activitystreams",
- id: "https://#{domain}/users/#{actor.preferredUsername}/following",
+ id: "https://#{actor.domain}/users/#{actor.preferredUsername}/following",
type: "OrderedCollection",
totalItems: total,
- first: "https://#{domain}/users/#{actor.preferredUsername}/following?page=1"
+ first: "https://#{actor.domain}/users/#{actor.preferredUsername}/following?page=1"
)
end
- @spec following(
- String.t(),
- Nulla.Models.Actor.t(),
- 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
+ @spec following(Actor.t(), Integer.t(), List.t(), Integer.t(), Integer.t()) ::
+ Jason.OrderedObject.t()
+ def following(actor, total, following_list, page, limit) when is_integer(page) and page > 0 do
data = [
"@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",
totalItems: total,
- next: "https://#{domain}/users/#{actor.preferredUsername}/following?page=#{page + 1}",
- prev: "https://#{domain}/users/#{actor.preferredUsername}/following?page=#{page - 1}",
- partOf: "https://#{domain}/users/#{actor.preferredUsername}/following",
+ next: "https://#{actor.domain}/users/#{actor.preferredUsername}/following?page=#{page + 1}",
+ prev: "https://#{actor.domain}/users/#{actor.preferredUsername}/following?page=#{page - 1}",
+ partOf: "https://#{actor.domain}/users/#{actor.preferredUsername}/following",
orderedItems: following_list
]
@@ -153,7 +151,7 @@ defmodule Nulla.ActivityPub do
end
data =
- if page * offset > total do
+ if page * limit > total do
data
|> Keyword.delete(:next)
|> Keyword.delete(:prev)
@@ -164,35 +162,29 @@ defmodule Nulla.ActivityPub do
Jason.OrderedObject.new(data)
end
- @spec followers(String.t(), Nulla.Models.Actor.t(), Integer.t()) :: Jason.OrderedObject.t()
- def followers(domain, actor, total) do
+ @spec followers(Actor.t(), Integer.t()) :: Jason.OrderedObject.t()
+ def followers(actor, total) do
Jason.OrderedObject.new(
"@context": "https://www.w3.org/ns/activitystreams",
- id: "https://#{domain}/users/#{actor.preferredUsername}/followers",
+ id: "https://#{actor.domain}/users/#{actor.preferredUsername}/followers",
type: "OrderedCollection",
totalItems: total,
- first: "https://#{domain}/users/#{actor.preferredUsername}/followers?page=1"
+ first: "https://#{actor.domain}/users/#{actor.preferredUsername}/followers?page=1"
)
end
- @spec followers(
- String.t(),
- Nulla.Models.Actor.t(),
- Integer.t(),
- List.t(),
- Integer.t(),
- Integer.t()
- ) :: Jason.OrderedObject.t()
- def followers(domain, actor, total, followers_list, page, offset)
+ @spec followers(Actor.t(), Integer.t(), List.t(), Integer.t(), Integer.t()) ::
+ Jason.OrderedObject.t()
+ def followers(actor, total, followers_list, page, limit)
when is_integer(page) and page > 0 do
data = [
"@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",
totalItems: total,
- next: "https://#{domain}/users/#{actor.preferredUsername}/followers?page=#{page + 1}",
- prev: "https://#{domain}/users/#{actor.preferredUsername}/followers?page=#{page - 1}",
- partOf: "https://#{domain}/users/#{actor.preferredUsername}/followers",
+ next: "https://#{actor.domain}/users/#{actor.preferredUsername}/followers?page=#{page + 1}",
+ prev: "https://#{actor.domain}/users/#{actor.preferredUsername}/followers?page=#{page - 1}",
+ partOf: "https://#{actor.domain}/users/#{actor.preferredUsername}/followers",
orderedItems: followers_list
]
@@ -204,7 +196,7 @@ defmodule Nulla.ActivityPub do
end
data =
- if page * offset > total do
+ if page * limit > total do
data
|> Keyword.delete(:next)
|> Keyword.delete(:prev)
@@ -215,7 +207,7 @@ defmodule Nulla.ActivityPub do
Jason.OrderedObject.new(data)
end
- @spec webfinger(Nulla.Models.Actor.t()) :: Jason.OrderedObject.t()
+ @spec webfinger(Actor.t()) :: Jason.OrderedObject.t()
def webfinger(actor) do
Jason.OrderedObject.new(
subject: "#{actor.preferredUsername}@#{actor.domain}",
@@ -255,8 +247,7 @@ defmodule Nulla.ActivityPub do
)
end
- @spec nodeinfo(String.t(), Map.t(), Nulla.Models.InstanceSettings.t()) ::
- Jason.OrderedObject.t()
+ @spec nodeinfo(String.t(), Map.t(), InstanceSettings.t()) :: Jason.OrderedObject.t()
def nodeinfo(version, users, instance) do
Jason.OrderedObject.new(
version: "2.0",
@@ -323,7 +314,7 @@ defmodule Nulla.ActivityPub do
)
end
- @spec activity_note(Nulla.Models.Note.t()) :: Jason.OrderedObject.t()
+ @spec activity_note(Note.t()) :: Jason.OrderedObject.t()
def activity_note(note) do
Jason.OrderedObject.new(
id:
@@ -349,7 +340,7 @@ defmodule Nulla.ActivityPub do
)
end
- @spec follow_accept(Nulla.Models.Activity.t()) :: Jason.OrderedObject.t()
+ @spec follow_accept(Activity.t()) :: Jason.OrderedObject.t()
def follow_accept(activity) do
Jason.OrderedObject.new(
"@context": "https://www.w3.org/ns/activitystreams",
diff --git a/lib/nulla/models/activity.ex b/lib/nulla/models/activity.ex
index f2649bf..f752917 100644
--- a/lib/nulla/models/activity.ex
+++ b/lib/nulla/models/activity.ex
@@ -28,7 +28,7 @@ defmodule Nulla.Models.Activity do
%__MODULE__{}
|> __MODULE__.changeset(attrs)
- |> Changeset.put_change(:id, id)
+ |> put_change(:id, id)
|> Repo.insert()
end
end
diff --git a/lib/nulla/models/actor.ex b/lib/nulla/models/actor.ex
index d181c38..8db516e 100644
--- a/lib/nulla/models/actor.ex
+++ b/lib/nulla/models/actor.ex
@@ -106,7 +106,7 @@ defmodule Nulla.Models.Actor do
%__MODULE__{}
|> changeset(attrs)
- |> Changeset.put_change(:id, id)
+ |> put_change(:id, id)
|> Repo.insert()
end
diff --git a/lib/nulla/models/instance_settings.ex b/lib/nulla/models/instance_settings.ex
index 0a2f38f..37ffe88 100644
--- a/lib/nulla/models/instance_settings.ex
+++ b/lib/nulla/models/instance_settings.ex
@@ -11,7 +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 :api_offset, :integer, default: 100
+ field :api_limit, :integer, default: 100
field :public_key, :string
field :private_key, :string
end
@@ -26,7 +26,7 @@ defmodule Nulla.Models.InstanceSettings do
:registration,
:max_characters,
:max_upload_size,
- :api_offset,
+ :api_limit,
:public_key,
:private_key
])
@@ -37,7 +37,7 @@ defmodule Nulla.Models.InstanceSettings do
:registration,
:max_characters,
:max_upload_size,
- :api_offset,
+ :api_limit,
:public_key,
:private_key
])
diff --git a/lib/nulla/models/relation.ex b/lib/nulla/models/relation.ex
index 7d05339..3799af9 100644
--- a/lib/nulla/models/relation.ex
+++ b/lib/nulla/models/relation.ex
@@ -1,6 +1,7 @@
defmodule Nulla.Models.Relation do
use Ecto.Schema
import Ecto.Changeset
+ import Ecto.Query
alias Nulla.Repo
alias Nulla.Snowflake
alias Nulla.Models.Actor
@@ -21,8 +22,8 @@ defmodule Nulla.Models.Relation do
field :requested, :boolean, default: false
field :note, :string
- belongs_to :local_actor_id, Actor
- belongs_to :remote_actor_id, Actor
+ belongs_to :local_actor, Actor
+ belongs_to :remote_actor, Actor
timestamps()
end
@@ -44,19 +45,65 @@ defmodule Nulla.Models.Relation do
:domain_blocking,
:requested,
:note,
- :source_id,
- :target_id
+ :local_actor_id,
+ :remote_actor_id
])
|> validate_required([:id, :local_actor_id, :remote_actor_id])
|> unique_constraint([:local_actor_id, :remote_actor_id])
end
- def create_relation(attrs) do
+ def create_relation(attrs) do
id = Snowflake.next_id()
%__MODULE__{}
|> __MODULE__.changeset(attrs)
- |> Changeset.put_change(:id, id)
+ |> put_change(:id, id)
|> 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
diff --git a/lib/nulla/models/user.ex b/lib/nulla/models/user.ex
index 9d5966d..7766afe 100644
--- a/lib/nulla/models/user.ex
+++ b/lib/nulla/models/user.ex
@@ -69,7 +69,7 @@ defmodule Nulla.Models.User do
def update_last_active(user) do
user
- |> Changeset.change(last_active_at: DateTime.utc_now())
+ |> change(last_active_at: DateTime.utc_now())
|> Repo.update()
end
end
diff --git a/lib/nulla/utils.ex b/lib/nulla/utils.ex
index fc788c0..4e74f08 100644
--- a/lib/nulla/utils.ex
+++ b/lib/nulla/utils.ex
@@ -1,102 +1,16 @@
defmodule Nulla.Utils do
- import Ecto.Query
- alias Nulla.Repo
- alias Nulla.Models.User
- alias Nulla.Models.Follow
+ alias Nulla.Models.Actor
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
case URI.parse(uri).path do
"/@" <> username ->
instance_settings = InstanceSettings.get_instance_settings!()
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}
- user -> {:ok, user}
+ user -> user
end
_ ->
@@ -110,7 +24,7 @@ defmodule Nulla.Utils do
{"Accept", "application/activity+json"}
])
- case Finch.request(request, MyApp.Finch) do
+ case Finch.request(request, Finch) do
{:ok, %Finch.Response{status: 200, body: body}} ->
case Jason.decode(body) do
{:ok, data} -> {:ok, data}
diff --git a/lib/nulla_web/components/templates.ex b/lib/nulla_web/components/templates.ex
index 817fa17..6a61d9b 100644
--- a/lib/nulla_web/components/templates.ex
+++ b/lib/nulla_web/components/templates.ex
@@ -18,33 +18,37 @@ defmodule NullaWeb.ActorHTML do
def format_registration_date(date) do
now = Date.utc_today()
formatted = Date.to_string(date) |> String.replace("-", "/")
-
+
diff_days = Date.diff(now, date)
-
+
cond do
diff_days == 0 ->
"#{formatted} (today)"
-
+
diff_days == 1 ->
"#{formatted} (1 day ago)"
-
+
diff_days < 30 ->
"#{formatted} (#{diff_days} days ago)"
-
+
diff_days < 365 ->
year_diff = now.year - date.year
month_diff = now.month - date.month
day_correction = if now.day < date.day, do: -1, else: 0
months = year_diff * 12 + month_diff + day_correction
+
if months == 1 do
"#{formatted} (1 month ago)"
else
"#{formatted} (#{months} months ago)"
end
-
+
true ->
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
"#{formatted} (1 year ago)"
else
diff --git a/lib/nulla_web/components/templates/actor/show.html.heex b/lib/nulla_web/components/templates/actor/show.html.heex
index fb5fedf..76d3f63 100644
--- a/lib/nulla_web/components/templates/actor/show.html.heex
+++ b/lib/nulla_web/components/templates/actor/show.html.heex
@@ -19,7 +19,8 @@