Add user hashtag follow/unfollow functions

This commit is contained in:
FloatingGhost 2022-12-04 00:33:23 +00:00
parent ec6bf8c3f7
commit cb889a1539
5 changed files with 156 additions and 0 deletions

View file

@ -18,6 +18,8 @@ defmodule Pleroma.User do
alias Pleroma.Emoji alias Pleroma.Emoji
alias Pleroma.FollowingRelationship alias Pleroma.FollowingRelationship
alias Pleroma.Formatter alias Pleroma.Formatter
alias Pleroma.Hashtag
alias Pleroma.User.HashtagFollow
alias Pleroma.HTML alias Pleroma.HTML
alias Pleroma.Keys alias Pleroma.Keys
alias Pleroma.MFA alias Pleroma.MFA
@ -168,6 +170,12 @@ defmodule Pleroma.User do
has_many(:frontend_profiles, Pleroma.Akkoma.FrontendSettingsProfile) has_many(:frontend_profiles, Pleroma.Akkoma.FrontendSettingsProfile)
many_to_many(:followed_hashtags, Hashtag,
on_replace: :delete,
on_delete: :delete_all,
join_through: HashtagFollow
)
for {relationship_type, for {relationship_type,
[ [
{outgoing_relation, outgoing_relation_target}, {outgoing_relation, outgoing_relation_target},
@ -2550,4 +2558,24 @@ defmodule Pleroma.User do
_ -> {:error, user} _ -> {:error, user}
end end
end end
def hashtag_follows(%User{} = user) do
HashtagFollow
|> where(user_id: ^user.id)
|> Repo.all()
end
def follow_hashtag(%User{} = user, %Hashtag{} = hashtag) do
Logger.debug("Follow hashtag #{hashtag.name} for user #{user.nickname}")
HashtagFollow.new(user, hashtag)
end
def unfollow_hashtag(%User{} = user, %Hashtag{} = hashtag) do
Logger.debug("Unfollow hashtag #{hashtag.name} for user #{user.nickname}")
from(hf in HashtagFollow)
|> where([hf], hf.user_id == ^user.id and hf.hashtag_id == ^hashtag.id)
|> Repo.delete_all()
end
end end

View file

@ -0,0 +1,29 @@
defmodule Pleroma.User.HashtagFollow do
use Ecto.Schema
import Ecto.Changeset
alias Pleroma.User
alias Pleroma.Hashtag
alias Pleroma.Repo
schema "user_follows_hashtag" do
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
belongs_to(:hashtag, Hashtag)
end
def changeset(%__MODULE__{} = user_hashtag_follow, attrs) do
user_hashtag_follow
|> cast(attrs, [:user_id, :hashtag_id])
|> unique_constraint(:hashtag_id,
name: :user_hashtag_follows_user_id_hashtag_id_index,
message: "already following"
)
|> validate_required([:user_id, :hashtag_id])
end
def new(%User{} = user, %Hashtag{} = hashtag) do
%__MODULE__{}
|> changeset(%{user_id: user.id, hashtag_id: hashtag.id})
|> Repo.insert(on_conflict: :nothing)
end
end

View file

@ -0,0 +1,12 @@
defmodule Pleroma.Repo.Migrations.AddUserFollowsHashtag do
use Ecto.Migration
def change do
create table(:user_follows_hashtag) do
add(:hashtag_id, references(:hashtags))
add(:user_id, references(:users, type: :uuid, on_delete: :delete_all))
end
create(unique_index(:user_follows_hashtag, [:user_id, :hashtag_id]))
end
end

View file

@ -2679,4 +2679,84 @@ defmodule Pleroma.UserTest do
assert user.ap_id in user3_updated.also_known_as assert user.ap_id in user3_updated.also_known_as
end end
end end
describe "follow_hashtag/2" do
test "should follow a hashtag" do
user = insert(:user)
hashtag = insert(:hashtag)
assert {:ok, _} = user |> User.follow_hashtag(hashtag)
user =
User.get_cached_by_ap_id(user.ap_id)
|> Repo.preload(:followed_hashtags)
assert user.followed_hashtags |> length() == 1
assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
end
test "should not follow a hashtag twice" do
user = insert(:user)
hashtag = insert(:hashtag)
assert {:ok, _} = user |> User.follow_hashtag(hashtag)
assert {:ok, _} = user |> User.follow_hashtag(hashtag)
user =
User.get_cached_by_ap_id(user.ap_id)
|> Repo.preload(:followed_hashtags)
assert user.followed_hashtags |> length() == 1
assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
end
test "can follow multiple hashtags" do
user = insert(:user)
hashtag = insert(:hashtag)
other_hashtag = insert(:hashtag)
assert {:ok, _} = user |> User.follow_hashtag(hashtag)
assert {:ok, _} = user |> User.follow_hashtag(other_hashtag)
user =
User.get_cached_by_ap_id(user.ap_id)
|> Repo.preload(:followed_hashtags)
assert user.followed_hashtags |> length() == 2
assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
assert other_hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end)
end
end
describe "unfollow_hashtag/2" do
test "should unfollow a hashtag" do
user = insert(:user)
hashtag = insert(:hashtag)
assert {:ok, _} = user |> User.follow_hashtag(hashtag)
assert {1, nil} = user |> User.unfollow_hashtag(hashtag)
user =
User.get_cached_by_ap_id(user.ap_id)
|> Repo.preload(:followed_hashtags)
assert user.followed_hashtags |> length() == 0
end
test "should not error when trying to unfollow a hashtag twice" do
user = insert(:user)
hashtag = insert(:hashtag)
assert {:ok, _} = user |> User.follow_hashtag(hashtag)
assert {1, nil} = user |> User.unfollow_hashtag(hashtag)
assert {0, nil} = user |> User.unfollow_hashtag(hashtag)
user =
User.get_cached_by_ap_id(user.ap_id)
|> Repo.preload(:followed_hashtags)
assert user.followed_hashtags |> length() == 0
end
end
end end

View file

@ -716,4 +716,11 @@ defmodule Pleroma.Factory do
user: user user: user
} }
end end
def hashtag_factory(params \\ %{}) do
%Pleroma.Hashtag{
name: "test #{sequence(:hashtag_name, & &1)}"
}
|> Map.merge(params)
end
end end