Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into chat-federation-information
This commit is contained in:
commit
74b88c0a8b
20 changed files with 107 additions and 23 deletions
|
@ -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.
|
||||
- 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: On deletion, returns the original post text.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
|
|
@ -12,6 +12,11 @@ defmodule Pleroma.Config.Loader do
|
|||
:swarm
|
||||
]
|
||||
|
||||
@reject_groups [
|
||||
:postgrex,
|
||||
:tesla
|
||||
]
|
||||
|
||||
if Code.ensure_loaded?(Config.Reader) do
|
||||
@reader Config.Reader
|
||||
|
||||
|
@ -47,7 +52,8 @@ defp filter(configs) do
|
|||
@spec filter_group(atom(), keyword()) :: keyword()
|
||||
def filter_group(group, configs) do
|
||||
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
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.MigrationHelper.NotificationBackfill do
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
|
@ -25,18 +24,27 @@ def fill_in_notification_types do
|
|||
|> type_from_activity()
|
||||
|
||||
notification
|
||||
|> Notification.changeset(%{type: type})
|
||||
|> Ecto.Changeset.change(%{type: type})
|
||||
|> Repo.update()
|
||||
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.
|
||||
defp type_from_activity(%{data: %{"type" => type}} = activity) do
|
||||
case type do
|
||||
"Follow" ->
|
||||
accepted_function = fn activity ->
|
||||
with %User{} = follower <- User.get_by_ap_id(activity.data["actor"]),
|
||||
%User{} = followed <- User.get_by_ap_id(activity.data["object"]) do
|
||||
with %User{} = follower <- get_by_ap_id(activity.data["actor"]),
|
||||
%User{} = followed <- get_by_ap_id(activity.data["object"]) do
|
||||
Pleroma.FollowingRelationship.following?(follower, followed)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -52,6 +52,7 @@ defp search_query(query_string, for_user, following) do
|
|||
|> base_query(following)
|
||||
|> filter_blocked_user(for_user)
|
||||
|> filter_invisible_users()
|
||||
|> filter_internal_users()
|
||||
|> filter_blocked_domains(for_user)
|
||||
|> fts_search(query_string)
|
||||
|> trigram_rank(query_string)
|
||||
|
@ -109,6 +110,10 @@ defp filter_invisible_users(query) do
|
|||
from(q in query, where: q.invisible == false)
|
||||
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
|
||||
query
|
||||
|> join(:left, [u], b in Pleroma.UserRelationship,
|
||||
|
|
|
@ -84,7 +84,7 @@ def delete_operation do
|
|||
operationId: "StatusController.delete",
|
||||
parameters: [id_param()],
|
||||
responses: %{
|
||||
200 => empty_object_response(),
|
||||
200 => status_response(),
|
||||
403 => Operation.response("Forbidden", "application/json", ApiError),
|
||||
404 => Operation.response("Not Found", "application/json", ApiError)
|
||||
}
|
||||
|
|
|
@ -62,6 +62,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
|
|||
}
|
||||
},
|
||||
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{
|
||||
type: :string,
|
||||
format: "date-time",
|
||||
|
|
|
@ -186,6 +186,7 @@ defp object(draft) do
|
|||
draft.poll
|
||||
)
|
||||
|> Map.put("emoji", emoji)
|
||||
|> Map.put("source", draft.status)
|
||||
|
||||
%__MODULE__{draft | object: object}
|
||||
end
|
||||
|
|
|
@ -44,6 +44,7 @@ def search2(conn, params), do: do_search(:v2, conn, params)
|
|||
def search(conn, params), do: do_search(:v1, conn, params)
|
||||
|
||||
defp do_search(version, %{assigns: %{user: user}} = conn, %{q: query} = params) do
|
||||
query = String.trim(query)
|
||||
options = search_options(params, user)
|
||||
timeout = Keyword.get(Repo.config(), :timeout, 15_000)
|
||||
default_values = %{"statuses" => [], "accounts" => [], "hashtags" => []}
|
||||
|
|
|
@ -200,11 +200,18 @@ def show(%{assigns: %{user: user}} = conn, %{id: id}) do
|
|||
|
||||
@doc "DELETE /api/v1/statuses/:id"
|
||||
def delete(%{assigns: %{user: user}} = conn, %{id: id}) do
|
||||
with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
|
||||
json(conn, %{})
|
||||
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
|
||||
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
|
||||
{:error, :not_found} = e -> e
|
||||
_e -> render_error(conn, :forbidden, "Can't delete this post")
|
||||
_e -> {:error, :not_found}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -333,6 +333,7 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
|
|||
reblog: nil,
|
||||
card: card,
|
||||
content: content_html,
|
||||
text: opts[:with_source] && object.data["source"],
|
||||
created_at: created_at,
|
||||
reblogs_count: announcement_count,
|
||||
replies_count: object.data["repliesCount"] || 0,
|
||||
|
|
|
@ -104,7 +104,9 @@ def stream(topics, items) do
|
|||
:ok
|
||||
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} =
|
||||
User.outgoing_relationships_ap_ids(user, [:block, :mute, :reblog_mute])
|
||||
|
||||
|
@ -116,7 +118,9 @@ def filtered_by_user?(%User{} = user, %Activity{} = item) do
|
|||
true <-
|
||||
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" && 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 <- MapSet.disjoint?(recipients, recipient_blocks),
|
||||
%{host: item_host} <- URI.parse(item.actor),
|
||||
|
@ -131,8 +135,8 @@ def filtered_by_user?(%User{} = user, %Activity{} = item) do
|
|||
end
|
||||
end
|
||||
|
||||
def filtered_by_user?(%User{} = user, %Notification{activity: activity}) do
|
||||
filtered_by_user?(user, activity)
|
||||
def filtered_by_user?(%User{} = user, %Notification{activity: activity}, _) do
|
||||
filtered_by_user?(user, activity, :notification)
|
||||
end
|
||||
|
||||
defp do_stream("direct", item) do
|
||||
|
|
|
@ -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
|
|
@ -10,7 +10,6 @@ defmodule Pleroma.Config.HolderTest do
|
|||
test "default_config/0" do
|
||||
config = Holder.default_config()
|
||||
assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads"
|
||||
assert config[:tesla][:adapter] == Tesla.Mock
|
||||
|
||||
refute config[:pleroma][Pleroma.Repo]
|
||||
refute config[:pleroma][Pleroma.Web.Endpoint]
|
||||
|
@ -18,17 +17,15 @@ test "default_config/0" do
|
|||
refute config[:pleroma][:configurable_from_database]
|
||||
refute config[:pleroma][:database]
|
||||
refute config[:phoenix][:serve_endpoints]
|
||||
refute config[:tesla][:adapter]
|
||||
end
|
||||
|
||||
test "default_config/1" do
|
||||
pleroma_config = Holder.default_config(:pleroma)
|
||||
assert pleroma_config[Pleroma.Uploaders.Local][:uploads] == "test/uploads"
|
||||
tesla_config = Holder.default_config(:tesla)
|
||||
assert tesla_config[:adapter] == Tesla.Mock
|
||||
end
|
||||
|
||||
test "default_config/2" do
|
||||
assert Holder.default_config(:pleroma, Pleroma.Uploaders.Local) == [uploads: "test/uploads"]
|
||||
assert Holder.default_config(:tesla, :adapter) == Tesla.Mock
|
||||
end
|
||||
end
|
||||
|
|
|
@ -67,6 +67,7 @@ def note_factory(attrs \\ %{}) do
|
|||
data = %{
|
||||
"type" => "Note",
|
||||
"content" => text,
|
||||
"source" => text,
|
||||
"id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
|
||||
"actor" => user.ap_id,
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
|
|
|
@ -17,7 +17,7 @@ defmodule Pleroma.UserSearchTest do
|
|||
describe "User.search" do
|
||||
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"})
|
||||
insert(:user, %{invisible: true, nickname: "john t800"})
|
||||
|
||||
|
@ -25,6 +25,15 @@ test "excluded invisible users from results" do
|
|||
assert found_user.id == user.id
|
||||
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
|
||||
Enum.each(0..4, &insert(:user, %{nickname: "john#{&1}"}))
|
||||
assert length(User.search("john", limit: 3)) == 3
|
||||
|
|
|
@ -491,6 +491,7 @@ test "it filters out obviously bad tags when accepting a post as HTML" do
|
|||
object = Object.normalize(activity)
|
||||
|
||||
assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')"
|
||||
assert object.data["source"] == post
|
||||
end
|
||||
|
||||
test "it filters out obviously bad tags when accepting a post as Markdown" do
|
||||
|
@ -507,6 +508,7 @@ test "it filters out obviously bad tags when accepting a post as Markdown" do
|
|||
object = Object.normalize(activity)
|
||||
|
||||
assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')"
|
||||
assert object.data["source"] == post
|
||||
end
|
||||
|
||||
test "it does not allow replies to direct messages that are not direct messages themselves" do
|
||||
|
|
|
@ -79,6 +79,7 @@ test "search", %{conn: conn} do
|
|||
assert status["id"] == to_string(activity.id)
|
||||
end
|
||||
|
||||
@tag capture_log: true
|
||||
test "constructs hashtags from search query", %{conn: conn} do
|
||||
results =
|
||||
conn
|
||||
|
@ -318,11 +319,13 @@ test "search doesn't show statuses that it shouldn't", %{conn: conn} do
|
|||
test "search fetches remote accounts", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
|
||||
query = URI.encode_query(%{q: " mike@osada.macgirvin.com ", resolve: true})
|
||||
|
||||
results =
|
||||
conn
|
||||
|> assign(:user, user)
|
||||
|> 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)
|
||||
|
||||
[account] = results["accounts"]
|
||||
|
|
|
@ -760,13 +760,18 @@ test "if user is authenticated", %{local: local, remote: remote} do
|
|||
test "when you created it" do
|
||||
%{user: author, conn: conn} = oauth_access(["write:statuses"])
|
||||
activity = insert(:note_activity, user: author)
|
||||
object = Object.normalize(activity)
|
||||
|
||||
conn =
|
||||
content = object.data["content"]
|
||||
source = object.data["source"]
|
||||
|
||||
result =
|
||||
conn
|
||||
|> assign(:user, author)
|
||||
|> 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)
|
||||
end
|
||||
|
@ -789,7 +794,7 @@ test "when you didn't create it" do
|
|||
|
||||
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
|
||||
end
|
||||
|
|
|
@ -183,6 +183,7 @@ test "a note activity" do
|
|||
card: nil,
|
||||
reblog: nil,
|
||||
content: HTML.filter_tags(object_data["content"]),
|
||||
text: nil,
|
||||
created_at: created_at,
|
||||
reblogs_count: 0,
|
||||
replies_count: 0,
|
||||
|
|
|
@ -128,6 +128,23 @@ test "it does not stream announces of the user's own posts in the 'user' stream"
|
|||
assert Streamer.filtered_by_user?(user, announce)
|
||||
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
|
||||
Streamer.get_topic_and_add_socket("user", user)
|
||||
|
||||
|
|
Loading…
Reference in a new issue