Add user hashtag follow/unfollow functions
This commit is contained in:
parent
ec6bf8c3f7
commit
cb889a1539
5 changed files with 156 additions and 0 deletions
|
@ -18,6 +18,8 @@ defmodule Pleroma.User do
|
|||
alias Pleroma.Emoji
|
||||
alias Pleroma.FollowingRelationship
|
||||
alias Pleroma.Formatter
|
||||
alias Pleroma.Hashtag
|
||||
alias Pleroma.User.HashtagFollow
|
||||
alias Pleroma.HTML
|
||||
alias Pleroma.Keys
|
||||
alias Pleroma.MFA
|
||||
|
@ -168,6 +170,12 @@ defmodule Pleroma.User do
|
|||
|
||||
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,
|
||||
[
|
||||
{outgoing_relation, outgoing_relation_target},
|
||||
|
@ -2550,4 +2558,24 @@ def update_last_status_at(user) do
|
|||
_ -> {:error, user}
|
||||
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
|
||||
|
|
29
lib/pleroma/user/hashtag_follow.ex
Normal file
29
lib/pleroma/user/hashtag_follow.ex
Normal 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
|
|
@ -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
|
|
@ -2679,4 +2679,84 @@ test "should report error on non-existing alias" do
|
|||
assert user.ap_id in user3_updated.also_known_as
|
||||
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
|
||||
|
|
|
@ -716,4 +716,11 @@ def delivery_factory(params \\ %{}) do
|
|||
user: user
|
||||
}
|
||||
end
|
||||
|
||||
def hashtag_factory(params \\ %{}) do
|
||||
%Pleroma.Hashtag{
|
||||
name: "test #{sequence(:hashtag_name, & &1)}"
|
||||
}
|
||||
|> Map.merge(params)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue