Merge remote-tracking branch 'upstream/develop' into neckbeard
This commit is contained in:
commit
70cd62b033
|
@ -559,8 +559,8 @@ config :pleroma, Oban,
|
|||
token_expiration: 5,
|
||||
filter_expiration: 1,
|
||||
backup: 1,
|
||||
federator_incoming: 50,
|
||||
federator_outgoing: 50,
|
||||
federator_incoming: 5,
|
||||
federator_outgoing: 5,
|
||||
ingestion_queue: 50,
|
||||
web_push: 50,
|
||||
mailer: 10,
|
||||
|
|
|
@ -112,9 +112,10 @@ defmodule Mix.Tasks.Pleroma.User do
|
|||
{:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
|
||||
shell_info("Generated password reset token for #{user.nickname}")
|
||||
|
||||
IO.puts("URL: #{Pleroma.Web.Router.Helpers.reset_password_url(Pleroma.Web.Endpoint,
|
||||
:reset,
|
||||
token.token)}")
|
||||
url =
|
||||
Pleroma.Web.Router.Helpers.reset_password_url(Pleroma.Web.Endpoint, :reset, token.token)
|
||||
|
||||
IO.puts("URL: #{url}")
|
||||
else
|
||||
_ ->
|
||||
shell_error("No local user #{nickname}")
|
||||
|
|
|
@ -94,6 +94,7 @@ defmodule Pleroma.User.Search do
|
|||
|> subquery()
|
||||
|> order_by(desc: :search_rank)
|
||||
|> maybe_restrict_local(for_user)
|
||||
|> filter_deactivated_users()
|
||||
end
|
||||
|
||||
defp select_top_users(query, top_user_ids) do
|
||||
|
@ -166,6 +167,10 @@ defmodule Pleroma.User.Search do
|
|||
from(q in query, where: q.actor_type != "Application")
|
||||
end
|
||||
|
||||
defp filter_deactivated_users(query) do
|
||||
from(q in query, where: q.is_active == true)
|
||||
end
|
||||
|
||||
defp filter_blocked_user(query, %User{} = blocker) do
|
||||
query
|
||||
|> join(:left, [u], b in Pleroma.UserRelationship,
|
||||
|
|
|
@ -376,6 +376,22 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
|||
}
|
||||
end
|
||||
|
||||
def remove_from_followers_operation do
|
||||
%Operation{
|
||||
tags: ["Account actions"],
|
||||
summary: "Remove from followers",
|
||||
operationId: "AccountController.remove_from_followers",
|
||||
security: [%{"oAuth" => ["follow", "write:follows"]}],
|
||||
description: "Remove the given account from followers",
|
||||
parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
|
||||
responses: %{
|
||||
200 => Operation.response("Relationship", "application/json", AccountRelationship),
|
||||
400 => Operation.response("Error", "application/json", ApiError),
|
||||
404 => Operation.response("Error", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def note_operation do
|
||||
%Operation{
|
||||
tags: ["Account actions"],
|
||||
|
|
|
@ -76,16 +76,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
|||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{scopes: ["follow", "write:follows"]} when action in [:follow_by_uri, :follow, :unfollow]
|
||||
%{scopes: ["follow", "write:follows"]}
|
||||
when action in [:follow_by_uri, :follow, :unfollow, :remove_from_followers]
|
||||
)
|
||||
|
||||
plug(OAuthScopesPlug, %{scopes: ["follow", "read:mutes"]} when action == :mutes)
|
||||
|
||||
plug(OAuthScopesPlug, %{scopes: ["follow", "write:mutes"]} when action in [:mute, :unmute])
|
||||
|
||||
@relationship_actions [:follow, :unfollow]
|
||||
@relationship_actions [:follow, :unfollow, :remove_from_followers]
|
||||
@needs_account ~W(
|
||||
followers following lists follow unfollow mute unmute block unblock note endorse unendorse
|
||||
followers following lists follow unfollow mute unmute block unblock
|
||||
note endorse unendorse remove_from_followers
|
||||
)a
|
||||
|
||||
plug(
|
||||
|
@ -477,6 +479,20 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
|||
end
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/accounts/:id/remove_from_followers"
|
||||
def remove_from_followers(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do
|
||||
{:error, "Can not unfollow yourself"}
|
||||
end
|
||||
|
||||
def remove_from_followers(%{assigns: %{user: followed, account: follower}} = conn, _params) do
|
||||
with {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
|
||||
render(conn, "relationship.json", user: followed, target: follower)
|
||||
else
|
||||
nil ->
|
||||
render_error(conn, :not_found, "Record not found")
|
||||
end
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/follows"
|
||||
def follow_by_uri(%{body_params: %{uri: uri}} = conn, _) do
|
||||
case User.get_cached_by_nickname(uri) do
|
||||
|
|
|
@ -510,6 +510,7 @@ defmodule Pleroma.Web.Router do
|
|||
post("/accounts/:id/note", AccountController, :note)
|
||||
post("/accounts/:id/pin", AccountController, :endorse)
|
||||
post("/accounts/:id/unpin", AccountController, :unendorse)
|
||||
post("/accounts/:id/remove_from_followers", AccountController, :remove_from_followers)
|
||||
|
||||
get("/conversations", ConversationController, :index)
|
||||
post("/conversations/:id/read", ConversationController, :mark_as_read)
|
||||
|
|
6
mix.exs
6
mix.exs
|
@ -167,8 +167,8 @@ defmodule Pleroma.Mixfile do
|
|||
{:poolboy, "~> 1.5"},
|
||||
{:prometheus, "~> 4.6"},
|
||||
{:prometheus_ex,
|
||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/prometheus.ex.git",
|
||||
ref: "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5",
|
||||
git: "https://github.com/lanodan/prometheus.ex.git",
|
||||
branch: "fix/elixir-1.14",
|
||||
override: true},
|
||||
{:prometheus_plugs, "~> 1.1"},
|
||||
{:prometheus_phoenix, "~> 1.3"},
|
||||
|
@ -212,7 +212,7 @@ defmodule Pleroma.Mixfile do
|
|||
{:excoveralls, "0.12.3", only: :test},
|
||||
{:hackney, "~> 1.18.0", override: true},
|
||||
{:mox, "~> 1.0", only: :test},
|
||||
{:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test}
|
||||
{:websockex, "~> 0.4.3", only: :test}
|
||||
] ++ oauth_deps()
|
||||
end
|
||||
|
||||
|
|
4
mix.lock
4
mix.lock
|
@ -110,7 +110,7 @@
|
|||
"pot": {:hex, :pot, "1.0.1", "81b511b1fa7c3123171c265cb7065a1528cebd7277b0cbc94257c50a8b2e4c17", [:rebar3], [], "hexpm", "ed87f5976531d91528452faa1138a5328db7f9f20d8feaae15f5051f79bcfb6d"},
|
||||
"prometheus": {:hex, :prometheus, "4.8.0", "1ce1e1002b173c336d61f186b56263346536e76814edd9a142e12aeb2d6c1ad2", [:mix, :rebar3], [], "hexpm", "0fc2e17103073edb3758a46a5d44b006191bf25b73cbaa2b779109de396afcb5"},
|
||||
"prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"},
|
||||
"prometheus_ex": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus.ex.git", "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5", [ref: "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5"]},
|
||||
"prometheus_ex": {:git, "https://github.com/lanodan/prometheus.ex.git", "31f7fbe4b71b79ba27efc2a5085746c4011ceb8f", [branch: "fix/elixir-1.14"]},
|
||||
"prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "c4d1404ac4e9d3d963da601db2a7d8ea31194f0017057fabf0cfb9bf5a6c8c75"},
|
||||
"prometheus_phx": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus-phx.git", "9cd8f248c9381ffedc799905050abce194a97514", [branch: "no-logging"]},
|
||||
"prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"},
|
||||
|
@ -134,5 +134,5 @@
|
|||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
||||
"unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"},
|
||||
"web_push_encryption": {:hex, :web_push_encryption, "0.3.1", "76d0e7375142dfee67391e7690e89f92578889cbcf2879377900b5620ee4708d", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.1", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "4f82b2e57622fb9337559058e8797cb0df7e7c9790793bdc4e40bc895f70e2a2"},
|
||||
"websocket_client": {:git, "https://github.com/jeremyong/websocket_client.git", "9a6f65d05ebf2725d62fb19262b21f1805a59fbf", []},
|
||||
"websockex": {:hex, :websockex, "0.4.3", "92b7905769c79c6480c02daacaca2ddd49de936d912976a4d3c923723b647bf0", [:mix], [], "hexpm", "95f2e7072b85a3a4cc385602d42115b73ce0b74a9121d0d6dbbf557645ac53e4"},
|
||||
}
|
||||
|
|
|
@ -33,16 +33,18 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
|
|||
|
||||
test "refuses invalid requests" do
|
||||
capture_log(fn ->
|
||||
assert {:error, {404, _}} = start_socket()
|
||||
assert {:error, {404, _}} = start_socket("?stream=ncjdk")
|
||||
assert {:error, %WebSockex.RequestError{code: 404}} = start_socket()
|
||||
assert {:error, %WebSockex.RequestError{code: 404}} = start_socket("?stream=ncjdk")
|
||||
Process.sleep(30)
|
||||
end)
|
||||
end
|
||||
|
||||
test "requires authentication and a valid token for protected streams" do
|
||||
capture_log(fn ->
|
||||
assert {:error, {401, _}} = start_socket("?stream=user&access_token=aaaaaaaaaaaa")
|
||||
assert {:error, {401, _}} = start_socket("?stream=user")
|
||||
assert {:error, %WebSockex.RequestError{code: 401}} =
|
||||
start_socket("?stream=user&access_token=aaaaaaaaaaaa")
|
||||
|
||||
assert {:error, %WebSockex.RequestError{code: 401}} = start_socket("?stream=user")
|
||||
Process.sleep(30)
|
||||
end)
|
||||
end
|
||||
|
@ -102,7 +104,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
|
|||
assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}")
|
||||
|
||||
capture_log(fn ->
|
||||
assert {:error, {401, _}} = start_socket("?stream=user")
|
||||
assert {:error, %WebSockex.RequestError{code: 401}} = start_socket("?stream=user")
|
||||
Process.sleep(30)
|
||||
end)
|
||||
end
|
||||
|
@ -111,7 +113,9 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
|
|||
assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}")
|
||||
|
||||
capture_log(fn ->
|
||||
assert {:error, {401, _}} = start_socket("?stream=user:notification")
|
||||
assert {:error, %WebSockex.RequestError{code: 401}} =
|
||||
start_socket("?stream=user:notification")
|
||||
|
||||
Process.sleep(30)
|
||||
end)
|
||||
end
|
||||
|
@ -120,7 +124,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
|
|||
assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}])
|
||||
|
||||
capture_log(fn ->
|
||||
assert {:error, {401, _}} =
|
||||
assert {:error, %WebSockex.RequestError{code: 401}} =
|
||||
start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])
|
||||
|
||||
Process.sleep(30)
|
||||
|
|
|
@ -65,6 +65,14 @@ defmodule Pleroma.UserSearchTest do
|
|||
assert found_user.id == user.id
|
||||
end
|
||||
|
||||
test "excludes deactivated users from results" do
|
||||
user = insert(:user, %{nickname: "john t1000"})
|
||||
insert(:user, %{is_active: false, nickname: "john t800"})
|
||||
|
||||
[found_user] = User.search("john")
|
||||
assert found_user.id == user.id
|
||||
end
|
||||
|
||||
# Note: as in Mastodon, `is_discoverable` doesn't anyhow relate to user searchability
|
||||
test "includes non-discoverable users in results" do
|
||||
insert(:user, %{nickname: "john 3000", is_discoverable: false})
|
||||
|
|
|
@ -311,7 +311,7 @@ defmodule Pleroma.UserTest do
|
|||
describe "unfollow/2" do
|
||||
setup do: clear_config([:instance, :external_user_synchronization])
|
||||
|
||||
test "unfollow with syncronizes external user" do
|
||||
test "unfollow with synchronizes external user" do
|
||||
clear_config([:instance, :external_user_synchronization], true)
|
||||
|
||||
followed =
|
||||
|
@ -2265,7 +2265,7 @@ defmodule Pleroma.UserTest do
|
|||
assert other_user.follower_count == 1
|
||||
end
|
||||
|
||||
test "syncronizes the counters with the remote instance for the followed when enabled" do
|
||||
test "synchronizes the counters with the remote instance for the followed when enabled" do
|
||||
clear_config([:instance, :external_user_synchronization], false)
|
||||
|
||||
user = insert(:user)
|
||||
|
@ -2287,7 +2287,7 @@ defmodule Pleroma.UserTest do
|
|||
assert other_user.follower_count == 437
|
||||
end
|
||||
|
||||
test "syncronizes the counters with the remote instance for the follower when enabled" do
|
||||
test "synchronizes the counters with the remote instance for the follower when enabled" do
|
||||
clear_config([:instance, :external_user_synchronization], false)
|
||||
|
||||
user = insert(:user)
|
||||
|
|
|
@ -1662,7 +1662,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
|
|||
end
|
||||
|
||||
describe "fetch_follow_information_for_user" do
|
||||
test "syncronizes following/followers counters" do
|
||||
test "synchronizes following/followers counters" do
|
||||
user =
|
||||
insert(:user,
|
||||
local: false,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.AdminAPI.InstanceDocumentControllerTest do
|
||||
use Pleroma.Web.ConnCase, async: true
|
||||
use Pleroma.Web.ConnCase
|
||||
import Pleroma.Factory
|
||||
|
||||
@dir "test/tmp/instance_static"
|
||||
|
|
|
@ -2119,4 +2119,48 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|
|||
|> json_response_and_validate_schema(400)
|
||||
end
|
||||
end
|
||||
|
||||
describe "remove from followers" do
|
||||
setup do: oauth_access(["follow"])
|
||||
|
||||
test "removing user from followers", %{conn: conn, user: user} do
|
||||
%{id: other_user_id} = other_user = insert(:user)
|
||||
|
||||
CommonAPI.follow(other_user, user)
|
||||
|
||||
assert %{"id" => ^other_user_id, "followed_by" => false} =
|
||||
conn
|
||||
|> post("/api/v1/accounts/#{other_user_id}/remove_from_followers")
|
||||
|> json_response_and_validate_schema(200)
|
||||
|
||||
refute User.following?(other_user, user)
|
||||
end
|
||||
|
||||
test "removing remote user from followers", %{conn: conn, user: user} do
|
||||
%{id: other_user_id} = other_user = insert(:user, local: false)
|
||||
|
||||
CommonAPI.follow(other_user, user)
|
||||
|
||||
assert User.following?(other_user, user)
|
||||
|
||||
assert %{"id" => ^other_user_id, "followed_by" => false} =
|
||||
conn
|
||||
|> post("/api/v1/accounts/#{other_user_id}/remove_from_followers")
|
||||
|> json_response_and_validate_schema(200)
|
||||
|
||||
refute User.following?(other_user, user)
|
||||
end
|
||||
|
||||
test "removing user from followers errors", %{user: user, conn: conn} do
|
||||
# self remove
|
||||
conn_res = post(conn, "/api/v1/accounts/#{user.id}/remove_from_followers")
|
||||
|
||||
assert %{"error" => "Can not unfollow yourself"} =
|
||||
json_response_and_validate_schema(conn_res, 400)
|
||||
|
||||
# remove non existing user
|
||||
conn_res = post(conn, "/api/v1/accounts/doesntexist/remove_from_followers")
|
||||
assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -944,7 +944,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "hashtag timeline handling of :restrict_unauthenticated setting" do
|
||||
describe "hashtag timeline handling of restrict_unauthenticated setting" do
|
||||
setup do
|
||||
user = insert(:user)
|
||||
{:ok, activity1} = CommonAPI.post(user, %{status: "test #tag1"})
|
||||
|
|
|
@ -10,11 +10,14 @@ defmodule Pleroma.Web.MediaProxy.Invalidation.ScriptTest do
|
|||
|
||||
test "it logs error when script is not found" do
|
||||
assert capture_log(fn ->
|
||||
assert Invalidation.Script.purge(
|
||||
["http://example.com/media/example.jpg"],
|
||||
script_path: "./example"
|
||||
) == {:error, "%ErlangError{original: :enoent}"}
|
||||
end) =~ "Error while cache purge: %ErlangError{original: :enoent}"
|
||||
assert {:error, msg} =
|
||||
Invalidation.Script.purge(
|
||||
["http://example.com/media/example.jpg"],
|
||||
script_path: "./example"
|
||||
)
|
||||
|
||||
assert msg =~ ~r/%ErlangError{original: :enoent(, reason: nil)?}/
|
||||
end) =~ ~r/Error while cache purge: %ErlangError{original: :enoent(, reason: nil)?}/
|
||||
|
||||
capture_log(fn ->
|
||||
assert Invalidation.Script.purge(
|
||||
|
|
|
@ -5,18 +5,17 @@
|
|||
defmodule Pleroma.Integration.WebsocketClient do
|
||||
# https://github.com/phoenixframework/phoenix/blob/master/test/support/websocket_client.exs
|
||||
|
||||
use WebSockex
|
||||
|
||||
@doc """
|
||||
Starts the WebSocket server for given ws URL. Received Socket.Message's
|
||||
are forwarded to the sender pid
|
||||
"""
|
||||
def start_link(sender, url, headers \\ []) do
|
||||
:crypto.start()
|
||||
:ssl.start()
|
||||
|
||||
:websocket_client.start_link(
|
||||
String.to_charlist(url),
|
||||
WebSockex.start_link(
|
||||
url,
|
||||
__MODULE__,
|
||||
[sender],
|
||||
%{sender: sender},
|
||||
extra_headers: headers
|
||||
)
|
||||
end
|
||||
|
@ -36,27 +35,26 @@ defmodule Pleroma.Integration.WebsocketClient do
|
|||
end
|
||||
|
||||
@doc false
|
||||
def init([sender], _conn_state) do
|
||||
{:ok, %{sender: sender}}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def websocket_handle(frame, _conn_state, state) do
|
||||
@impl true
|
||||
def handle_frame(frame, state) do
|
||||
send(state.sender, frame)
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def websocket_info({:text, msg}, _conn_state, state) do
|
||||
@impl true
|
||||
def handle_info({:text, msg}, state) do
|
||||
{:reply, {:text, msg}, state}
|
||||
end
|
||||
|
||||
def websocket_info(:close, _conn_state, _state) do
|
||||
@impl true
|
||||
def handle_info(:close, _state) do
|
||||
{:close, <<>>, "done"}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def websocket_terminate(_reason, _conn_state, _state) do
|
||||
@impl true
|
||||
def terminate(_reason, _state) do
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue