Merge pull request 'Purge broken, unused and/or useless features' (#1008) from Oneric/akkoma:purge-broken into develop

Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/1008
This commit is contained in:
Oneric 2025-11-18 22:08:04 +00:00
commit 5e4475d61e
26 changed files with 184 additions and 578 deletions

View file

@ -1218,24 +1218,10 @@ Loads JSON generated from `config/descriptions.exs`.
## `GET /api/v1/pleroma/admin/stats`
### Stats
**DEPRECATED; DO NOT USE**!!
- Query Params:
- *optional* `instance`: **string** instance hostname (without protocol) to get stats for
- Example: `https://mypleroma.org/api/v1/pleroma/admin/stats?instance=lain.com`
- Response:
```json
{
"status_visibility": {
"direct": 739,
"private": 9,
"public": 17,
"unlisted": 14
}
}
```
Returned information is only stubbed out.
The endpoint will be removed entirely in an upcoming release.
## `GET /api/v1/pleroma/admin/oauth_app`

View file

@ -32,7 +32,7 @@ Home, public, hashtag & list timelines further accept:
## Statuses
- `visibility`: has additional possible values `list` and `local` (for local-only statuses)
- `visibility`: has additional possible value `local` (for local-only statuses)
- `emoji_reactions`: additional field since Akkoma 3.2.0; identical to `pleroma/emoji_reactions`
Has these additional fields under the `pleroma` object:
@ -216,7 +216,6 @@ Additional parameters can be added to the JSON body/Form data:
- `to`: A list of nicknames (like `admin@otp.akkoma.dev` or `admin` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for post visibility are not affected by this and will still apply.
- `visibility`: string, besides standard MastoAPI values (`direct`, `private`, `unlisted`, `local` or `public`) it can be used to address a List by setting it to `list:LIST_ID`.
- `expires_in`: The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour.
- `in_reply_to_conversation_id`: Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`.
## GET `/api/v1/statuses`

View file

@ -376,13 +376,8 @@ See [Admin-API](admin_api.md)
Pleroma Conversations have the same general structure that Mastodon Conversations have. The behavior differs in the following ways when using these endpoints:
1. Pleroma Conversations never add or remove recipients, unless explicitly changed by the user.
1. Pleroma Conversations never add or remove recipients (`accounts` key), unless explicitly changed by the user.
2. Pleroma Conversations statuses can be requested by Conversation id.
3. Pleroma Conversations can be replied to.
Conversations have the additional field `recipients` under the `pleroma` key. This holds a list of all the accounts that will receive a message in this conversation.
The status posting endpoint takes an additional parameter, `in_reply_to_conversation_id`, which, when set, will set the visiblity to direct and address only the people who are the recipients of that Conversation.
⚠ Conversation IDs can be found in direct messages with the `pleroma.direct_conversation_id` key, do not confuse it with `pleroma.conversation_id`.

View file

@ -267,17 +267,33 @@ special meaning to the potential local-scope identifier.
however those are also shown publicly on the local web interface
and are thus visible to non-members.
## List post scope
Messages originally addressed to a custom list will contain
a `listMessage` field with an unresolvable pseudo ActivityPub id.
# Deprecated and Removed Extensions
The following extensions were used in the past but have been dropped.
Documentation is retained here as a reference and since old objects might
still contains related fields.
## List post scope
Messages originally addressed to a custom list will contain
a `listMessage` field with an unresolvable pseudo ActivityPub id.
!!! note
The concept did not work out too well in practice with even remote servers
recognising the `listMessage` extension being unaware of the state of the
list and resulting weird desyncs in thread display and handling between
servers.
As it was it also never found its way in any known clients or frontends.
A more consistent superset of what this was able to actually do
can be achieved without ActivityPub extensions by explicitly addressing
all intended participants without inline mentions.
While true federated and moderated "lists" or "groups"
will need more work and a different approach.
Thus suport for it was removed and it is recommended
to not create any new implementation of it.
## Actor endpoints
The following endpoints used to be present:

View file

@ -1,68 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.RefreshCounterCache do
@shortdoc "Refreshes counter cache"
use Mix.Task
alias Pleroma.Activity
alias Pleroma.CounterCache
alias Pleroma.Repo
import Ecto.Query
def run([]) do
Mix.Pleroma.start_pleroma()
instances =
Activity
|> distinct([a], true)
|> select([a], fragment("split_part(?, '/', 3)", a.actor))
|> Repo.all()
instances
|> Enum.with_index(1)
|> Enum.each(fn {instance, i} ->
counters = instance_counters(instance)
CounterCache.set(instance, counters)
Mix.Pleroma.shell_info(
"[#{i}/#{length(instances)}] Setting #{instance} counters: #{inspect(counters)}"
)
end)
Mix.Pleroma.shell_info("Done")
end
defp instance_counters(instance) do
counters = %{"public" => 0, "unlisted" => 0, "private" => 0, "direct" => 0}
Activity
|> where([a], fragment("(? ->> 'type'::text) = 'Create'", a.data))
|> where([a], fragment("split_part(?, '/', 3) = ?", a.actor, ^instance))
|> select(
[a],
{fragment(
"activity_visibility(?, ?, ?)",
a.actor,
a.recipients,
a.data
), count(a.id)}
)
|> group_by(
[a],
fragment(
"activity_visibility(?, ?, ?)",
a.actor,
a.recipients,
a.data
)
)
|> Repo.all(timeout: :timer.minutes(30))
|> Enum.reduce(counters, fn {visibility, count}, acc ->
Map.put(acc, visibility, count)
end)
end
end

View file

@ -22,6 +22,27 @@ defmodule Pleroma.Config.DeprecationWarnings do
"\n* `config :pleroma, :instance, :quarantined_instances` is now covered by `:pleroma, :mrf_simple, :reject`"}
]
def check_skip_thread_containment do
# The default in config/config.exs is "true" since 593b8b1e6a8502cca9bf5559b8bec86f172bbecb
# but when the default is retrieved in code the fallback is still "false"
uses_thread_visibility_filtering = !Config.get([:instance, :skip_thread_containment], false)
if uses_thread_visibility_filtering do
Logger.warning("""
!!!DEPRECATION WARNING!!!
Your config is explicitly enabling thread-based visibility containment by setting the below:
```
config :pleroma, :instance, skip_thread_containment: false
```
This feature comes with a very high performance overhead and is considered for removal.
If you actually need or strongly prefer keeping it, speak up NOW(!) by filing a ticket at
https://akkoma.dev/AkkomaGang/akkoma/issues
Complaints only after the removal happened are much less likely to have any effect.
""")
end
end
def check_exiftool_filter do
filters = Config.get([Pleroma.Upload]) |> Keyword.get(:filters, [])
@ -222,7 +243,8 @@ def warn do
check_http_adapter(),
check_uploader_base_url_set(),
check_uploader_base_url_is_not_base_domain(),
check_exiftool_filter()
check_exiftool_filter(),
check_skip_thread_containment()
]
|> Enum.reduce(:ok, fn
:ok, :ok -> :ok

View file

@ -1,79 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.CounterCache do
alias Pleroma.CounterCache
alias Pleroma.Repo
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query
schema "counter_cache" do
field(:instance, :string)
field(:public, :integer)
field(:unlisted, :integer)
field(:private, :integer)
field(:direct, :integer)
end
def changeset(struct, params) do
struct
|> cast(params, [:instance, :public, :unlisted, :private, :direct])
|> validate_required([:instance])
|> unique_constraint(:instance)
end
def get_by_instance(instance) do
CounterCache
|> select([c], %{
"public" => c.public,
"unlisted" => c.unlisted,
"private" => c.private,
"direct" => c.direct
})
|> where([c], c.instance == ^instance)
|> Repo.one()
|> case do
nil -> %{"public" => 0, "unlisted" => 0, "private" => 0, "direct" => 0}
val -> val
end
end
def get_sum do
CounterCache
|> select([c], %{
"public" => type(sum(c.public), :integer),
"unlisted" => type(sum(c.unlisted), :integer),
"private" => type(sum(c.private), :integer),
"direct" => type(sum(c.direct), :integer)
})
|> Repo.one()
end
def set(instance, values) do
params =
Enum.reduce(
["public", "private", "unlisted", "direct"],
%{"instance" => instance},
fn param, acc ->
Map.put_new(acc, param, Map.get(values, param, 0))
end
)
%CounterCache{}
|> changeset(params)
|> Repo.insert(
on_conflict: [
set: [
public: params["public"],
private: params["private"],
unlisted: params["unlisted"],
direct: params["direct"]
]
],
returning: true,
conflict_target: :instance
)
end
end

View file

@ -7,7 +7,6 @@ defmodule Pleroma.Stats do
import Ecto.Query
alias Pleroma.CounterCache
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Instances.Instance
@ -107,15 +106,6 @@ def calculate_stat_data do
}
end
@spec get_status_visibility_count(String.t() | nil) :: map()
def get_status_visibility_count(instance \\ nil) do
if is_nil(instance) do
CounterCache.get_sum()
else
CounterCache.get_by_instance(instance)
end
end
@impl true
def handle_continue(:calculate_stats, _) do
stats = calculate_stat_data()

View file

@ -53,25 +53,11 @@ def is_direct?(activity) do
!is_public?(activity) && !is_private?(activity)
end
def is_list?(%{data: %{"listMessage" => _}}), do: true
def is_list?(_), do: false
@spec visible_for_user?(Object.t() | Activity.t() | nil, User.t() | nil) :: boolean()
def visible_for_user?(%Object{data: %{"type" => "Tombstone"}}, _), do: false
def visible_for_user?(%Activity{actor: ap_id}, %User{ap_id: ap_id}), do: true
def visible_for_user?(%Object{data: %{"actor" => ap_id}}, %User{ap_id: ap_id}), do: true
def visible_for_user?(nil, _), do: false
def visible_for_user?(%Activity{data: %{"listMessage" => _}}, nil), do: false
def visible_for_user?(
%Activity{data: %{"listMessage" => list_ap_id}} = activity,
%User{} = user
) do
user.ap_id in activity.data["to"] ||
list_ap_id
|> Pleroma.List.get_by_ap_id()
|> Pleroma.List.member?(user)
end
def visible_for_user?(%{__struct__: module} = message, nil)
when module in [Activity, Object] do
@ -141,9 +127,6 @@ def get_visibility(object) do
object.data["directMessage"] == true ->
"direct"
is_binary(object.data["listMessage"]) ->
"list"
length(cc) > 0 ->
"private"

View file

@ -11,7 +11,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
alias Pleroma.Config
alias Pleroma.MFA
alias Pleroma.ModerationLog
alias Pleroma.Stats
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.AdminAPI
@ -399,10 +398,17 @@ def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" =
json(conn, "")
end
def stats(conn, params) do
counters = Stats.get_status_visibility_count(params["instance"])
json(conn, %{"status_visibility" => counters})
# Legacy endpoint, stubbed out for a transition period before removal
# (atm only used by admin-fe)
def stats(conn, _params) do
json(conn, %{
"status_visibility" => %{
"direct" => 0,
"private" => 0,
"public" => 0,
"unlisted" => 0
}
})
end
def create_backup(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do

View file

@ -553,10 +553,9 @@ defp create_request do
nullable: true,
anyOf: [
VisibilityScope,
%Schema{type: :string, description: "`list:LIST_ID`", example: "LIST:123"}
%Schema{type: :string, description: "scope name", example: "unlisted"}
],
description:
"Visibility of the posted status. Besides standard MastoAPI values (`direct`, `private`, `unlisted` or `public`) it can be used to address a List by setting it to `list:LIST_ID`"
description: "Visibility of the posted status."
},
expires_in: %Schema{
nullable: true,
@ -564,12 +563,6 @@ defp create_request do
description:
"The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour."
},
in_reply_to_conversation_id: %Schema{
nullable: true,
type: :string,
description:
"Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`."
},
quote_id: %Schema{
nullable: true,
type: :string,

View file

@ -9,6 +9,6 @@ defmodule Pleroma.Web.ApiSpec.Schemas.VisibilityScope do
title: "VisibilityScope",
description: "Status visibility",
type: :string,
enum: ["public", "unlisted", "local", "private", "direct", "list"]
enum: ["public", "unlisted", "local", "private", "direct"]
})
end

View file

@ -4,7 +4,6 @@
defmodule Pleroma.Web.CommonAPI do
alias Pleroma.Activity
alias Pleroma.Conversation.Participation
alias Pleroma.Object
alias Pleroma.ThreadMute
alias Pleroma.User
@ -294,23 +293,16 @@ def announce_visibility(_, %{visibility: visibility})
def announce_visibility(object, _), do: Visibility.get_visibility(object)
def get_visibility(_, _, %Participation{}), do: {"direct", "direct"}
def get_visibility(%{visibility: visibility}, in_reply_to, _)
def get_visibility(%{visibility: visibility}, in_reply_to)
when visibility in ~w{public local unlisted private direct},
do: {visibility, get_replied_to_visibility(in_reply_to)}
def get_visibility(%{visibility: "list:" <> list_id}, in_reply_to, _) do
visibility = {:list, String.to_integer(list_id)}
{visibility, get_replied_to_visibility(in_reply_to)}
end
def get_visibility(_, in_reply_to, _) when not is_nil(in_reply_to) do
def get_visibility(_, in_reply_to) when not is_nil(in_reply_to) do
visibility = get_replied_to_visibility(in_reply_to)
{visibility, visibility}
end
def get_visibility(_, in_reply_to, _), do: {"public", get_replied_to_visibility(in_reply_to)}
def get_visibility(_, nil), do: {"public", nil}
def get_replied_to_visibility(nil), do: nil

View file

@ -4,7 +4,6 @@
defmodule Pleroma.Web.CommonAPI.ActivityDraft do
alias Pleroma.Activity
alias Pleroma.Conversation.Participation
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.CommonAPI
@ -22,7 +21,6 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
full_payload: nil,
attachments: [],
in_reply_to: nil,
in_reply_to_conversation: nil,
language: nil,
content_map: %{},
quote_id: nil,
@ -56,7 +54,6 @@ def create(user, params) do
|> expires_at()
|> poll()
|> with_valid(&in_reply_to/1)
|> with_valid(&in_reply_to_conversation/1)
|> with_valid(&visibility/1)
|> with_valid(&quote_id/1)
|> content()
@ -133,11 +130,6 @@ defp in_reply_to(%{params: %{in_reply_to_status_id: %Activity{} = in_reply_to}}
defp in_reply_to(draft), do: draft
defp in_reply_to_conversation(draft) do
in_reply_to_conversation = Participation.get(draft.params[:in_reply_to_conversation_id])
%__MODULE__{draft | in_reply_to_conversation: in_reply_to_conversation}
end
defp quote_id(%{params: %{quote_id: ""}} = draft), do: draft
defp quote_id(%{params: %{quote_id: id}} = draft) when is_binary(id) do
@ -175,7 +167,7 @@ defp language(%{content_html: content} = draft) do
end
defp visibility(%{params: params} = draft) do
case CommonAPI.get_visibility(params, draft.in_reply_to, draft.in_reply_to_conversation) do
case CommonAPI.get_visibility(params, draft.in_reply_to) do
{visibility, "direct"} when visibility != "direct" ->
add_error(draft, dgettext("errors", "The message visibility must be direct"))
@ -298,7 +290,6 @@ defp changes(draft) do
object: draft.object,
additional: additional
}
|> Utils.maybe_add_list_data(draft.user, draft.visibility)
%__MODULE__{draft | changes: changes}
end

View file

@ -9,7 +9,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Calendar.Strftime
alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Conversation.Participation
alias Pleroma.Formatter
alias Pleroma.Object
alias Pleroma.Repo
@ -52,11 +51,6 @@ def get_attachment(media_id) do
@spec get_to_and_cc(ActivityDraft.t()) :: {list(String.t()), list(String.t())}
def get_to_and_cc(%{in_reply_to_conversation: %Participation{} = participation}) do
participation = Repo.preload(participation, :recipients)
{Enum.map(participation.recipients, & &1.ap_id), []}
end
def get_to_and_cc(%{visibility: visibility} = draft) do
# If the OP is a DM already, add the implicit actor
mentions =
@ -118,31 +112,12 @@ def get_to_and_cc_for_visibility("direct", _, _, mentions) do
{mentions, []}
end
def get_to_and_cc_for_visibility({:list, _}, _, _, mentions) do
{mentions, []}
end
def get_addressed_users(_, to) when is_list(to) do
User.get_ap_ids_by_nicknames(to)
end
def get_addressed_users(mentioned_users, _), do: mentioned_users
def maybe_add_list_data(activity_params, user, {:list, list_id}) do
case Pleroma.List.get(list_id, user) do
%Pleroma.List{} = list ->
activity_params
|> put_in([:additional, "bcc"], [list.ap_id])
|> put_in([:additional, "listMessage"], list.ap_id)
|> put_in([:object, "listMessage"], list.ap_id)
_ ->
activity_params
end
end
def maybe_add_list_data(activity_params, _, _), do: activity_params
def make_poll_data(%{"poll" => %{"expires_in" => expires_in}} = data)
when is_binary(expires_in) do
# In some cases mastofe sends out strings instead of integers
@ -248,10 +223,6 @@ def get_content_type(content_type) do
end
end
def make_context(%{in_reply_to_conversation: %Participation{} = participation}) do
Repo.preload(participation, :conversation).conversation.ap_id
end
def make_context(%{in_reply_to: %Activity{data: %{"context" => context}}}), do: context
def make_context(%{quote: %Activity{data: %{"context" => context}}}), do: context
def make_context(_), do: Utils.generate_context_id()

View file

@ -0,0 +1,93 @@
defmodule Pleroma.Repo.Migrations.PurgeCounterCache do
use Ecto.Migration
@function_name "update_status_visibility_counter_cache"
@trigger_name "status_visibility_counter_cache_trigger"
@table_name "counter_cache"
def up() do
execute("DROP TRIGGER IF EXISTS " <> @trigger_name <> " ON activities;")
execute("DROP FUNCTION IF EXISTS " <> @function_name <> ";")
# automatically drops indices
drop table(@table_name)
end
def down() do
create_if_not_exists table(:counter_cache) do
add(:instance, :string, null: false)
add(:direct, :bigint, null: false, default: 0)
add(:private, :bigint, null: false, default: 0)
add(:unlisted, :bigint, null: false, default: 0)
add(:public, :bigint, null: false, default: 0)
end
"""
CREATE OR REPLACE FUNCTION #{@function_name}()
RETURNS TRIGGER AS
$$
DECLARE
hostname character varying(255);
visibility_new character varying(64);
visibility_old character varying(64);
actor character varying(255);
BEGIN
IF TG_OP = 'DELETE' THEN
actor := OLD.actor;
ELSE
actor := NEW.actor;
END IF;
hostname := split_part(actor, '/', 3);
IF TG_OP = 'INSERT' THEN
visibility_new := activity_visibility(NEW.actor, NEW.recipients, NEW.data);
IF NEW.data->>'type' = 'Create'
AND visibility_new IN ('public', 'unlisted', 'private', 'direct') THEN
EXECUTE format('INSERT INTO "counter_cache" ("instance", %1$I) VALUES ($1, 1)
ON CONFLICT ("instance") DO
UPDATE SET %1$I = "counter_cache".%1$I + 1', visibility_new)
USING hostname;
END IF;
RETURN NEW;
ELSIF TG_OP = 'UPDATE' THEN
visibility_new := activity_visibility(NEW.actor, NEW.recipients, NEW.data);
visibility_old := activity_visibility(OLD.actor, OLD.recipients, OLD.data);
IF (NEW.data->>'type' = 'Create')
AND (OLD.data->>'type' = 'Create')
AND visibility_new != visibility_old
AND visibility_new IN ('public', 'unlisted', 'private', 'direct') THEN
EXECUTE format('UPDATE "counter_cache" SET
%1$I = greatest("counter_cache".%1$I - 1, 0),
%2$I = "counter_cache".%2$I + 1
WHERE "instance" = $1', visibility_old, visibility_new)
USING hostname;
END IF;
RETURN NEW;
ELSIF TG_OP = 'DELETE' THEN
IF OLD.data->>'type' = 'Create' THEN
visibility_old := activity_visibility(OLD.actor, OLD.recipients, OLD.data);
EXECUTE format('UPDATE "counter_cache" SET
%1$I = greatest("counter_cache".%1$I - 1, 0)
WHERE "instance" = $1', visibility_old)
USING hostname;
END IF;
RETURN OLD;
END IF;
END;
$$
LANGUAGE 'plpgsql';
"""
|> execute()
"""
CREATE TRIGGER #{@trigger_name}
BEFORE
INSERT
OR UPDATE of recipients, data
OR DELETE
ON activities
FOR EACH ROW
EXECUTE PROCEDURE #{@function_name}();
"""
|> execute()
end
end

View file

@ -522,7 +522,6 @@ test "We don't have unexpected tables which may contain objects that are referen
["conversation_participation_recipient_ships"],
["conversation_participations"],
["conversations"],
["counter_cache"],
["data_migration_failed_ids"],
["data_migrations"],
["deliveries"],

View file

@ -1,44 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.RefreshCounterCacheTest do
# Uses log capture, has to stay synchronous
use Pleroma.DataCase
alias Pleroma.Web.CommonAPI
import ExUnit.CaptureIO, only: [capture_io: 1]
import Pleroma.Factory
test "counts statuses" do
user = insert(:user)
other_user = insert(:user)
CommonAPI.post(user, %{visibility: "public", status: "hey"})
Enum.each(0..1, fn _ ->
CommonAPI.post(user, %{
visibility: "unlisted",
status: "hey"
})
end)
Enum.each(0..2, fn _ ->
CommonAPI.post(user, %{
visibility: "direct",
status: "hey @#{other_user.nickname}"
})
end)
Enum.each(0..3, fn _ ->
CommonAPI.post(user, %{
visibility: "private",
status: "hey"
})
end)
assert capture_io(fn -> Mix.Tasks.Pleroma.RefreshCounterCache.run([]) end) =~ "Done\n"
assert %{"direct" => 3, "private" => 4, "public" => 1, "unlisted" => 2} =
Pleroma.Stats.get_status_visibility_count()
end
end

View file

@ -29,14 +29,14 @@ test "for a new conversation or a reply, it doesn't mark the author's participat
user = insert(:user)
other_user = insert(:user)
{:ok, _} =
{:ok, op_activity} =
CommonAPI.post(user, %{status: "Hey @#{other_user.nickname}.", visibility: "direct"})
user = User.get_cached_by_id(user.id)
other_user = User.get_cached_by_id(other_user.id)
[%{read: true}] = Participation.for_user(user)
[%{read: false} = participation] = Participation.for_user(other_user)
[%{read: false}] = Participation.for_user(other_user)
assert Participation.unread_count(user) == 0
assert Participation.unread_count(other_user) == 1
@ -44,7 +44,7 @@ test "for a new conversation or a reply, it doesn't mark the author's participat
CommonAPI.post(other_user, %{
status: "Hey @#{user.nickname}.",
visibility: "direct",
in_reply_to_conversation_id: participation.id
in_reply_to_id: op_activity.id
})
user = User.get_cached_by_id(user.id)
@ -317,7 +317,7 @@ test "the conversation with the blocked user is not marked as unread on a reply"
blocked = insert(:user)
third_user = insert(:user)
{:ok, _direct1} =
{:ok, direct1} =
CommonAPI.post(blocker, %{
status: "Hi @#{third_user.nickname}, @#{blocked.nickname}",
visibility: "direct"
@ -327,27 +327,25 @@ test "the conversation with the blocked user is not marked as unread on a reply"
assert [%{read: true}] = Participation.for_user(blocker)
assert Participation.unread_count(blocker) == 0
assert [blocked_participation] = Participation.for_user(blocked)
# When it's a reply from the blocked user
{:ok, _direct2} =
{:ok, direct2} =
CommonAPI.post(blocked, %{
status: "reply",
visibility: "direct",
in_reply_to_conversation_id: blocked_participation.id
in_reply_to_id: direct1.id
})
assert [%{read: true}] = Participation.for_user(blocker)
assert Participation.unread_count(blocker) == 0
assert [third_user_participation] = Participation.for_user(third_user)
# When it's a reply from the third user
# When it's a reply from the third user to the blocked user
{:ok, _direct3} =
CommonAPI.post(third_user, %{
status: "reply",
visibility: "direct",
in_reply_to_conversation_id: third_user_participation.id
in_reply_to_id: direct2.id
})
assert [%{read: true}] = Participation.for_user(blocker)

View file

@ -8,7 +8,6 @@ defmodule Pleroma.StatsTest do
import Pleroma.Factory
alias Pleroma.Stats
alias Pleroma.Web.CommonAPI
describe "user count" do
test "it ignores internal users" do
@ -19,104 +18,4 @@ test "it ignores internal users" do
assert match?(%{stats: %{user_count: 1}}, Stats.calculate_stat_data())
end
end
describe "status visibility sum count" do
test "on new status" do
instance2 = "instance2.tld"
user = insert(:user)
other_user = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
CommonAPI.post(user, %{visibility: "public", status: "hey"})
Enum.each(0..1, fn _ ->
CommonAPI.post(user, %{
visibility: "unlisted",
status: "hey"
})
end)
Enum.each(0..2, fn _ ->
CommonAPI.post(user, %{
visibility: "direct",
status: "hey @#{other_user.nickname}"
})
end)
Enum.each(0..3, fn _ ->
CommonAPI.post(user, %{
visibility: "private",
status: "hey"
})
end)
assert %{"direct" => 3, "private" => 4, "public" => 1, "unlisted" => 2} =
Stats.get_status_visibility_count()
end
test "on status delete" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{visibility: "public", status: "hey"})
assert %{"public" => 1} = Stats.get_status_visibility_count()
CommonAPI.delete(activity.id, user)
assert %{"public" => 0} = Stats.get_status_visibility_count()
end
test "on status visibility update" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{visibility: "public", status: "hey"})
assert %{"public" => 1, "private" => 0} = Stats.get_status_visibility_count()
{:ok, _} = CommonAPI.update_activity_scope(activity.id, %{visibility: "private"})
assert %{"public" => 0, "private" => 1} = Stats.get_status_visibility_count()
end
test "doesn't count unrelated activities" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{visibility: "public", status: "hey"})
_ = CommonAPI.follow(user, other_user)
CommonAPI.favorite(other_user, activity.id)
CommonAPI.repeat(activity.id, other_user)
assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 0} =
Stats.get_status_visibility_count()
end
end
describe "status visibility by instance count" do
test "single instance" do
local_instance = Pleroma.Web.Endpoint.url() |> String.split("//") |> Enum.at(1)
instance2 = "instance2.tld"
user1 = insert(:user)
user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
CommonAPI.post(user1, %{visibility: "public", status: "hey"})
Enum.each(1..5, fn _ ->
CommonAPI.post(user1, %{
visibility: "unlisted",
status: "hey"
})
end)
Enum.each(1..10, fn _ ->
CommonAPI.post(user1, %{
visibility: "direct",
status: "hey @#{user2.nickname}"
})
end)
Enum.each(1..20, fn _ ->
CommonAPI.post(user2, %{
visibility: "private",
status: "hey"
})
end)
assert %{"direct" => 10, "private" => 0, "public" => 1, "unlisted" => 5} =
Stats.get_status_visibility_count(local_instance)
assert %{"direct" => 0, "private" => 20, "public" => 0, "unlisted" => 0} =
Stats.get_status_visibility_count(instance2)
end
end
end

View file

@ -36,12 +36,18 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
{:ok, local} = CommonAPI.post(user, %{status: "@#{mentioned.nickname}", visibility: "local"})
{:ok, list} =
# list visibility is no longer supported, but we want to check any
# leftover entreis are handled sensibly, so we nned to manually fix up the data
{:ok, list_activity} =
CommonAPI.post(user, %{
status: "@#{mentioned.nickname}",
visibility: "list:#{list.id}"
visibility: "direct"
})
list_object = Object.normalize(list_activity)
{:ok, list_object} = Object.update_data(list_object, %{"listMessage" => list.ap_id})
list_activity = %Activity{list_activity | object: list_object}
%{
public: public,
private: private,
@ -51,7 +57,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
mentioned: mentioned,
following: following,
unrelated: unrelated,
list: list,
list: list_activity,
local: local,
remote: remote
}
@ -69,8 +75,8 @@ test "is_direct?", %{
refute Visibility.is_direct?(public)
refute Visibility.is_direct?(private)
refute Visibility.is_direct?(unlisted)
assert Visibility.is_direct?(list)
refute Visibility.is_direct?(local)
assert Visibility.is_direct?(list)
end
test "is_public?", %{
@ -105,22 +111,6 @@ test "is_private?", %{
refute Visibility.is_private?(local)
end
test "is_list?", %{
public: public,
private: private,
direct: direct,
unlisted: unlisted,
list: list,
local: local
} do
refute Visibility.is_list?(direct)
refute Visibility.is_list?(public)
refute Visibility.is_list?(private)
refute Visibility.is_list?(unlisted)
assert Visibility.is_list?(list)
refute Visibility.is_list?(local)
end
test "visible_for_user? Activity", %{
public: public,
private: private,
@ -177,9 +167,6 @@ test "visible_for_user? Activity", %{
refute Visibility.visible_for_user?(direct, nil)
refute Visibility.visible_for_user?(local, nil)
# Visible for a list member
assert Visibility.visible_for_user?(list, unrelated)
# Local not visible to remote user
refute Visibility.visible_for_user?(local, remote)
end
@ -270,15 +257,16 @@ test "get_visibility", %{
assert Visibility.get_visibility(private) == "private"
assert Visibility.get_visibility(direct) == "direct"
assert Visibility.get_visibility(unlisted) == "unlisted"
assert Visibility.get_visibility(list) == "list"
# legacy, no longer supported visibility type doesn't leak out now
assert Visibility.get_visibility(list) == "direct"
end
test "get_visibility with directMessage flag" do
assert Visibility.get_visibility(%{data: %{"directMessage" => true}}) == "direct"
end
test "get_visibility with listMessage flag" do
assert Visibility.get_visibility(%{data: %{"listMessage" => ""}}) == "list"
test "get_visibility treats legacy list messages as direct" do
assert Visibility.get_visibility(%{data: %{"listMessage" => ""}}) == "direct"
end
describe "entire_thread_visible_for_user?/2" do

View file

@ -808,41 +808,6 @@ test "it resend emails for two users", %{conn: conn, admin: admin} do
end
end
describe "/api/v1/pleroma/admin/stats" do
test "status visibility count", %{conn: conn} do
user = insert(:user)
CommonAPI.post(user, %{visibility: "public", status: "hey"})
CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
response =
conn
|> get("/api/v1/pleroma/admin/stats")
|> json_response(200)
assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
response["status_visibility"]
end
test "by instance", %{conn: conn} do
user1 = insert(:user)
instance2 = "instance2.tld"
user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
CommonAPI.post(user1, %{visibility: "public", status: "hey"})
CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
CommonAPI.post(user2, %{visibility: "private", status: "hey"})
response =
conn
|> get("/api/v1/pleroma/admin/stats", instance: instance2)
|> json_response(200)
assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
response["status_visibility"]
end
end
describe "/api/v1/pleroma/backups" do
test "it creates a backup", %{conn: conn} do
admin = %{id: admin_id, nickname: admin_nickname} = insert(:user, is_admin: true)

View file

@ -609,27 +609,6 @@ test "returns [] when not pass media_ids" do
end
end
describe "maybe_add_list_data/3" do
test "adds list params when found user list" do
user = insert(:user)
{:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", user)
assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) ==
%{
additional: %{"bcc" => [list.ap_id], "listMessage" => list.ap_id},
object: %{"listMessage" => list.ap_id}
}
end
test "returns original params when list not found" do
user = insert(:user)
{:ok, %Pleroma.List{} = list} = Pleroma.List.create("title", insert(:user))
assert Utils.maybe_add_list_data(%{additional: %{}, object: %{}}, user, {:list, list.id}) ==
%{additional: %{}, object: %{}}
end
end
describe "maybe_add_attachments/3" do
test "returns parsed results when attachment_links is false" do
assert Utils.maybe_add_attachments(

View file

@ -318,49 +318,6 @@ test "repeating race condition" do
assert object.data["announcement_count"] == 20
end
test "when replying to a conversation / participation, it will set the correct context id even if no explicit reply_to is given" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
[participation] = Participation.for_user(user)
{:ok, convo_reply} =
CommonAPI.post(user, %{status: ".", in_reply_to_conversation_id: participation.id})
assert Visibility.is_direct?(convo_reply)
assert activity.data["context"] == convo_reply.data["context"]
end
test "when replying to a conversation / participation, it only mentions the recipients explicitly declared in the participation" do
har = insert(:user)
jafnhar = insert(:user)
tridi = insert(:user)
{:ok, activity} =
CommonAPI.post(har, %{
status: "@#{jafnhar.nickname} hey",
visibility: "direct"
})
assert har.ap_id in activity.recipients
assert jafnhar.ap_id in activity.recipients
[participation] = Participation.for_user(har)
{:ok, activity} =
CommonAPI.post(har, %{
status: "I don't really like @#{tridi.nickname}",
visibility: "direct",
in_reply_to_status_id: activity.id,
in_reply_to_conversation_id: participation.id
})
assert har.ap_id in activity.recipients
assert jafnhar.ap_id in activity.recipients
refute tridi.ap_id in activity.recipients
end
test "with the safe_dm_mention option set, it does not mention people beyond the initial tags" do
har = insert(:user)
jafnhar = insert(:user)
@ -543,17 +500,6 @@ test "replying with a direct message will NOT auto-add the author of the reply t
refute user.ap_id in secret_answer.recipients
end
test "it allows to address a list" do
user = insert(:user)
{:ok, list} = Pleroma.List.create("foo", user)
{:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
assert activity.data["bcc"] == [list.ap_id]
assert activity.recipients == [list.ap_id, user.ap_id]
assert activity.data["listMessage"] == list.ap_id
end
test "it adds the htmlMFM term to MFM posts and properly processes it" do
user = insert(:user)

View file

@ -942,18 +942,6 @@ test "does not embed a relationship in the account in reposts" do
assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec())
end
test "visibility/list" do
user = insert(:user)
{:ok, list} = Pleroma.List.create("foo", user)
{:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
status = StatusView.render("show.json", activity: activity)
assert status.visibility == "list"
end
test "has a field for parent visibility" do
user = insert(:user)
poster = insert(:user)

View file

@ -45,8 +45,7 @@ test "/api/v1/pleroma/conversations/:id/statuses" do
{:ok, activity_two} =
CommonAPI.post(other_user, %{
status: "Hi!",
in_reply_to_status_id: activity.id,
in_reply_to_conversation_id: participation.id
in_reply_to_status_id: activity.id
})
result =
@ -63,8 +62,7 @@ test "/api/v1/pleroma/conversations/:id/statuses" do
{:ok, %{id: id_three}} =
CommonAPI.post(other_user, %{
status: "Bye!",
in_reply_to_status_id: activity.id,
in_reply_to_conversation_id: participation.id
in_reply_to_status_id: activity.id
})
assert [%{"id" => ^id_two}, %{"id" => ^id_three}] =