diff --git a/lib/pleroma/hashtag.ex b/lib/pleroma/hashtag.ex index 53e2e9c89..303bf517a 100644 --- a/lib/pleroma/hashtag.ex +++ b/lib/pleroma/hashtag.ex @@ -27,6 +27,10 @@ defmodule Pleroma.Hashtag do |> String.trim() end + def get_by_id(id) do + Repo.get(Hashtag, id) + end + def get_or_create_by_name(name) do changeset = changeset(%Hashtag{}, %{name: name}) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c8e43a606..5f16b1d52 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2559,23 +2559,40 @@ defmodule Pleroma.User do end end - def hashtag_follows(%User{} = user) do - HashtagFollow - |> where(user_id: ^user.id) - |> Repo.all() + defp maybe_load_followed_hashtags(%User{followed_hashtags: follows} = user) + when is_list(follows), + do: user + + defp maybe_load_followed_hashtags(%User{} = user) do + followed_hashtags = HashtagFollow.get_by_user(user) + %{user | followed_hashtags: followed_hashtags} end def follow_hashtag(%User{} = user, %Hashtag{} = hashtag) do Logger.debug("Follow hashtag #{hashtag.name} for user #{user.nickname}") + user = maybe_load_followed_hashtags(user) - HashtagFollow.new(user, hashtag) + with {:ok, _} <- HashtagFollow.new(user, hashtag), + follows <- HashtagFollow.get_by_user(user), + %User{} = user <- user |> Map.put(:followed_hashtags, follows) do + user + |> set_cache() + end end def unfollow_hashtag(%User{} = user, %Hashtag{} = hashtag) do Logger.debug("Unfollow hashtag #{hashtag.name} for user #{user.nickname}") + user = maybe_load_followed_hashtags(user) - from(hf in HashtagFollow) - |> where([hf], hf.user_id == ^user.id and hf.hashtag_id == ^hashtag.id) - |> Repo.delete_all() + with {_, nil} <- HashtagFollow.delete(user, hashtag), + follows <- HashtagFollow.get_by_user(user), + %User{} = user <- user |> Map.put(:followed_hashtags, follows) do + user + |> set_cache() + end + end + + def following_hashtag?(%User{} = user, %Hashtag{} = hashtag) do + not is_nil(HashtagFollow.get(user, hashtag)) end end diff --git a/lib/pleroma/user/hashtag_follow.ex b/lib/pleroma/user/hashtag_follow.ex index 421493fe6..2fb9006ec 100644 --- a/lib/pleroma/user/hashtag_follow.ex +++ b/lib/pleroma/user/hashtag_follow.ex @@ -1,5 +1,6 @@ defmodule Pleroma.User.HashtagFollow do use Ecto.Schema + import Ecto.Query import Ecto.Changeset alias Pleroma.User @@ -26,4 +27,20 @@ defmodule Pleroma.User.HashtagFollow do |> changeset(%{user_id: user.id, hashtag_id: hashtag.id}) |> Repo.insert(on_conflict: :nothing) end + + def delete(%User{} = user, %Hashtag{} = hashtag) do + get(user, hashtag) + |> Repo.delete() + end + + def get(%User{} = user, %Hashtag{} = hashtag) do + from(hf in __MODULE__) + |> where([hf], hf.user_id == ^user.id and hf.hashtag_id == ^hashtag.id) + |> Repo.one() + end + + def get_by_user(%User{} = user) do + Ecto.assoc(user, :followed_hashtags) + |> Repo.all() + end end diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index bf8dc5300..db5c753d5 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -2687,11 +2687,9 @@ defmodule Pleroma.UserTest do assert {:ok, _} = user |> User.follow_hashtag(hashtag) - user = - User.get_cached_by_ap_id(user.ap_id) - |> Repo.preload(:followed_hashtags) + user = User.get_cached_by_ap_id(user.ap_id) - assert user.followed_hashtags |> length() == 1 + assert user.followed_hashtags |> Enum.count() == 1 assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) end @@ -2703,11 +2701,9 @@ defmodule Pleroma.UserTest do assert {:ok, _} = user |> User.follow_hashtag(hashtag) - user = - User.get_cached_by_ap_id(user.ap_id) - |> Repo.preload(:followed_hashtags) + user = User.get_cached_by_ap_id(user.ap_id) - assert user.followed_hashtags |> length() == 1 + assert user.followed_hashtags |> Enum.count() == 1 assert hashtag.name in Enum.map(user.followed_hashtags, fn %{name: name} -> name end) end @@ -2719,11 +2715,9 @@ defmodule Pleroma.UserTest do 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) + user = User.get_cached_by_ap_id(user.ap_id) - assert user.followed_hashtags |> length() == 2 + assert user.followed_hashtags |> Enum.count() == 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 @@ -2737,11 +2731,9 @@ defmodule Pleroma.UserTest do 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) + user = User.get_cached_by_ap_id(user.ap_id) - assert user.followed_hashtags |> length() == 0 + assert user.followed_hashtags |> Enum.count() == 0 end test "should not error when trying to unfollow a hashtag twice" do @@ -2752,11 +2744,9 @@ defmodule Pleroma.UserTest do 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) + user = User.get_cached_by_ap_id(user.ap_id) - assert user.followed_hashtags |> length() == 0 + assert user.followed_hashtags |> Enum.count() == 0 end end end