Merge branch 'develop' into instance-info

This commit is contained in:
FloatingGhost 2022-11-04 05:09:55 +00:00
commit f66ddf697b
17 changed files with 175 additions and 74 deletions

View file

@ -14,6 +14,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Follows no longer override domain blocks, a domain block is final
- Deletes are now the lowest priority to publish and will be handled after creates
## Fixed
- Registrations via ldap are now compatible with the latest OTP24
## 2022.10
### Added

View file

@ -185,7 +185,7 @@
adapter: []
config :pleroma, :instance,
name: "Pleroma",
name: "Akkoma",
email: "example@example.com",
notify_email: "noreply@example.com",
description: "Akkoma: The cooler fediverse server",

View file

@ -1389,6 +1389,12 @@
label: "Render misskey markdown",
type: :boolean,
description: "Whether to render Misskey-flavoured markdown"
},
%{
key: :stopGifs,
label: "Stop Gifs",
type: :boolean,
description: "Whether to pause animated images until they're hovered on"
}
]
},

View file

@ -59,6 +59,7 @@ To add configuration to your config file, you can copy it from the base config.
* `cleanup_attachments`: Remove attachments along with statuses. Does not affect duplicate files and attachments without status. Enabling this will increase load to database when deleting statuses on larger instances.
* `show_reactions`: Let favourites and emoji reactions be viewed through the API (default: `true`).
* `password_reset_token_validity`: The time after which reset tokens aren't accepted anymore, in seconds (default: one day).
* `local_bubble`: Array of domains representing instances closely related to yours. Used to populate the `bubble` timeline. e.g `['example.com']`, (default: `[]`)
## :database
* `improved_hashtag_timeline`: Setting to force toggle / force disable improved hashtags timeline. `:enabled` forces hashtags to be fetched from `hashtags` table for hashtags timeline. `:disabled` forces object-embedded hashtags to be used (slower). Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` [unless overridden] when HashtagsTableMigrator completes).

View file

@ -67,8 +67,9 @@ def create(relationship_type, %User{} = source, %User{} = target) do
target_id: target.id
})
|> Repo.insert(
on_conflict: {:replace_all_except, [:id]},
conflict_target: [:source_id, :relationship_type, :target_id]
on_conflict: {:replace_all_except, [:id, :inserted_at]},
conflict_target: [:source_id, :relationship_type, :target_id],
returning: true
)
end

View file

@ -102,7 +102,7 @@ defp register_user(connection, base, uid, name) do
{:scope, :eldap.wholeSubtree()},
{:timeout, @search_timeout}
]) do
{:ok, {:eldap_search_result, [{:eldap_entry, _, attributes}], _}} ->
{:ok, {:eldap_search_result, [{:eldap_entry, _, attributes}], _, _}} ->
params = %{
name: name,
nickname: name,

View file

@ -16,7 +16,7 @@ defmodule Pleroma.Web.Push.Impl do
require Logger
import Ecto.Query
@types ["Create", "Follow", "Announce", "Like", "Move", "EmojiReact"]
@types ["Create", "Follow", "Announce", "Like", "Move", "EmojiReact", "Update"]
@doc "Performs sending notifications for user subscriptions"
@spec perform(Notification.t()) :: list(any) | :error | {:error, :unknown_type}
@ -167,6 +167,15 @@ def format_body(
end
end
def format_body(
%{activity: %{data: %{"type" => "Update"}}},
actor,
_object,
_mastodon_type
) do
"@#{actor.nickname} edited a status"
end
def format_title(activity, mastodon_type \\ nil)
def format_title(%{activity: %{data: %{"directMessage" => true}}}, _mastodon_type) do
@ -180,6 +189,7 @@ def format_title(%{type: type}, mastodon_type) do
"follow_request" -> "New Follow Request"
"reblog" -> "New Repeat"
"favourite" -> "New Favorite"
"update" -> "New Update"
"pleroma:emoji_reaction" -> "New Reaction"
type -> "New #{String.capitalize(type || "event")}"
end

BIN
priv/static/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

View file

@ -61,6 +61,12 @@ def handle_cast(:refresh, _state) do
{:noreply, @init_state}
end
# Don't actually restart during tests.
# We just check if the correct call has been done.
# If we actually restart, we get errors during the tests like
# (RuntimeError) could not lookup Ecto repo Pleroma.Repo because it was not started or
# it does not exist
# See tests in Pleroma.Config.TransferTaskTest
def handle_cast({:restart, :test, _}, state) do
Logger.debug("pleroma manually restarted")
{:noreply, Map.put(state, :need_reboot, false)}
@ -74,6 +80,12 @@ def handle_cast({:restart, _, delay}, state) do
def handle_cast({:after_boot, _}, %{after_boot: true} = state), do: {:noreply, state}
# Don't actually restart during tests.
# We just check if the correct call has been done.
# If we actually restart, we get errors during the tests like
# (RuntimeError) could not lookup Ecto repo Pleroma.Repo because it was not started or
# it does not exist
# See tests in Pleroma.Config.TransferTaskTest
def handle_cast({:after_boot, :test}, state) do
Logger.debug("pleroma restarted after boot")
state = %{state | after_boot: true, rebooted: true}

View file

@ -13,7 +13,8 @@ def project do
def application do
[
mod: {Restarter, []}
mod: {Restarter, []},
extra_applications: [:logger]
]
end

View file

@ -119,44 +119,87 @@ test "transfer config values with full subkey update" do
describe "pleroma restart" do
setup do
on_exit(fn -> Restarter.Pleroma.refresh() end)
on_exit(fn ->
Restarter.Pleroma.refresh()
# Restarter.Pleroma.refresh/0 is an asynchronous call.
# A GenServer will first finish the previous call before starting a new one.
# Here we do a synchronous call.
# That way we are sure that the previous call has finished before we continue.
# See https://stackoverflow.com/questions/51361856/how-to-use-task-await-with-genserver
Restarter.Pleroma.rebooted?()
end)
end
@tag :erratic
test "don't restart if no reboot time settings were changed" do
clear_config(:emoji)
insert(:config, key: :emoji, value: [groups: [a: 1, b: 2]])
refute String.contains?(
capture_log(fn -> TransferTask.start_link([]) end),
capture_log(fn ->
TransferTask.start_link([])
# TransferTask.start_link/1 is an asynchronous call.
# A GenServer will first finish the previous call before starting a new one.
# Here we do a synchronous call.
# That way we are sure that the previous call has finished before we continue.
Restarter.Pleroma.rebooted?()
end),
"pleroma restarted"
)
end
@tag :erratic
test "on reboot time key" do
clear_config([:pleroma, :rate_limit])
insert(:config, key: {:pleroma, :rate_limit}, value: [enabled: false])
assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted"
clear_config(:rate_limit)
insert(:config, key: :rate_limit, value: [enabled: false])
# Note that we don't actually restart Pleroma.
# See module Restarter.Pleroma
assert capture_log(fn ->
TransferTask.start_link([])
# TransferTask.start_link/1 is an asynchronous call.
# A GenServer will first finish the previous call before starting a new one.
# Here we do a synchronous call.
# That way we are sure that the previous call has finished before we continue.
Restarter.Pleroma.rebooted?()
end) =~ "pleroma restarted"
end
@tag :erratic
test "on reboot time subkey" do
clear_config(Pleroma.Captcha)
insert(:config, key: Pleroma.Captcha, value: [seconds_valid: 60])
assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted"
# Note that we don't actually restart Pleroma.
# See module Restarter.Pleroma
assert capture_log(fn ->
TransferTask.start_link([])
# TransferTask.start_link/1 is an asynchronous call.
# A GenServer will first finish the previous call before starting a new one.
# Here we do a synchronous call.
# That way we are sure that the previous call has finished before we continue.
Restarter.Pleroma.rebooted?()
end) =~ "pleroma restarted"
end
@tag :erratic
test "don't restart pleroma on reboot time key and subkey if there is false flag" do
clear_config([:pleroma, :rate_limit])
clear_config(:rate_limit)
clear_config(Pleroma.Captcha)
insert(:config, key: {:pleroma, :rate_limit}, value: [enabled: false])
insert(:config, key: :rate_limit, value: [enabled: false])
insert(:config, key: Pleroma.Captcha, value: [seconds_valid: 60])
refute String.contains?(
capture_log(fn -> TransferTask.load_and_update_env([], false) end),
capture_log(fn ->
TransferTask.load_and_update_env([], false)
# TransferTask.start_link/1 is an asynchronous call.
# A GenServer will first finish the previous call before starting a new one.
# Here we do a synchronous call.
# That way we are sure that the previous call has finished before we continue.
Restarter.Pleroma.rebooted?()
end),
"pleroma restarted"
)
end

View file

@ -122,11 +122,11 @@ test "recreating an existing participations sets it to unread" do
end
test "it marks a participation as read" do
participation = insert(:participation, %{read: false})
participation = insert(:participation, %{updated_at: ~N[2017-07-17 17:09:58], read: false})
{:ok, updated_participation} = Participation.mark_as_read(participation)
assert updated_participation.read
assert updated_participation.updated_at == participation.updated_at
assert :gt = NaiveDateTime.compare(updated_participation.updated_at, participation.updated_at)
end
test "it marks a participation as unread" do

View file

@ -5,8 +5,9 @@
defmodule Pleroma.UserRelationshipTest do
alias Pleroma.UserRelationship
use Pleroma.DataCase, async: true
use Pleroma.DataCase, async: false
import Mock
import Pleroma.Factory
describe "*_exists?/2" do
@ -79,7 +80,12 @@ test "creates user relationship record if it doesn't exist", %{users: [user1, us
end
test "if record already exists, returns it", %{users: [user1, user2]} do
user_block = UserRelationship.create_block(user1, user2)
user_block =
with_mock NaiveDateTime, [:passthrough], utc_now: fn -> ~N[2017-03-17 17:09:58] end do
{:ok, %{inserted_at: ~N[2017-03-17 17:09:58]}} =
UserRelationship.create_block(user1, user2)
end
assert user_block == UserRelationship.create_block(user1, user2)
end
end

View file

@ -3,9 +3,10 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
use Pleroma.Web.ConnCase, async: true
use Pleroma.Web.ConnCase, async: false
use Oban.Testing, repo: Pleroma.Repo
import Mock
import Pleroma.Factory
alias Pleroma.Filter
@ -53,25 +54,20 @@ test "a filter with expires_in", %{conn: conn, user: user} do
in_seconds = 600
response =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/filters", %{
"phrase" => "knights",
context: ["home"],
expires_in: in_seconds
})
|> json_response_and_validate_schema(200)
with_mock NaiveDateTime, [:passthrough], utc_now: fn -> ~N[2017-03-17 17:09:58] end do
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/filters", %{
"phrase" => "knights",
context: ["home"],
expires_in: in_seconds
})
|> json_response_and_validate_schema(200)
end
assert response["irreversible"] == false
expires_at =
NaiveDateTime.utc_now()
|> NaiveDateTime.add(in_seconds)
assert NaiveDateTime.diff(
NaiveDateTime.from_iso8601!(response["expires_at"]),
expires_at
) < 5
assert response["expires_at"] == "2017-03-17T17:19:58.000Z"
filter = Filter.get(response["id"], user)
@ -183,26 +179,21 @@ test "with adding expires_at", %{conn: conn, user: user} do
in_seconds = 600
response =
conn
|> put_req_header("content-type", "application/json")
|> put("/api/v1/filters/#{filter.filter_id}", %{
phrase: "nii",
context: ["public"],
expires_in: in_seconds,
irreversible: true
})
|> json_response_and_validate_schema(200)
with_mock NaiveDateTime, [:passthrough], utc_now: fn -> ~N[2017-03-17 17:09:58] end do
conn
|> put_req_header("content-type", "application/json")
|> put("/api/v1/filters/#{filter.filter_id}", %{
phrase: "nii",
context: ["public"],
expires_in: in_seconds,
irreversible: true
})
|> json_response_and_validate_schema(200)
end
assert response["irreversible"] == true
expected_time =
NaiveDateTime.utc_now()
|> NaiveDateTime.add(in_seconds)
assert NaiveDateTime.diff(
NaiveDateTime.from_iso8601!(response["expires_at"]),
expected_time
) < 5
assert response["expires_at"] == "2017-03-17T17:19:58.000Z"
filter = Filter.get(response["id"], user)

View file

@ -71,7 +71,7 @@ test "creates a new user after successful LDAP authorization" do
equalityMatch: fn _type, _value -> :ok end,
wholeSubtree: fn -> :ok end,
search: fn _connection, _options ->
{:ok, {:eldap_search_result, [{:eldap_entry, '', []}], []}}
{:ok, {:eldap_search_result, [{:eldap_entry, '', []}], [], []}}
end,
close: fn _connection ->
send(self(), :close_connection)

View file

@ -48,38 +48,42 @@ test "it is enabled if remote_ip_found flag doesn't exist" do
refute RateLimiter.disabled?(build_conn())
end
@tag :erratic
test "it restricts based on config values" do
limiter_name = :test_plug_opts
scale = 80
limit = 5
clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
clear_config([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1})
clear_config([:rate_limit, limiter_name], {scale, limit})
plug_opts = RateLimiter.init(name: limiter_name)
conn = build_conn(:get, "/")
for i <- 1..5 do
conn = RateLimiter.call(conn, plug_opts)
assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
Process.sleep(10)
for _ <- 1..5 do
conn_limited = RateLimiter.call(conn, plug_opts)
refute conn_limited.status == Conn.Status.code(:too_many_requests)
refute conn_limited.resp_body
refute conn_limited.halted
end
conn = RateLimiter.call(conn, plug_opts)
assert %{"error" => "Throttled"} = ConnTest.json_response(conn, :too_many_requests)
assert conn.halted
conn_limited = RateLimiter.call(conn, plug_opts)
assert %{"error" => "Throttled"} = ConnTest.json_response(conn_limited, :too_many_requests)
assert conn_limited.halted
Process.sleep(50)
expire_ttl(conn, limiter_name)
conn = build_conn(:get, "/")
for _ <- 1..5 do
conn_limited = RateLimiter.call(conn, plug_opts)
conn = RateLimiter.call(conn, plug_opts)
assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts)
refute conn_limited.status == Conn.Status.code(:too_many_requests)
refute conn_limited.resp_body
refute conn_limited.halted
end
refute conn.status == Conn.Status.code(:too_many_requests)
refute conn.resp_body
refute conn.halted
conn_limited = RateLimiter.call(conn, plug_opts)
assert %{"error" => "Throttled"} = ConnTest.json_response(conn_limited, :too_many_requests)
assert conn_limited.halted
end
describe "options" do
@ -263,4 +267,12 @@ test "doesn't crash due to a race condition when multiple requests are made at t
refute {:err, :not_found} == RateLimiter.inspect_bucket(conn, limiter_name, opts)
end
def expire_ttl(%{remote_ip: remote_ip} = _conn, bucket_name_root) do
bucket_name = "anon:#{bucket_name_root}" |> String.to_atom()
key_name = "ip::#{remote_ip |> Tuple.to_list() |> Enum.join(".")}"
{:ok, bucket_value} = Cachex.get(bucket_name, key_name)
Cachex.put(bucket_name, key_name, bucket_value, ttl: -1)
end
end

View file

@ -200,6 +200,21 @@ test "renders title and body for pleroma:emoji_reaction activity" do
"New Reaction"
end
test "renders title and body for update activity" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "lorem ipsum"})
{:ok, activity} = CommonAPI.update(user, activity, %{status: "edited status"})
object = Object.normalize(activity, fetch: false)
assert Impl.format_body(%{activity: activity, type: "update"}, user, object) ==
"@#{user.nickname} edited a status"
assert Impl.format_title(%{activity: activity, type: "update"}) ==
"New Update"
end
test "renders title for create activity with direct visibility" do
user = insert(:user, nickname: "Bob")