summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorlain <lain@soykaf.club>2025-02-22 12:26:18 +0000
committerlain <lain@soykaf.club>2025-02-22 12:26:18 +0000
commit801a2256f41778754f9b1e40f2681ebda5d4b5d1 (patch)
treedea7efd4710f2803147bd19c8b6f8643bf298f8c /test
parentfe3c72f7a278fe3db822faaf5428a004833436aa (diff)
parentaa74c87443230921aadf6022b13eb9e44a031d95 (diff)
downloadpleroma-801a2256f41778754f9b1e40f2681ebda5d4b5d1.tar.gz
pleroma-801a2256f41778754f9b1e40f2681ebda5d4b5d1.zip
Merge branch 'follow-hashtags' into 'develop'
Hashtag following (from Akkoma) See merge request pleroma/pleroma!4307
Diffstat (limited to 'test')
-rw-r--r--test/mix/tasks/pleroma/database_test.exs2
-rw-r--r--test/pleroma/user_test.exs70
-rw-r--r--test/pleroma/web/activity_pub/activity_pub_test.exs27
-rw-r--r--test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs159
-rw-r--r--test/pleroma/web/streamer_test.exs30
-rw-r--r--test/support/factory.ex7
6 files changed, 294 insertions, 1 deletions
diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs
index 96a925528..38ed096ae 100644
--- a/test/mix/tasks/pleroma/database_test.exs
+++ b/test/mix/tasks/pleroma/database_test.exs
@@ -411,7 +411,7 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do
["scheduled_activities"],
["schema_migrations"],
["thread_mutes"],
- # ["user_follows_hashtag"], # not in pleroma
+ ["user_follows_hashtag"],
# ["user_frontend_setting_profiles"], # not in pleroma
["user_invite_tokens"],
["user_notes"],
diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs
index 06afc0709..4a3d6bacc 100644
--- a/test/pleroma/user_test.exs
+++ b/test/pleroma/user_test.exs
@@ -2919,4 +2919,74 @@ defmodule Pleroma.UserTest do
assert [%{"verified_at" => ^verified_at}] = user.fields
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)
+
+ assert user.followed_hashtags |> Enum.count() == 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)
+
+ assert user.followed_hashtags |> Enum.count() == 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)
+
+ 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
+ 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 {:ok, _} = user |> User.unfollow_hashtag(hashtag)
+
+ user = User.get_cached_by_ap_id(user.ap_id)
+
+ assert user.followed_hashtags |> Enum.count() == 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 {:ok, _} = user |> User.unfollow_hashtag(hashtag)
+ assert {:ok, _} = user |> User.unfollow_hashtag(hashtag)
+
+ user = User.get_cached_by_ap_id(user.ap_id)
+
+ assert user.followed_hashtags |> Enum.count() == 0
+ end
+ end
end
diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs
index 72222ae88..c7adf6bba 100644
--- a/test/pleroma/web/activity_pub/activity_pub_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_test.exs
@@ -867,6 +867,33 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
end
+ describe "fetch activities for followed hashtags" do
+ test "it should return public activities that reference a given hashtag" do
+ hashtag = insert(:hashtag, name: "tenshi")
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, normally_visible} =
+ CommonAPI.post(other_user, %{status: "hello :)", visibility: "public"})
+
+ {:ok, public} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "public"})
+ {:ok, _unrelated} = CommonAPI.post(user, %{status: "dai #tensh", visibility: "public"})
+ {:ok, unlisted} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "unlisted"})
+ {:ok, _private} = CommonAPI.post(user, %{status: "maji #tenshi", visibility: "private"})
+
+ activities =
+ ActivityPub.fetch_activities([other_user.follower_address], %{
+ followed_hashtags: [hashtag.id]
+ })
+
+ assert length(activities) == 3
+ normal_id = normally_visible.id
+ public_id = public.id
+ unlisted_id = unlisted.id
+ assert [%{id: ^normal_id}, %{id: ^public_id}, %{id: ^unlisted_id}] = activities
+ end
+ end
+
describe "fetch activities in context" do
test "retrieves activities that have a given context" do
{:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "2hu"})
diff --git a/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs
new file mode 100644
index 000000000..71c8e7fc0
--- /dev/null
+++ b/test/pleroma/web/mastodon_api/controllers/tag_controller_test.exs
@@ -0,0 +1,159 @@
+defmodule Pleroma.Web.MastodonAPI.TagControllerTest do
+ use Pleroma.Web.ConnCase
+
+ import Pleroma.Factory
+ import Tesla.Mock
+
+ alias Pleroma.User
+
+ setup do
+ mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
+ describe "GET /api/v1/tags/:id" do
+ test "returns 200 with tag" do
+ %{user: user, conn: conn} = oauth_access(["read"])
+
+ tag = insert(:hashtag, name: "jubjub")
+ {:ok, _user} = User.follow_hashtag(user, tag)
+
+ response =
+ conn
+ |> get("/api/v1/tags/jubjub")
+ |> json_response_and_validate_schema(200)
+
+ assert %{
+ "name" => "jubjub",
+ "url" => "http://localhost:4001/tags/jubjub",
+ "history" => [],
+ "following" => true
+ } = response
+ end
+
+ test "returns 404 with unknown tag" do
+ %{conn: conn} = oauth_access(["read"])
+
+ conn
+ |> get("/api/v1/tags/jubjub")
+ |> json_response_and_validate_schema(404)
+ end
+ end
+
+ describe "POST /api/v1/tags/:id/follow" do
+ test "should follow a hashtag" do
+ %{user: user, conn: conn} = oauth_access(["write:follows"])
+ hashtag = insert(:hashtag, name: "jubjub")
+
+ response =
+ conn
+ |> post("/api/v1/tags/jubjub/follow")
+ |> json_response_and_validate_schema(200)
+
+ assert response["following"] == true
+ user = User.get_cached_by_ap_id(user.ap_id)
+ assert User.following_hashtag?(user, hashtag)
+ end
+
+ test "should 404 if hashtag doesn't exist" do
+ %{conn: conn} = oauth_access(["write:follows"])
+
+ response =
+ conn
+ |> post("/api/v1/tags/rubrub/follow")
+ |> json_response_and_validate_schema(404)
+
+ assert response["error"] == "Hashtag not found"
+ end
+ end
+
+ describe "POST /api/v1/tags/:id/unfollow" do
+ test "should unfollow a hashtag" do
+ %{user: user, conn: conn} = oauth_access(["write:follows"])
+ hashtag = insert(:hashtag, name: "jubjub")
+ {:ok, user} = User.follow_hashtag(user, hashtag)
+
+ response =
+ conn
+ |> post("/api/v1/tags/jubjub/unfollow")
+ |> json_response_and_validate_schema(200)
+
+ assert response["following"] == false
+ user = User.get_cached_by_ap_id(user.ap_id)
+ refute User.following_hashtag?(user, hashtag)
+ end
+
+ test "should 404 if hashtag doesn't exist" do
+ %{conn: conn} = oauth_access(["write:follows"])
+
+ response =
+ conn
+ |> post("/api/v1/tags/rubrub/unfollow")
+ |> json_response_and_validate_schema(404)
+
+ assert response["error"] == "Hashtag not found"
+ end
+ end
+
+ describe "GET /api/v1/followed_tags" do
+ test "should list followed tags" do
+ %{user: user, conn: conn} = oauth_access(["read:follows"])
+
+ response =
+ conn
+ |> get("/api/v1/followed_tags")
+ |> json_response_and_validate_schema(200)
+
+ assert Enum.empty?(response)
+
+ hashtag = insert(:hashtag, name: "jubjub")
+ {:ok, _user} = User.follow_hashtag(user, hashtag)
+
+ response =
+ conn
+ |> get("/api/v1/followed_tags")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"name" => "jubjub"}] = response
+ end
+
+ test "should include a link header to paginate" do
+ %{user: user, conn: conn} = oauth_access(["read:follows"])
+
+ for i <- 1..21 do
+ hashtag = insert(:hashtag, name: "jubjub#{i}}")
+ {:ok, _user} = User.follow_hashtag(user, hashtag)
+ end
+
+ response =
+ conn
+ |> get("/api/v1/followed_tags")
+
+ json = json_response_and_validate_schema(response, 200)
+ assert Enum.count(json) == 20
+ assert [link_header] = get_resp_header(response, "link")
+ assert link_header =~ "rel=\"next\""
+ next_link = extract_next_link_header(link_header)
+
+ response =
+ conn
+ |> get(next_link)
+ |> json_response_and_validate_schema(200)
+
+ assert Enum.count(response) == 1
+ end
+
+ test "should refuse access without read:follows scope" do
+ %{conn: conn} = oauth_access(["write"])
+
+ conn
+ |> get("/api/v1/followed_tags")
+ |> json_response_and_validate_schema(403)
+ end
+ end
+
+ defp extract_next_link_header(header) do
+ [_, next_link] = Regex.run(~r{<(?<next_link>.*)>; rel="next"}, header)
+ next_link
+ end
+end
diff --git a/test/pleroma/web/streamer_test.exs b/test/pleroma/web/streamer_test.exs
index 262ff11d2..85978e824 100644
--- a/test/pleroma/web/streamer_test.exs
+++ b/test/pleroma/web/streamer_test.exs
@@ -558,6 +558,36 @@ defmodule Pleroma.Web.StreamerTest do
assert_receive {:render_with_user, _, "status_update.json", ^create, _}
refute Streamer.filtered_by_user?(user, edited)
end
+
+ test "it streams posts containing followed hashtags on the 'user' stream", %{
+ user: user,
+ token: oauth_token
+ } do
+ hashtag = insert(:hashtag, %{name: "tenshi"})
+ other_user = insert(:user)
+ {:ok, user} = User.follow_hashtag(user, hashtag)
+
+ Streamer.get_topic_and_add_socket("user", user, oauth_token)
+ {:ok, activity} = CommonAPI.post(other_user, %{status: "hey #tenshi"})
+
+ assert_receive {:render_with_user, _, "update.json", ^activity, _}
+ end
+
+ test "should not stream private posts containing followed hashtags on the 'user' stream", %{
+ user: user,
+ token: oauth_token
+ } do
+ hashtag = insert(:hashtag, %{name: "tenshi"})
+ other_user = insert(:user)
+ {:ok, user} = User.follow_hashtag(user, hashtag)
+
+ Streamer.get_topic_and_add_socket("user", user, oauth_token)
+
+ {:ok, activity} =
+ CommonAPI.post(other_user, %{status: "hey #tenshi", visibility: "private"})
+
+ refute_receive {:render_with_user, _, "update.json", ^activity, _}
+ end
end
describe "public streams" do
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 91e5805c8..88c4ed8e5 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -668,4 +668,11 @@ defmodule Pleroma.Factory do
|> Map.merge(params)
|> Pleroma.Announcement.add_rendered_properties()
end
+
+ def hashtag_factory(params \\ %{}) do
+ %Pleroma.Hashtag{
+ name: "test #{sequence(:hashtag_name, & &1)}"
+ }
+ |> Map.merge(params)
+ end
end