Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into chat-federation-information

This commit is contained in:
lain 2020-07-06 11:27:06 +02:00
commit 74b88c0a8b
20 changed files with 107 additions and 23 deletions

View file

@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- **Breaking:** Emoji API: changed methods and renamed routes. - **Breaking:** Emoji API: changed methods and renamed routes.
- Streaming: Repeats of a user's posts will no longer be pushed to the user's stream. - Streaming: Repeats of a user's posts will no longer be pushed to the user's stream.
- Mastodon API: Added `pleroma.metadata.fields_limits` to /api/v1/instance - Mastodon API: Added `pleroma.metadata.fields_limits` to /api/v1/instance
- Mastodon API: On deletion, returns the original post text.
</details> </details>
<details> <details>

View file

@ -12,6 +12,11 @@ defmodule Pleroma.Config.Loader do
:swarm :swarm
] ]
@reject_groups [
:postgrex,
:tesla
]
if Code.ensure_loaded?(Config.Reader) do if Code.ensure_loaded?(Config.Reader) do
@reader Config.Reader @reader Config.Reader
@ -47,7 +52,8 @@ defmodule Pleroma.Config.Loader do
@spec filter_group(atom(), keyword()) :: keyword() @spec filter_group(atom(), keyword()) :: keyword()
def filter_group(group, configs) do def filter_group(group, configs) do
Enum.reject(configs[group], fn {key, _v} -> Enum.reject(configs[group], fn {key, _v} ->
key in @reject_keys or (group == :phoenix and key == :serve_endpoints) or group == :postgrex key in @reject_keys or group in @reject_groups or
(group == :phoenix and key == :serve_endpoints)
end) end)
end end
end end

View file

@ -3,7 +3,6 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MigrationHelper.NotificationBackfill do defmodule Pleroma.MigrationHelper.NotificationBackfill do
alias Pleroma.Notification
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.User alias Pleroma.User
@ -25,18 +24,27 @@ defmodule Pleroma.MigrationHelper.NotificationBackfill do
|> type_from_activity() |> type_from_activity()
notification notification
|> Notification.changeset(%{type: type}) |> Ecto.Changeset.change(%{type: type})
|> Repo.update() |> Repo.update()
end) end)
end end
defp get_by_ap_id(ap_id) do
q =
from(u in User,
select: u.id
)
Repo.get_by(q, ap_id: ap_id)
end
# This is copied over from Notifications to keep this stable. # This is copied over from Notifications to keep this stable.
defp type_from_activity(%{data: %{"type" => type}} = activity) do defp type_from_activity(%{data: %{"type" => type}} = activity) do
case type do case type do
"Follow" -> "Follow" ->
accepted_function = fn activity -> accepted_function = fn activity ->
with %User{} = follower <- User.get_by_ap_id(activity.data["actor"]), with %User{} = follower <- get_by_ap_id(activity.data["actor"]),
%User{} = followed <- User.get_by_ap_id(activity.data["object"]) do %User{} = followed <- get_by_ap_id(activity.data["object"]) do
Pleroma.FollowingRelationship.following?(follower, followed) Pleroma.FollowingRelationship.following?(follower, followed)
end end
end end

View file

@ -52,6 +52,7 @@ defmodule Pleroma.User.Search do
|> base_query(following) |> base_query(following)
|> filter_blocked_user(for_user) |> filter_blocked_user(for_user)
|> filter_invisible_users() |> filter_invisible_users()
|> filter_internal_users()
|> filter_blocked_domains(for_user) |> filter_blocked_domains(for_user)
|> fts_search(query_string) |> fts_search(query_string)
|> trigram_rank(query_string) |> trigram_rank(query_string)
@ -109,6 +110,10 @@ defmodule Pleroma.User.Search do
from(q in query, where: q.invisible == false) from(q in query, where: q.invisible == false)
end end
defp filter_internal_users(query) do
from(q in query, where: q.actor_type != "Application")
end
defp filter_blocked_user(query, %User{} = blocker) do defp filter_blocked_user(query, %User{} = blocker) do
query query
|> join(:left, [u], b in Pleroma.UserRelationship, |> join(:left, [u], b in Pleroma.UserRelationship,

View file

@ -84,7 +84,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
operationId: "StatusController.delete", operationId: "StatusController.delete",
parameters: [id_param()], parameters: [id_param()],
responses: %{ responses: %{
200 => empty_object_response(), 200 => status_response(),
403 => Operation.response("Forbidden", "application/json", ApiError), 403 => Operation.response("Forbidden", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiError) 404 => Operation.response("Not Found", "application/json", ApiError)
} }

View file

@ -62,6 +62,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
} }
}, },
content: %Schema{type: :string, format: :html, description: "HTML-encoded status content"}, content: %Schema{type: :string, format: :html, description: "HTML-encoded status content"},
text: %Schema{
type: :string,
description: "Original unformatted content in plain text",
nullable: true
},
created_at: %Schema{ created_at: %Schema{
type: :string, type: :string,
format: "date-time", format: "date-time",

View file

@ -186,6 +186,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
draft.poll draft.poll
) )
|> Map.put("emoji", emoji) |> Map.put("emoji", emoji)
|> Map.put("source", draft.status)
%__MODULE__{draft | object: object} %__MODULE__{draft | object: object}
end end

View file

@ -44,6 +44,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
def search(conn, params), do: do_search(:v1, conn, params) def search(conn, params), do: do_search(:v1, conn, params)
defp do_search(version, %{assigns: %{user: user}} = conn, %{q: query} = params) do defp do_search(version, %{assigns: %{user: user}} = conn, %{q: query} = params) do
query = String.trim(query)
options = search_options(params, user) options = search_options(params, user)
timeout = Keyword.get(Repo.config(), :timeout, 15_000) timeout = Keyword.get(Repo.config(), :timeout, 15_000)
default_values = %{"statuses" => [], "accounts" => [], "hashtags" => []} default_values = %{"statuses" => [], "accounts" => [], "hashtags" => []}

View file

@ -200,11 +200,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
@doc "DELETE /api/v1/statuses/:id" @doc "DELETE /api/v1/statuses/:id"
def delete(%{assigns: %{user: user}} = conn, %{id: id}) do def delete(%{assigns: %{user: user}} = conn, %{id: id}) do
with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do with %Activity{} = activity <- Activity.get_by_id_with_object(id),
json(conn, %{}) render <-
try_render(conn, "show.json",
activity: activity,
for: user,
with_direct_conversation_id: true,
with_source: true
),
{:ok, %Activity{}} <- CommonAPI.delete(id, user) do
render
else else
{:error, :not_found} = e -> e _e -> {:error, :not_found}
_e -> render_error(conn, :forbidden, "Can't delete this post")
end end
end end

View file

@ -333,6 +333,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
reblog: nil, reblog: nil,
card: card, card: card,
content: content_html, content: content_html,
text: opts[:with_source] && object.data["source"],
created_at: created_at, created_at: created_at,
reblogs_count: announcement_count, reblogs_count: announcement_count,
replies_count: object.data["repliesCount"] || 0, replies_count: object.data["repliesCount"] || 0,

View file

@ -104,7 +104,9 @@ defmodule Pleroma.Web.Streamer do
:ok :ok
end end
def filtered_by_user?(%User{} = user, %Activity{} = item) do def filtered_by_user?(user, item, streamed_type \\ :activity)
def filtered_by_user?(%User{} = user, %Activity{} = item, streamed_type) do
%{block: blocked_ap_ids, mute: muted_ap_ids, reblog_mute: reblog_muted_ap_ids} = %{block: blocked_ap_ids, mute: muted_ap_ids, reblog_mute: reblog_muted_ap_ids} =
User.outgoing_relationships_ap_ids(user, [:block, :mute, :reblog_mute]) User.outgoing_relationships_ap_ids(user, [:block, :mute, :reblog_mute])
@ -116,7 +118,9 @@ defmodule Pleroma.Web.Streamer do
true <- true <-
Enum.all?([blocked_ap_ids, muted_ap_ids], &(item.actor not in &1)), Enum.all?([blocked_ap_ids, muted_ap_ids], &(item.actor not in &1)),
true <- item.data["type"] != "Announce" || item.actor not in reblog_muted_ap_ids, true <- item.data["type"] != "Announce" || item.actor not in reblog_muted_ap_ids,
true <- !(item.data["type"] == "Announce" && parent.data["actor"] == user.ap_id), true <-
!(streamed_type == :activity && item.data["type"] == "Announce" &&
parent.data["actor"] == user.ap_id),
true <- Enum.all?([blocked_ap_ids, muted_ap_ids], &(parent.data["actor"] not in &1)), true <- Enum.all?([blocked_ap_ids, muted_ap_ids], &(parent.data["actor"] not in &1)),
true <- MapSet.disjoint?(recipients, recipient_blocks), true <- MapSet.disjoint?(recipients, recipient_blocks),
%{host: item_host} <- URI.parse(item.actor), %{host: item_host} <- URI.parse(item.actor),
@ -131,8 +135,8 @@ defmodule Pleroma.Web.Streamer do
end end
end end
def filtered_by_user?(%User{} = user, %Notification{activity: activity}) do def filtered_by_user?(%User{} = user, %Notification{activity: activity}, _) do
filtered_by_user?(user, activity) filtered_by_user?(user, activity, :notification)
end end
defp do_stream("direct", item) do defp do_stream("direct", item) do

View file

@ -0,0 +1,10 @@
defmodule Pleroma.Repo.Migrations.RemoveTeslaFromConfig do
use Ecto.Migration
def up do
execute("DELETE FROM config WHERE config.group = ':tesla'")
end
def down do
end
end

View file

@ -10,7 +10,6 @@ defmodule Pleroma.Config.HolderTest do
test "default_config/0" do test "default_config/0" do
config = Holder.default_config() config = Holder.default_config()
assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads" assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads"
assert config[:tesla][:adapter] == Tesla.Mock
refute config[:pleroma][Pleroma.Repo] refute config[:pleroma][Pleroma.Repo]
refute config[:pleroma][Pleroma.Web.Endpoint] refute config[:pleroma][Pleroma.Web.Endpoint]
@ -18,17 +17,15 @@ defmodule Pleroma.Config.HolderTest do
refute config[:pleroma][:configurable_from_database] refute config[:pleroma][:configurable_from_database]
refute config[:pleroma][:database] refute config[:pleroma][:database]
refute config[:phoenix][:serve_endpoints] refute config[:phoenix][:serve_endpoints]
refute config[:tesla][:adapter]
end end
test "default_config/1" do test "default_config/1" do
pleroma_config = Holder.default_config(:pleroma) pleroma_config = Holder.default_config(:pleroma)
assert pleroma_config[Pleroma.Uploaders.Local][:uploads] == "test/uploads" assert pleroma_config[Pleroma.Uploaders.Local][:uploads] == "test/uploads"
tesla_config = Holder.default_config(:tesla)
assert tesla_config[:adapter] == Tesla.Mock
end end
test "default_config/2" do test "default_config/2" do
assert Holder.default_config(:pleroma, Pleroma.Uploaders.Local) == [uploads: "test/uploads"] assert Holder.default_config(:pleroma, Pleroma.Uploaders.Local) == [uploads: "test/uploads"]
assert Holder.default_config(:tesla, :adapter) == Tesla.Mock
end end
end end

View file

@ -67,6 +67,7 @@ defmodule Pleroma.Factory do
data = %{ data = %{
"type" => "Note", "type" => "Note",
"content" => text, "content" => text,
"source" => text,
"id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(), "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
"actor" => user.ap_id, "actor" => user.ap_id,
"to" => ["https://www.w3.org/ns/activitystreams#Public"], "to" => ["https://www.w3.org/ns/activitystreams#Public"],

View file

@ -17,7 +17,7 @@ defmodule Pleroma.UserSearchTest do
describe "User.search" do describe "User.search" do
setup do: clear_config([:instance, :limit_to_local_content]) setup do: clear_config([:instance, :limit_to_local_content])
test "excluded invisible users from results" do test "excludes invisible users from results" do
user = insert(:user, %{nickname: "john t1000"}) user = insert(:user, %{nickname: "john t1000"})
insert(:user, %{invisible: true, nickname: "john t800"}) insert(:user, %{invisible: true, nickname: "john t800"})
@ -25,6 +25,15 @@ defmodule Pleroma.UserSearchTest do
assert found_user.id == user.id assert found_user.id == user.id
end end
test "excludes service actors from results" do
insert(:user, actor_type: "Application", nickname: "user1")
service = insert(:user, actor_type: "Service", nickname: "user2")
person = insert(:user, actor_type: "Person", nickname: "user3")
assert [found_user1, found_user2] = User.search("user")
assert [found_user1.id, found_user2.id] -- [service.id, person.id] == []
end
test "accepts limit parameter" do test "accepts limit parameter" do
Enum.each(0..4, &insert(:user, %{nickname: "john#{&1}"})) Enum.each(0..4, &insert(:user, %{nickname: "john#{&1}"}))
assert length(User.search("john", limit: 3)) == 3 assert length(User.search("john", limit: 3)) == 3

View file

@ -491,6 +491,7 @@ defmodule Pleroma.Web.CommonAPITest do
object = Object.normalize(activity) object = Object.normalize(activity)
assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)" assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
assert object.data["source"] == post
end end
test "it filters out obviously bad tags when accepting a post as Markdown" do test "it filters out obviously bad tags when accepting a post as Markdown" do
@ -507,6 +508,7 @@ defmodule Pleroma.Web.CommonAPITest do
object = Object.normalize(activity) object = Object.normalize(activity)
assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)" assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
assert object.data["source"] == post
end end
test "it does not allow replies to direct messages that are not direct messages themselves" do test "it does not allow replies to direct messages that are not direct messages themselves" do

View file

@ -79,6 +79,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
assert status["id"] == to_string(activity.id) assert status["id"] == to_string(activity.id)
end end
@tag capture_log: true
test "constructs hashtags from search query", %{conn: conn} do test "constructs hashtags from search query", %{conn: conn} do
results = results =
conn conn
@ -318,11 +319,13 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
test "search fetches remote accounts", %{conn: conn} do test "search fetches remote accounts", %{conn: conn} do
user = insert(:user) user = insert(:user)
query = URI.encode_query(%{q: " mike@osada.macgirvin.com ", resolve: true})
results = results =
conn conn
|> assign(:user, user) |> assign(:user, user)
|> assign(:token, insert(:oauth_token, user: user, scopes: ["read"])) |> assign(:token, insert(:oauth_token, user: user, scopes: ["read"]))
|> get("/api/v1/search?q=mike@osada.macgirvin.com&resolve=true") |> get("/api/v1/search?#{query}")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
[account] = results["accounts"] [account] = results["accounts"]

View file

@ -760,13 +760,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
test "when you created it" do test "when you created it" do
%{user: author, conn: conn} = oauth_access(["write:statuses"]) %{user: author, conn: conn} = oauth_access(["write:statuses"])
activity = insert(:note_activity, user: author) activity = insert(:note_activity, user: author)
object = Object.normalize(activity)
conn = content = object.data["content"]
source = object.data["source"]
result =
conn conn
|> assign(:user, author) |> assign(:user, author)
|> delete("/api/v1/statuses/#{activity.id}") |> delete("/api/v1/statuses/#{activity.id}")
|> json_response_and_validate_schema(200)
assert %{} = json_response_and_validate_schema(conn, 200) assert match?(%{"content" => ^content, "text" => ^source}, result)
refute Activity.get_by_id(activity.id) refute Activity.get_by_id(activity.id)
end end
@ -789,7 +794,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
conn = delete(conn, "/api/v1/statuses/#{activity.id}") conn = delete(conn, "/api/v1/statuses/#{activity.id}")
assert %{"error" => _} = json_response_and_validate_schema(conn, 403) assert %{"error" => "Record not found"} == json_response_and_validate_schema(conn, 404)
assert Activity.get_by_id(activity.id) == activity assert Activity.get_by_id(activity.id) == activity
end end

View file

@ -183,6 +183,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
card: nil, card: nil,
reblog: nil, reblog: nil,
content: HTML.filter_tags(object_data["content"]), content: HTML.filter_tags(object_data["content"]),
text: nil,
created_at: created_at, created_at: created_at,
reblogs_count: 0, reblogs_count: 0,
replies_count: 0, replies_count: 0,

View file

@ -128,6 +128,23 @@ defmodule Pleroma.Web.StreamerTest do
assert Streamer.filtered_by_user?(user, announce) assert Streamer.filtered_by_user?(user, announce)
end end
test "it does stream notifications announces of the user's own posts in the 'user' stream", %{
user: user
} do
Streamer.get_topic_and_add_socket("user", user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
{:ok, announce} = CommonAPI.repeat(activity.id, other_user)
notification =
Pleroma.Notification
|> Repo.get_by(%{user_id: user.id, activity_id: announce.id})
|> Repo.preload(:activity)
refute Streamer.filtered_by_user?(user, notification)
end
test "it streams boosts of mastodon user in the 'user' stream", %{user: user} do test "it streams boosts of mastodon user in the 'user' stream", %{user: user} do
Streamer.get_topic_and_add_socket("user", user) Streamer.get_topic_and_add_socket("user", user)