Merge branch 'follow-hashtags' into 'develop'
Hashtag following (from Akkoma) See merge request pleroma/pleroma!4307
This commit is contained in:
commit
801a2256f4
21 changed files with 720 additions and 8 deletions
|
|
@ -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"],
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue