From 3a57d743571ffa899cdaeaa89396d75d20d882ed Mon Sep 17 00:00:00 2001 From: miraikumiko Date: Wed, 18 Jun 2025 06:35:58 +0200 Subject: [PATCH] Add relations --- lib/nulla/models/activity.ex | 5 +- lib/nulla/models/actor.ex | 2 +- lib/nulla/models/follow.ex | 32 ---------- lib/nulla/models/media_attachment.ex | 3 +- lib/nulla/models/moderation_log.ex | 3 +- lib/nulla/models/relation.ex | 60 ++++++++++++++----- lib/nulla/models/session.ex | 3 +- lib/nulla/models/user.ex | 2 +- lib/nulla_web/controllers/actor_controller.ex | 1 - lib/nulla_web/controllers/inbox_controller.ex | 11 ++-- .../20250615131836_create_follows.exs | 16 ----- .../20250617091354_create_relations.exs | 28 +++++---- 12 files changed, 81 insertions(+), 85 deletions(-) delete mode 100644 lib/nulla/models/follow.ex delete mode 100644 priv/repo/migrations/20250615131836_create_follows.exs diff --git a/lib/nulla/models/activity.ex b/lib/nulla/models/activity.ex index cfd208e..f2649bf 100644 --- a/lib/nulla/models/activity.ex +++ b/lib/nulla/models/activity.ex @@ -1,7 +1,8 @@ defmodule Nulla.Models.Activity do use Ecto.Schema import Ecto.Changeset - alias Nulla.SnowFlake + alias Nulla.Repo + alias Nulla.Snowflake @primary_key {:id, :integer, autogenerate: false} schema "activities" do @@ -27,7 +28,7 @@ defmodule Nulla.Models.Activity do %__MODULE__{} |> __MODULE__.changeset(attrs) - |> Ecto.Changeset.put_change(:id, id) + |> Changeset.put_change(:id, id) |> Repo.insert() end end diff --git a/lib/nulla/models/actor.ex b/lib/nulla/models/actor.ex index ace64be..d181c38 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) - |> Ecto.Changeset.put_change(:id, id) + |> Changeset.put_change(:id, id) |> Repo.insert() end diff --git a/lib/nulla/models/follow.ex b/lib/nulla/models/follow.ex deleted file mode 100644 index b976f59..0000000 --- a/lib/nulla/models/follow.ex +++ /dev/null @@ -1,32 +0,0 @@ -defmodule Nulla.Models.Follow do - use Ecto.Schema - import Ecto.Changeset - alias Nulla.Repo - alias Nulla.Snowflake - alias Nulla.Models.Actor - - @primary_key {:id, :integer, autogenerate: false} - schema "follows" do - belongs_to :follower, Actor - belongs_to :followed, Actor - - timestamps() - end - - @doc false - def changeset(follow, attrs) do - follow - |> cast(attrs, [:user_id, :target_id]) - |> validate_required([:user_id, :target_id]) - |> unique_constraint([:user_id, :target_id]) - end - - def create_follow(attrs) do - id = Snowflake.next_id() - - %__MODULE__{} - |> __MODULE__.changeset(attrs) - |> Ecto.Changeset.put_change(:id, id) - |> Repo.insert() - end -end diff --git a/lib/nulla/models/media_attachment.ex b/lib/nulla/models/media_attachment.ex index bafed6f..97efee3 100644 --- a/lib/nulla/models/media_attachment.ex +++ b/lib/nulla/models/media_attachment.ex @@ -1,6 +1,7 @@ defmodule Nulla.Models.MediaAttachment do use Ecto.Schema import Ecto.Changeset + alias Nulla.Models.Note @primary_key {:id, :integer, autogenerate: false} schema "media_attachments" do @@ -8,7 +9,7 @@ defmodule Nulla.Models.MediaAttachment do field :mime_type, :string field :description, :string - belongs_to :note, Nulla.Models.Note + belongs_to :note, Note timestamps(type: :utc_datetime) end diff --git a/lib/nulla/models/moderation_log.ex b/lib/nulla/models/moderation_log.ex index 7e30af1..1a62b71 100644 --- a/lib/nulla/models/moderation_log.ex +++ b/lib/nulla/models/moderation_log.ex @@ -1,6 +1,7 @@ defmodule Nulla.Models.ModerationLog do use Ecto.Schema import Ecto.Changeset + alias Nulla.Models.User @primary_key {:id, :integer, autogenerate: false} schema "moderation_logs" do @@ -10,7 +11,7 @@ defmodule Nulla.Models.ModerationLog do field :reason, :string field :metadata, :map - belongs_to :moderator, Nulla.Models.User + belongs_to :moderator, User timestamps() end diff --git a/lib/nulla/models/relation.ex b/lib/nulla/models/relation.ex index 4b80963..7d05339 100644 --- a/lib/nulla/models/relation.ex +++ b/lib/nulla/models/relation.ex @@ -1,30 +1,62 @@ defmodule Nulla.Models.Relation do use Ecto.Schema import Ecto.Changeset + alias Nulla.Repo + alias Nulla.Snowflake alias Nulla.Models.Actor - alias Nulla.Models.Activity @primary_key {:id, :integer, autogenerate: false} + @foreign_key_type :integer schema "relations" do - field :type, :string - field :status, :string + field :following, :boolean, default: false + field :followed_by, :boolean, default: false + field :showing_replies, :boolean, default: true + field :showing_reblogs, :boolean, default: true + field :notifying, :boolean, default: false + field :muting, :boolean, default: false + field :muting_notifications, :boolean, default: false + field :blocking, :boolean, default: false + field :blocked_by, :boolean, default: false + field :domain_blocking, :boolean, default: false + field :requested, :boolean, default: false + field :note, :string - belongs_to :source, Actor, foreign_key: :source_id, type: :integer - belongs_to :target, Actor, foreign_key: :target_id, type: :integer - belongs_to :activity, Activity, foreign_key: :activity_id, type: :integer + belongs_to :local_actor_id, Actor + belongs_to :remote_actor_id, Actor timestamps() end + @doc false def changeset(relation, attrs) do relation - |> cast(attrs, [:id, :source_id, :target_id, :type, :status, :activity_id]) - |> validate_required([:id, :source_id, :target_id, :type]) - |> validate_inclusion(:type, ~w(follow block mute friend_request)) - |> validate_inclusion(:status, ~w(pending accepted rejected active)) - |> foreign_key_constraint(:source_id) - |> foreign_key_constraint(:target_id) - |> foreign_key_constraint(:activity_id) - |> unique_constraint([:source_id, :target_id, :type]) + |> cast(attrs, [ + :id, + :following, + :followed_by, + :showing_replies, + :showing_reblogs, + :notifying, + :muting, + :muting_notifications, + :blocking, + :blocked_by, + :domain_blocking, + :requested, + :note, + :source_id, + :target_id + ]) + |> validate_required([:id, :local_actor_id, :remote_actor_id]) + |> unique_constraint([:local_actor_id, :remote_actor_id]) end + + def create_relation(attrs) do + id = Snowflake.next_id() + + %__MODULE__{} + |> __MODULE__.changeset(attrs) + |> Changeset.put_change(:id, id) + |> Repo.insert() + end end diff --git a/lib/nulla/models/session.ex b/lib/nulla/models/session.ex index 0eb45b7..9058f6a 100644 --- a/lib/nulla/models/session.ex +++ b/lib/nulla/models/session.ex @@ -1,6 +1,7 @@ defmodule Nulla.Models.Session do use Ecto.Schema import Ecto.Changeset + alias Nulla.Models.User @primary_key {:id, :integer, autogenerate: false} schema "sessions" do @@ -8,7 +9,7 @@ defmodule Nulla.Models.Session do field :user_agent, :string field :ip, :string - belongs_to :user, Nulla.Models.User + belongs_to :user, User timestamps(type: :utc_datetime) end diff --git a/lib/nulla/models/user.ex b/lib/nulla/models/user.ex index 2d7742e..9d5966d 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 - |> Ecto.Changeset.change(last_active_at: DateTime.utc_now()) + |> Changeset.change(last_active_at: DateTime.utc_now()) |> Repo.update() end end diff --git a/lib/nulla_web/controllers/actor_controller.ex b/lib/nulla_web/controllers/actor_controller.ex index e3c55ea..e497888 100644 --- a/lib/nulla_web/controllers/actor_controller.ex +++ b/lib/nulla_web/controllers/actor_controller.ex @@ -1,7 +1,6 @@ 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 diff --git a/lib/nulla_web/controllers/inbox_controller.ex b/lib/nulla_web/controllers/inbox_controller.ex index fd0d7a8..0f63a9b 100644 --- a/lib/nulla_web/controllers/inbox_controller.ex +++ b/lib/nulla_web/controllers/inbox_controller.ex @@ -5,6 +5,7 @@ defmodule NullaWeb.InboxController do alias Nulla.Utils alias Nulla.Models.Actor alias Nulla.Models.Relation + alias Nulla.Models.Activity def inbox( conn, @@ -24,19 +25,19 @@ defmodule NullaWeb.InboxController do Activity.create_activity(%{ ap_id: follow_id, type: "Follow", - actor: actor_uri, + actor: remote_actor.id, object: target_uri }), accept_activity <- Activity.create_activity(%{ type: "Accept", - actor: target_uri, + actor: target_actor.id, object: follow_activity }), relation <- Relation.create_relation(%{ - id: 1, - follower: remote_actor.id, - followed: target_actor.id + followed_by: true, + local_actor_id: target_actor.id, + remote_actor_id: remote_actor.id }) do conn |> put_resp_content_type("application/activity+json") diff --git a/priv/repo/migrations/20250615131836_create_follows.exs b/priv/repo/migrations/20250615131836_create_follows.exs deleted file mode 100644 index c12b6ba..0000000 --- a/priv/repo/migrations/20250615131836_create_follows.exs +++ /dev/null @@ -1,16 +0,0 @@ -defmodule Nulla.Repo.Migrations.CreateFollows do - use Ecto.Migration - - def change do - create table(:follows, primary_key: false) do - add :id, :bigint, primary_key: true - add :follower_id, references(:actors, on_delete: :delete_all), null: false - add :following_id, references(:actors, on_delete: :delete_all), null: false - - timestamps() - end - - create unique_index(:follows, [:follower_id, :following_id]) - create index(:follows, [:following_id]) - end -end diff --git a/priv/repo/migrations/20250617091354_create_relations.exs b/priv/repo/migrations/20250617091354_create_relations.exs index b4c66bf..55b7012 100644 --- a/priv/repo/migrations/20250617091354_create_relations.exs +++ b/priv/repo/migrations/20250617091354_create_relations.exs @@ -4,20 +4,28 @@ defmodule Nulla.Repo.Migrations.CreateActorRelations do def change do create table(:relations, primary_key: false) do add :id, :bigint, primary_key: true - add :source_id, :bigint, null: false - add :target_id, :bigint, null: false - add :type, :string, null: false - add :status, :string, null: false - add :activity_id, :bigint + add :following, :boolean, null: false, default: false + add :followed_by, :boolean, null: false, default: false + add :showing_replies, :boolean, null: false, default: true + add :showing_reblogs, :boolean, null: false, default: true + add :notifying, :boolean, null: false, default: false + add :muting, :boolean, null: false, default: false + add :muting_notifications, :boolean, null: false, default: false + add :blocking, :boolean, null: false, default: false + add :blocked_by, :boolean, null: false, default: false + add :domain_blocking, :boolean, null: false, default: false + add :requested, :boolean, null: false, default: false + add :note, :string + + add :local_actor_id, references(:actors, type: :bigint), null: false + add :remote_actor_id, references(:actors, type: :bigint), null: false timestamps() end - create index(:relations, [:source_id]) - create index(:relations, [:target_id]) - create index(:relations, [:type]) - create index(:relations, [:activity_id]) + create index(:relations, [:local_actor_id]) + create index(:relations, [:remote_actor_id]) - create unique_index(:relations, [:source_id, :target_id, :type]) + create unique_index(:relations, [:local_actor_id, :remote_actor_id]) end end