Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into qdrant-search-2
This commit is contained in:
commit
7923ede8ba
|
@ -0,0 +1 @@
|
||||||
|
Add instance rules
|
|
@ -0,0 +1 @@
|
||||||
|
Startup detection for configured MRF modules that are missing or incorrectly defined
|
|
@ -0,0 +1 @@
|
||||||
|
Web Push notifications are no longer generated for muted/blocked threads and users.
|
|
@ -1751,3 +1751,53 @@ Note that this differs from the Mastodon API variant: Mastodon API only returns
|
||||||
```json
|
```json
|
||||||
{}
|
{}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## `GET /api/v1/pleroma/admin/rules`
|
||||||
|
|
||||||
|
### List rules
|
||||||
|
|
||||||
|
- Response: JSON, list of rules
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"priority": 1,
|
||||||
|
"text": "There are no rules",
|
||||||
|
"hint": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## `POST /api/v1/pleroma/admin/rules`
|
||||||
|
|
||||||
|
### Create a rule
|
||||||
|
|
||||||
|
- Params:
|
||||||
|
- `text`: string, required, rule content
|
||||||
|
- `hint`: string, optional, rule description
|
||||||
|
- `priority`: integer, optional, rule ordering priority
|
||||||
|
|
||||||
|
- Response: JSON, a single rule
|
||||||
|
|
||||||
|
## `PATCH /api/v1/pleroma/admin/rules/:id`
|
||||||
|
|
||||||
|
### Update a rule
|
||||||
|
|
||||||
|
- Params:
|
||||||
|
- `text`: string, optional, rule content
|
||||||
|
- `hint`: string, optional, rule description
|
||||||
|
- `priority`: integer, optional, rule ordering priority
|
||||||
|
|
||||||
|
- Response: JSON, a single rule
|
||||||
|
|
||||||
|
## `DELETE /api/v1/pleroma/admin/rules/:id`
|
||||||
|
|
||||||
|
### Delete a rule
|
||||||
|
|
||||||
|
- Response: JSON, empty object
|
||||||
|
|
||||||
|
```json
|
||||||
|
{}
|
||||||
|
```
|
||||||
|
|
|
@ -28,6 +28,7 @@ def verify! do
|
||||||
|> check_welcome_message_config!()
|
|> check_welcome_message_config!()
|
||||||
|> check_rum!()
|
|> check_rum!()
|
||||||
|> check_repo_pool_size!()
|
|> check_repo_pool_size!()
|
||||||
|
|> check_mrfs()
|
||||||
|> handle_result()
|
|> handle_result()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -234,4 +235,25 @@ defp check_filter(filter, command_required) do
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp check_mrfs(:ok) do
|
||||||
|
mrfs = Config.get!([:mrf, :policies])
|
||||||
|
|
||||||
|
missing_mrfs =
|
||||||
|
Enum.reduce(mrfs, [], fn x, acc ->
|
||||||
|
if Code.ensure_compiled(x) do
|
||||||
|
acc
|
||||||
|
else
|
||||||
|
acc ++ [x]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if Enum.empty?(missing_mrfs) do
|
||||||
|
:ok
|
||||||
|
else
|
||||||
|
{:error, "The following MRF modules are configured but missing: #{inspect(missing_mrfs)}"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp check_mrfs(result), do: result
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,7 +19,8 @@ defmodule Pleroma.Constants do
|
||||||
"context_id",
|
"context_id",
|
||||||
"deleted_activity_id",
|
"deleted_activity_id",
|
||||||
"pleroma_internal",
|
"pleroma_internal",
|
||||||
"generator"
|
"generator",
|
||||||
|
"rules"
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -361,36 +361,32 @@ def dismiss(%{id: user_id} = _user, id) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec create_notifications(Activity.t(), keyword()) :: {:ok, [Notification.t()] | []}
|
@spec create_notifications(Activity.t()) :: {:ok, [Notification.t()] | []}
|
||||||
def create_notifications(activity, options \\ [])
|
def create_notifications(activity)
|
||||||
|
|
||||||
def create_notifications(%Activity{data: %{"to" => _, "type" => "Create"}} = activity, options) do
|
def create_notifications(%Activity{data: %{"to" => _, "type" => "Create"}} = activity) do
|
||||||
object = Object.normalize(activity, fetch: false)
|
object = Object.normalize(activity, fetch: false)
|
||||||
|
|
||||||
if object && object.data["type"] == "Answer" do
|
if object && object.data["type"] == "Answer" do
|
||||||
{:ok, []}
|
{:ok, []}
|
||||||
else
|
else
|
||||||
do_create_notifications(activity, options)
|
do_create_notifications(activity)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_notifications(%Activity{data: %{"type" => type}} = activity, options)
|
def create_notifications(%Activity{data: %{"type" => type}} = activity)
|
||||||
when type in ["Follow", "Like", "Announce", "Move", "EmojiReact", "Flag", "Update"] do
|
when type in ["Follow", "Like", "Announce", "Move", "EmojiReact", "Flag", "Update"] do
|
||||||
do_create_notifications(activity, options)
|
do_create_notifications(activity)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_notifications(_, _), do: {:ok, []}
|
def create_notifications(_), do: {:ok, []}
|
||||||
|
|
||||||
defp do_create_notifications(%Activity{} = activity, options) do
|
defp do_create_notifications(%Activity{} = activity) do
|
||||||
do_send = Keyword.get(options, :do_send, true)
|
enabled_receivers = get_notified_from_activity(activity)
|
||||||
|
|
||||||
{enabled_receivers, disabled_receivers} = get_notified_from_activity(activity)
|
|
||||||
potential_receivers = enabled_receivers ++ disabled_receivers
|
|
||||||
|
|
||||||
notifications =
|
notifications =
|
||||||
Enum.map(potential_receivers, fn user ->
|
Enum.map(enabled_receivers, fn user ->
|
||||||
do_send = do_send && user in enabled_receivers
|
create_notification(activity, user)
|
||||||
create_notification(activity, user, do_send: do_send)
|
|
||||||
end)
|
end)
|
||||||
|> Enum.reject(&is_nil/1)
|
|> Enum.reject(&is_nil/1)
|
||||||
|
|
||||||
|
@ -450,7 +446,6 @@ defp type_from_activity_object(%{data: %{"type" => "Create"}} = activity) do
|
||||||
|
|
||||||
# TODO move to sql, too.
|
# TODO move to sql, too.
|
||||||
def create_notification(%Activity{} = activity, %User{} = user, opts \\ []) do
|
def create_notification(%Activity{} = activity, %User{} = user, opts \\ []) do
|
||||||
do_send = Keyword.get(opts, :do_send, true)
|
|
||||||
type = Keyword.get(opts, :type, type_from_activity(activity))
|
type = Keyword.get(opts, :type, type_from_activity(activity))
|
||||||
|
|
||||||
unless skip?(activity, user, opts) do
|
unless skip?(activity, user, opts) do
|
||||||
|
@ -465,11 +460,6 @@ def create_notification(%Activity{} = activity, %User{} = user, opts \\ []) do
|
||||||
|> Marker.multi_set_last_read_id(user, "notifications")
|
|> Marker.multi_set_last_read_id(user, "notifications")
|
||||||
|> Repo.transaction()
|
|> Repo.transaction()
|
||||||
|
|
||||||
if do_send do
|
|
||||||
Streamer.stream(["user", "user:notification"], notification)
|
|
||||||
Push.send(notification)
|
|
||||||
end
|
|
||||||
|
|
||||||
notification
|
notification
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -527,10 +517,7 @@ def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, lo
|
||||||
|> exclude_relationship_restricted_ap_ids(activity)
|
|> exclude_relationship_restricted_ap_ids(activity)
|
||||||
|> exclude_thread_muter_ap_ids(activity)
|
|> exclude_thread_muter_ap_ids(activity)
|
||||||
|
|
||||||
notification_enabled_users =
|
Enum.filter(potential_receivers, fn u -> u.ap_id in notification_enabled_ap_ids end)
|
||||||
Enum.filter(potential_receivers, fn u -> u.ap_id in notification_enabled_ap_ids end)
|
|
||||||
|
|
||||||
{notification_enabled_users, potential_receivers -- notification_enabled_users}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_notified_from_activity(_, _local_only), do: {[], []}
|
def get_notified_from_activity(_, _local_only), do: {[], []}
|
||||||
|
@ -643,6 +630,7 @@ def skip?(activity, user, opts \\ [])
|
||||||
def skip?(%Activity{} = activity, %User{} = user, opts) do
|
def skip?(%Activity{} = activity, %User{} = user, opts) do
|
||||||
[
|
[
|
||||||
:self,
|
:self,
|
||||||
|
:internal,
|
||||||
:invisible,
|
:invisible,
|
||||||
:block_from_strangers,
|
:block_from_strangers,
|
||||||
:recently_followed,
|
:recently_followed,
|
||||||
|
@ -662,6 +650,12 @@ def skip?(:self, %Activity{} = activity, %User{} = user, opts) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def skip?(:internal, %Activity{} = activity, _user, _opts) do
|
||||||
|
actor = activity.data["actor"]
|
||||||
|
user = User.get_cached_by_ap_id(actor)
|
||||||
|
User.internal?(user)
|
||||||
|
end
|
||||||
|
|
||||||
def skip?(:invisible, %Activity{} = activity, _user, _opts) do
|
def skip?(:invisible, %Activity{} = activity, _user, _opts) do
|
||||||
actor = activity.data["actor"]
|
actor = activity.data["actor"]
|
||||||
user = User.get_cached_by_ap_id(actor)
|
user = User.get_cached_by_ap_id(actor)
|
||||||
|
@ -748,4 +742,12 @@ def mark_context_as_read(%User{id: id}, context) do
|
||||||
)
|
)
|
||||||
|> Repo.update_all(set: [seen: true])
|
|> Repo.update_all(set: [seen: true])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec send(list(Notification.t())) :: :ok
|
||||||
|
def send(notifications) do
|
||||||
|
Enum.each(notifications, fn notification ->
|
||||||
|
Streamer.stream(["user", "user:notification"], notification)
|
||||||
|
Push.send(notification)
|
||||||
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Rule do
|
||||||
|
use Ecto.Schema
|
||||||
|
|
||||||
|
import Ecto.Changeset
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.Rule
|
||||||
|
|
||||||
|
schema "rules" do
|
||||||
|
field(:priority, :integer, default: 0)
|
||||||
|
field(:text, :string)
|
||||||
|
field(:hint, :string)
|
||||||
|
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
|
||||||
|
def changeset(%Rule{} = rule, params \\ %{}) do
|
||||||
|
rule
|
||||||
|
|> cast(params, [:priority, :text, :hint])
|
||||||
|
|> validate_required([:text])
|
||||||
|
end
|
||||||
|
|
||||||
|
def query do
|
||||||
|
Rule
|
||||||
|
|> order_by(asc: :priority)
|
||||||
|
|> order_by(asc: :id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(ids) when is_list(ids) do
|
||||||
|
from(r in __MODULE__, where: r.id in ^ids)
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(id), do: Repo.get(__MODULE__, id)
|
||||||
|
|
||||||
|
def exists?(id) do
|
||||||
|
from(r in __MODULE__, where: r.id == ^id)
|
||||||
|
|> Repo.exists?()
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(params) do
|
||||||
|
{:ok, rule} =
|
||||||
|
%Rule{}
|
||||||
|
|> changeset(params)
|
||||||
|
|> Repo.insert()
|
||||||
|
|
||||||
|
rule
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(params, id) do
|
||||||
|
{:ok, rule} =
|
||||||
|
get(id)
|
||||||
|
|> changeset(params)
|
||||||
|
|> Repo.update()
|
||||||
|
|
||||||
|
rule
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(id) do
|
||||||
|
get(id)
|
||||||
|
|> Repo.delete()
|
||||||
|
end
|
||||||
|
end
|
|
@ -200,7 +200,8 @@ defp insert_activity_with_expiration(data, local, recipients) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def notify_and_stream(activity) do
|
def notify_and_stream(activity) do
|
||||||
Notification.create_notifications(activity)
|
{:ok, notifications} = Notification.create_notifications(activity)
|
||||||
|
Notification.send(notifications)
|
||||||
|
|
||||||
original_activity =
|
original_activity =
|
||||||
case activity do
|
case activity do
|
||||||
|
@ -1259,6 +1260,15 @@ defp restrict_quote_url(query, %{quote_url: quote_url}) do
|
||||||
|
|
||||||
defp restrict_quote_url(query, _), do: query
|
defp restrict_quote_url(query, _), do: query
|
||||||
|
|
||||||
|
defp restrict_rule(query, %{rule_id: rule_id}) do
|
||||||
|
from(
|
||||||
|
activity in query,
|
||||||
|
where: fragment("(?)->'rules' \\? (?)", activity.data, ^rule_id)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict_rule(query, _), do: query
|
||||||
|
|
||||||
defp exclude_poll_votes(query, %{include_poll_votes: true}), do: query
|
defp exclude_poll_votes(query, %{include_poll_votes: true}), do: query
|
||||||
|
|
||||||
defp exclude_poll_votes(query, _) do
|
defp exclude_poll_votes(query, _) do
|
||||||
|
@ -1421,6 +1431,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do
|
||||||
|> restrict_instance(opts)
|
|> restrict_instance(opts)
|
||||||
|> restrict_announce_object_actor(opts)
|
|> restrict_announce_object_actor(opts)
|
||||||
|> restrict_filtered(opts)
|
|> restrict_filtered(opts)
|
||||||
|
|> restrict_rule(opts)
|
||||||
|> restrict_quote_url(opts)
|
|> restrict_quote_url(opts)
|
||||||
|> maybe_restrict_deactivated_users(opts)
|
|> maybe_restrict_deactivated_users(opts)
|
||||||
|> exclude_poll_votes(opts)
|
|> exclude_poll_votes(opts)
|
||||||
|
|
|
@ -21,7 +21,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
||||||
alias Pleroma.Web.ActivityPub.Builder
|
alias Pleroma.Web.ActivityPub.Builder
|
||||||
alias Pleroma.Web.ActivityPub.Pipeline
|
alias Pleroma.Web.ActivityPub.Pipeline
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.Push
|
|
||||||
alias Pleroma.Web.Streamer
|
alias Pleroma.Web.Streamer
|
||||||
alias Pleroma.Workers.PollWorker
|
alias Pleroma.Workers.PollWorker
|
||||||
|
|
||||||
|
@ -125,7 +124,7 @@ def handle(
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, notifications} = Notification.create_notifications(object, do_send: false)
|
{:ok, notifications} = Notification.create_notifications(object)
|
||||||
|
|
||||||
meta =
|
meta =
|
||||||
meta
|
meta
|
||||||
|
@ -184,7 +183,11 @@ def handle(%{data: %{"type" => "Like"}} = object, meta) do
|
||||||
liked_object = Object.get_by_ap_id(object.data["object"])
|
liked_object = Object.get_by_ap_id(object.data["object"])
|
||||||
Utils.add_like_to_object(object, liked_object)
|
Utils.add_like_to_object(object, liked_object)
|
||||||
|
|
||||||
Notification.create_notifications(object)
|
{:ok, notifications} = Notification.create_notifications(object)
|
||||||
|
|
||||||
|
meta =
|
||||||
|
meta
|
||||||
|
|> add_notifications(notifications)
|
||||||
|
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
end
|
end
|
||||||
|
@ -202,7 +205,7 @@ def handle(%{data: %{"type" => "Like"}} = object, meta) do
|
||||||
def handle(%{data: %{"type" => "Create"}} = activity, meta) do
|
def handle(%{data: %{"type" => "Create"}} = activity, meta) do
|
||||||
with {:ok, object, meta} <- handle_object_creation(meta[:object_data], activity, meta),
|
with {:ok, object, meta} <- handle_object_creation(meta[:object_data], activity, meta),
|
||||||
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
|
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
|
||||||
{:ok, notifications} = Notification.create_notifications(activity, do_send: false)
|
{:ok, notifications} = Notification.create_notifications(activity)
|
||||||
{:ok, _user} = ActivityPub.increase_note_count_if_public(user, object)
|
{:ok, _user} = ActivityPub.increase_note_count_if_public(user, object)
|
||||||
{:ok, _user} = ActivityPub.update_last_status_at_if_public(user, object)
|
{:ok, _user} = ActivityPub.update_last_status_at_if_public(user, object)
|
||||||
|
|
||||||
|
@ -256,11 +259,13 @@ def handle(%{data: %{"type" => "Announce"}} = object, meta) do
|
||||||
|
|
||||||
Utils.add_announce_to_object(object, announced_object)
|
Utils.add_announce_to_object(object, announced_object)
|
||||||
|
|
||||||
if !User.internal?(user) do
|
{:ok, notifications} = Notification.create_notifications(object)
|
||||||
Notification.create_notifications(object)
|
|
||||||
|
|
||||||
ap_streamer().stream_out(object)
|
if !User.internal?(user), do: ap_streamer().stream_out(object)
|
||||||
end
|
|
||||||
|
meta =
|
||||||
|
meta
|
||||||
|
|> add_notifications(notifications)
|
||||||
|
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
end
|
end
|
||||||
|
@ -281,7 +286,11 @@ def handle(%{data: %{"type" => "EmojiReact"}} = object, meta) do
|
||||||
reacted_object = Object.get_by_ap_id(object.data["object"])
|
reacted_object = Object.get_by_ap_id(object.data["object"])
|
||||||
Utils.add_emoji_reaction_to_object(object, reacted_object)
|
Utils.add_emoji_reaction_to_object(object, reacted_object)
|
||||||
|
|
||||||
Notification.create_notifications(object)
|
{:ok, notifications} = Notification.create_notifications(object)
|
||||||
|
|
||||||
|
meta =
|
||||||
|
meta
|
||||||
|
|> add_notifications(notifications)
|
||||||
|
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
end
|
end
|
||||||
|
@ -585,10 +594,7 @@ defp delete_object(object) do
|
||||||
|
|
||||||
defp send_notifications(meta) do
|
defp send_notifications(meta) do
|
||||||
Keyword.get(meta, :notifications, [])
|
Keyword.get(meta, :notifications, [])
|
||||||
|> Enum.each(fn notification ->
|
|> Notification.send()
|
||||||
Streamer.stream(["user", "user:notification"], notification)
|
|
||||||
Push.send(notification)
|
|
||||||
end)
|
|
||||||
|
|
||||||
meta
|
meta
|
||||||
end
|
end
|
||||||
|
|
|
@ -721,14 +721,18 @@ def make_listen_data(params, additional) do
|
||||||
|
|
||||||
#### Flag-related helpers
|
#### Flag-related helpers
|
||||||
@spec make_flag_data(map(), map()) :: map()
|
@spec make_flag_data(map(), map()) :: map()
|
||||||
def make_flag_data(%{actor: actor, context: context, content: content} = params, additional) do
|
def make_flag_data(
|
||||||
|
%{actor: actor, context: context, content: content} = params,
|
||||||
|
additional
|
||||||
|
) do
|
||||||
%{
|
%{
|
||||||
"type" => "Flag",
|
"type" => "Flag",
|
||||||
"actor" => actor.ap_id,
|
"actor" => actor.ap_id,
|
||||||
"content" => content,
|
"content" => content,
|
||||||
"object" => build_flag_object(params),
|
"object" => build_flag_object(params),
|
||||||
"context" => context,
|
"context" => context,
|
||||||
"state" => "open"
|
"state" => "open",
|
||||||
|
"rules" => Map.get(params, :rules, nil)
|
||||||
}
|
}
|
||||||
|> Map.merge(additional)
|
|> Map.merge(additional)
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.AdminAPI.RuleController do
|
||||||
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.Rule
|
||||||
|
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||||
|
|
||||||
|
import Pleroma.Web.ControllerHelper,
|
||||||
|
only: [
|
||||||
|
json_response: 3
|
||||||
|
]
|
||||||
|
|
||||||
|
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||||
|
|
||||||
|
plug(
|
||||||
|
OAuthScopesPlug,
|
||||||
|
%{scopes: ["admin:write"]}
|
||||||
|
when action in [:create, :update, :delete]
|
||||||
|
)
|
||||||
|
|
||||||
|
plug(OAuthScopesPlug, %{scopes: ["admin:read"]} when action == :index)
|
||||||
|
|
||||||
|
action_fallback(AdminAPI.FallbackController)
|
||||||
|
|
||||||
|
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.RuleOperation
|
||||||
|
|
||||||
|
def index(conn, _) do
|
||||||
|
rules =
|
||||||
|
Rule.query()
|
||||||
|
|> Repo.all()
|
||||||
|
|
||||||
|
render(conn, "index.json", rules: rules)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(%{body_params: params} = conn, _) do
|
||||||
|
rule =
|
||||||
|
params
|
||||||
|
|> Rule.create()
|
||||||
|
|
||||||
|
render(conn, "show.json", rule: rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(%{body_params: params} = conn, %{id: id}) do
|
||||||
|
rule =
|
||||||
|
params
|
||||||
|
|> Rule.update(id)
|
||||||
|
|
||||||
|
render(conn, "show.json", rule: rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(conn, %{id: id}) do
|
||||||
|
with {:ok, _} <- Rule.delete(id) do
|
||||||
|
json(conn, %{})
|
||||||
|
else
|
||||||
|
_ -> json_response(conn, :bad_request, "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,9 +6,11 @@ defmodule Pleroma.Web.AdminAPI.ReportView do
|
||||||
use Pleroma.Web, :view
|
use Pleroma.Web, :view
|
||||||
|
|
||||||
alias Pleroma.HTML
|
alias Pleroma.HTML
|
||||||
|
alias Pleroma.Rule
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.AdminAPI
|
alias Pleroma.Web.AdminAPI
|
||||||
alias Pleroma.Web.AdminAPI.Report
|
alias Pleroma.Web.AdminAPI.Report
|
||||||
|
alias Pleroma.Web.AdminAPI.RuleView
|
||||||
alias Pleroma.Web.CommonAPI.Utils
|
alias Pleroma.Web.CommonAPI.Utils
|
||||||
alias Pleroma.Web.MastodonAPI.StatusView
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
|
|
||||||
|
@ -46,7 +48,8 @@ def render("show.json", %{report: report, user: user, account: account, statuses
|
||||||
as: :activity
|
as: :activity
|
||||||
}),
|
}),
|
||||||
state: report.data["state"],
|
state: report.data["state"],
|
||||||
notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes})
|
notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes}),
|
||||||
|
rules: rules(Map.get(report.data, "rules", nil))
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -71,4 +74,16 @@ def render("show_note.json", %{
|
||||||
created_at: Utils.to_masto_date(inserted_at)
|
created_at: Utils.to_masto_date(inserted_at)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp rules(nil) do
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
defp rules(rule_ids) do
|
||||||
|
rules =
|
||||||
|
rule_ids
|
||||||
|
|> Rule.get()
|
||||||
|
|
||||||
|
render(RuleView, "index.json", rules: rules)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.AdminAPI.RuleView do
|
||||||
|
use Pleroma.Web, :view
|
||||||
|
|
||||||
|
require Pleroma.Constants
|
||||||
|
|
||||||
|
def render("index.json", %{rules: rules} = _opts) do
|
||||||
|
render_many(rules, __MODULE__, "show.json")
|
||||||
|
end
|
||||||
|
|
||||||
|
def render("show.json", %{rule: rule} = _opts) do
|
||||||
|
%{
|
||||||
|
id: to_string(rule.id),
|
||||||
|
priority: rule.priority,
|
||||||
|
text: rule.text,
|
||||||
|
hint: rule.hint
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -97,6 +97,7 @@ def spec(opts \\ []) do
|
||||||
"Frontend management",
|
"Frontend management",
|
||||||
"Instance configuration",
|
"Instance configuration",
|
||||||
"Instance documents",
|
"Instance documents",
|
||||||
|
"Instance rule managment",
|
||||||
"Invites",
|
"Invites",
|
||||||
"MediaProxy cache",
|
"MediaProxy cache",
|
||||||
"OAuth application management",
|
"OAuth application management",
|
||||||
|
|
|
@ -30,6 +30,12 @@ def index_operation do
|
||||||
report_state(),
|
report_state(),
|
||||||
"Filter by report state"
|
"Filter by report state"
|
||||||
),
|
),
|
||||||
|
Operation.parameter(
|
||||||
|
:rule_id,
|
||||||
|
:query,
|
||||||
|
%Schema{type: :string},
|
||||||
|
"Filter by selected rule id"
|
||||||
|
),
|
||||||
Operation.parameter(
|
Operation.parameter(
|
||||||
:limit,
|
:limit,
|
||||||
:query,
|
:query,
|
||||||
|
@ -169,6 +175,17 @@ defp report do
|
||||||
inserted_at: %Schema{type: :string, format: :"date-time"}
|
inserted_at: %Schema{type: :string, format: :"date-time"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
rules: %Schema{
|
||||||
|
type: :array,
|
||||||
|
items: %Schema{
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
id: %Schema{type: :string},
|
||||||
|
text: %Schema{type: :string},
|
||||||
|
hint: %Schema{type: :string, nullable: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ApiSpec.Admin.RuleOperation do
|
||||||
|
alias OpenApiSpex.Operation
|
||||||
|
alias OpenApiSpex.Schema
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
||||||
|
|
||||||
|
import Pleroma.Web.ApiSpec.Helpers
|
||||||
|
|
||||||
|
def open_api_operation(action) do
|
||||||
|
operation = String.to_existing_atom("#{action}_operation")
|
||||||
|
apply(__MODULE__, operation, [])
|
||||||
|
end
|
||||||
|
|
||||||
|
def index_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["Instance rule managment"],
|
||||||
|
summary: "Retrieve list of instance rules",
|
||||||
|
operationId: "AdminAPI.RuleController.index",
|
||||||
|
security: [%{"oAuth" => ["admin:read"]}],
|
||||||
|
responses: %{
|
||||||
|
200 =>
|
||||||
|
Operation.response("Response", "application/json", %Schema{
|
||||||
|
type: :array,
|
||||||
|
items: rule()
|
||||||
|
}),
|
||||||
|
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["Instance rule managment"],
|
||||||
|
summary: "Create new rule",
|
||||||
|
operationId: "AdminAPI.RuleController.create",
|
||||||
|
security: [%{"oAuth" => ["admin:write"]}],
|
||||||
|
parameters: admin_api_params(),
|
||||||
|
requestBody: request_body("Parameters", create_request(), required: true),
|
||||||
|
responses: %{
|
||||||
|
200 => Operation.response("Response", "application/json", rule()),
|
||||||
|
400 => Operation.response("Bad Request", "application/json", ApiError),
|
||||||
|
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["Instance rule managment"],
|
||||||
|
summary: "Modify existing rule",
|
||||||
|
operationId: "AdminAPI.RuleController.update",
|
||||||
|
security: [%{"oAuth" => ["admin:write"]}],
|
||||||
|
parameters: [Operation.parameter(:id, :path, :string, "Rule ID")],
|
||||||
|
requestBody: request_body("Parameters", update_request(), required: true),
|
||||||
|
responses: %{
|
||||||
|
200 => Operation.response("Response", "application/json", rule()),
|
||||||
|
400 => Operation.response("Bad Request", "application/json", ApiError),
|
||||||
|
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["Instance rule managment"],
|
||||||
|
summary: "Delete rule",
|
||||||
|
operationId: "AdminAPI.RuleController.delete",
|
||||||
|
parameters: [Operation.parameter(:id, :path, :string, "Rule ID")],
|
||||||
|
security: [%{"oAuth" => ["admin:write"]}],
|
||||||
|
responses: %{
|
||||||
|
200 => empty_object_response(),
|
||||||
|
404 => Operation.response("Not Found", "application/json", ApiError),
|
||||||
|
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp create_request do
|
||||||
|
%Schema{
|
||||||
|
type: :object,
|
||||||
|
required: [:text],
|
||||||
|
properties: %{
|
||||||
|
priority: %Schema{type: :integer},
|
||||||
|
text: %Schema{type: :string},
|
||||||
|
hint: %Schema{type: :string}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_request do
|
||||||
|
%Schema{
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
priority: %Schema{type: :integer},
|
||||||
|
text: %Schema{type: :string},
|
||||||
|
hint: %Schema{type: :string}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp rule do
|
||||||
|
%Schema{
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
id: %Schema{type: :string},
|
||||||
|
priority: %Schema{type: :integer},
|
||||||
|
text: %Schema{type: :string},
|
||||||
|
hint: %Schema{type: :string, nullable: true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -46,6 +46,17 @@ def peers_operation do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def rules_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["Instance misc"],
|
||||||
|
summary: "Retrieve list of instance rules",
|
||||||
|
operationId: "InstanceController.rules",
|
||||||
|
responses: %{
|
||||||
|
200 => Operation.response("Array of domains", "application/json", array_of_rules())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
defp instance do
|
defp instance do
|
||||||
%Schema{
|
%Schema{
|
||||||
type: :object,
|
type: :object,
|
||||||
|
@ -181,7 +192,8 @@ defp instance do
|
||||||
"urls" => %{
|
"urls" => %{
|
||||||
"streaming_api" => "wss://lain.com"
|
"streaming_api" => "wss://lain.com"
|
||||||
},
|
},
|
||||||
"version" => "2.7.2 (compatible; Pleroma 2.0.50-536-g25eec6d7-develop)"
|
"version" => "2.7.2 (compatible; Pleroma 2.0.50-536-g25eec6d7-develop)",
|
||||||
|
"rules" => array_of_rules()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -371,4 +383,18 @@ defp array_of_domains do
|
||||||
example: ["pleroma.site", "lain.com", "bikeshed.party"]
|
example: ["pleroma.site", "lain.com", "bikeshed.party"]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp array_of_rules do
|
||||||
|
%Schema{
|
||||||
|
type: :array,
|
||||||
|
items: %Schema{
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
id: %Schema{type: :string},
|
||||||
|
text: %Schema{type: :string},
|
||||||
|
hint: %Schema{type: :string}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -53,6 +53,12 @@ defp create_request do
|
||||||
default: false,
|
default: false,
|
||||||
description:
|
description:
|
||||||
"If the account is remote, should the report be forwarded to the remote admin?"
|
"If the account is remote, should the report be forwarded to the remote admin?"
|
||||||
|
},
|
||||||
|
rule_ids: %Schema{
|
||||||
|
type: :array,
|
||||||
|
nullable: true,
|
||||||
|
items: %Schema{type: :string},
|
||||||
|
description: "Array of rules"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
required: [:account_id],
|
required: [:account_id],
|
||||||
|
@ -60,7 +66,8 @@ defp create_request do
|
||||||
"account_id" => "123",
|
"account_id" => "123",
|
||||||
"status_ids" => ["1337"],
|
"status_ids" => ["1337"],
|
||||||
"comment" => "bad status!",
|
"comment" => "bad status!",
|
||||||
"forward" => "false"
|
"forward" => "false",
|
||||||
|
"rule_ids" => ["3"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
alias Pleroma.Formatter
|
alias Pleroma.Formatter
|
||||||
alias Pleroma.ModerationLog
|
alias Pleroma.ModerationLog
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Rule
|
||||||
alias Pleroma.ThreadMute
|
alias Pleroma.ThreadMute
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.UserRelationship
|
alias Pleroma.UserRelationship
|
||||||
|
@ -568,14 +569,16 @@ def thread_muted?(_, _), do: false
|
||||||
def report(user, data) do
|
def report(user, data) do
|
||||||
with {:ok, account} <- get_reported_account(data.account_id),
|
with {:ok, account} <- get_reported_account(data.account_id),
|
||||||
{:ok, {content_html, _, _}} <- make_report_content_html(data[:comment]),
|
{:ok, {content_html, _, _}} <- make_report_content_html(data[:comment]),
|
||||||
{:ok, statuses} <- get_report_statuses(account, data) do
|
{:ok, statuses} <- get_report_statuses(account, data),
|
||||||
|
rules <- get_report_rules(Map.get(data, :rule_ids, nil)) do
|
||||||
ActivityPub.flag(%{
|
ActivityPub.flag(%{
|
||||||
context: Utils.generate_context_id(),
|
context: Utils.generate_context_id(),
|
||||||
actor: user,
|
actor: user,
|
||||||
account: account,
|
account: account,
|
||||||
statuses: statuses,
|
statuses: statuses,
|
||||||
content: content_html,
|
content: content_html,
|
||||||
forward: Map.get(data, :forward, false)
|
forward: Map.get(data, :forward, false),
|
||||||
|
rules: rules
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -587,6 +590,15 @@ defp get_reported_account(account_id) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp get_report_rules(nil) do
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_report_rules(rule_ids) do
|
||||||
|
rule_ids
|
||||||
|
|> Enum.filter(&Rule.exists?/1)
|
||||||
|
end
|
||||||
|
|
||||||
def update_report_state(activity_ids, state) when is_list(activity_ids) do
|
def update_report_state(activity_ids, state) when is_list(activity_ids) do
|
||||||
case Utils.update_report_state(activity_ids, state) do
|
case Utils.update_report_state(activity_ids, state) do
|
||||||
:ok -> {:ok, activity_ids}
|
:ok -> {:ok, activity_ids}
|
||||||
|
|
|
@ -25,4 +25,9 @@ def show2(conn, _params) do
|
||||||
def peers(conn, _params) do
|
def peers(conn, _params) do
|
||||||
json(conn, Pleroma.Stats.get_peers())
|
json(conn, Pleroma.Stats.get_peers())
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc "GET /api/v1/instance/rules"
|
||||||
|
def rules(conn, _params) do
|
||||||
|
render(conn, "rules.json")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -76,12 +76,26 @@ def render("show2.json", _) do
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render("rules.json", _) do
|
||||||
|
Pleroma.Rule.query()
|
||||||
|
|> Pleroma.Repo.all()
|
||||||
|
|> render_many(__MODULE__, "rule.json", as: :rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
def render("rule.json", %{rule: rule}) do
|
||||||
|
%{
|
||||||
|
id: to_string(rule.id),
|
||||||
|
text: rule.text,
|
||||||
|
hint: rule.hint || ""
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
defp common_information(instance) do
|
defp common_information(instance) do
|
||||||
%{
|
%{
|
||||||
title: Keyword.get(instance, :name),
|
|
||||||
version: "#{@mastodon_api_level} (compatible; #{Pleroma.Application.named_version()})",
|
|
||||||
languages: Keyword.get(instance, :languages, ["en"]),
|
languages: Keyword.get(instance, :languages, ["en"]),
|
||||||
rules: []
|
rules: render(__MODULE__, "rules.json"),
|
||||||
|
title: Keyword.get(instance, :name),
|
||||||
|
version: "#{@mastodon_api_level} (compatible; #{Pleroma.Application.named_version()})"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -292,6 +292,11 @@ defmodule Pleroma.Web.Router do
|
||||||
post("/frontends/install", FrontendController, :install)
|
post("/frontends/install", FrontendController, :install)
|
||||||
|
|
||||||
post("/backups", AdminAPIController, :create_backup)
|
post("/backups", AdminAPIController, :create_backup)
|
||||||
|
|
||||||
|
get("/rules", RuleController, :index)
|
||||||
|
post("/rules", RuleController, :create)
|
||||||
|
patch("/rules/:id", RuleController, :update)
|
||||||
|
delete("/rules/:id", RuleController, :delete)
|
||||||
end
|
end
|
||||||
|
|
||||||
# AdminAPI: admins and mods (staff) can perform these actions (if privileged by role)
|
# AdminAPI: admins and mods (staff) can perform these actions (if privileged by role)
|
||||||
|
@ -764,6 +769,7 @@ defmodule Pleroma.Web.Router do
|
||||||
|
|
||||||
get("/instance", InstanceController, :show)
|
get("/instance", InstanceController, :show)
|
||||||
get("/instance/peers", InstanceController, :peers)
|
get("/instance/peers", InstanceController, :peers)
|
||||||
|
get("/instance/rules", InstanceController, :rules)
|
||||||
|
|
||||||
get("/statuses", StatusController, :index)
|
get("/statuses", StatusController, :index)
|
||||||
get("/statuses/:id", StatusController, :show)
|
get("/statuses/:id", StatusController, :show)
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.CreateRules do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
create_if_not_exists table(:rules) do
|
||||||
|
add(:priority, :integer, default: 0, null: false)
|
||||||
|
add(:text, :text, null: false)
|
||||||
|
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Repo.Migrations.AddHintToRules do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
alter table(:rules) do
|
||||||
|
add_if_not_exists(:hint, :text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,7 +6,6 @@ defmodule Pleroma.NotificationTest do
|
||||||
use Pleroma.DataCase, async: false
|
use Pleroma.DataCase, async: false
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
import Mock
|
|
||||||
|
|
||||||
alias Pleroma.FollowingRelationship
|
alias Pleroma.FollowingRelationship
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
|
@ -18,8 +17,6 @@ defmodule Pleroma.NotificationTest do
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.Web.MastodonAPI.NotificationView
|
alias Pleroma.Web.MastodonAPI.NotificationView
|
||||||
alias Pleroma.Web.Push
|
|
||||||
alias Pleroma.Web.Streamer
|
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
|
Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
|
||||||
|
@ -175,158 +172,7 @@ test "create_poll_notifications/1" do
|
||||||
assert [user2.id, user3.id, user1.id] == Enum.map(notifications, & &1.user_id)
|
assert [user2.id, user3.id, user1.id] == Enum.map(notifications, & &1.user_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "CommonApi.post/2 notification-related functionality" do
|
|
||||||
test_with_mock "creates but does NOT send notification to blocker user",
|
|
||||||
Push,
|
|
||||||
[:passthrough],
|
|
||||||
[] do
|
|
||||||
user = insert(:user)
|
|
||||||
blocker = insert(:user)
|
|
||||||
{:ok, _user_relationship} = User.block(blocker, user)
|
|
||||||
|
|
||||||
{:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{blocker.nickname}!"})
|
|
||||||
|
|
||||||
blocker_id = blocker.id
|
|
||||||
assert [%Notification{user_id: ^blocker_id}] = Repo.all(Notification)
|
|
||||||
refute called(Push.send(:_))
|
|
||||||
end
|
|
||||||
|
|
||||||
test_with_mock "creates but does NOT send notification to notification-muter user",
|
|
||||||
Push,
|
|
||||||
[:passthrough],
|
|
||||||
[] do
|
|
||||||
user = insert(:user)
|
|
||||||
muter = insert(:user)
|
|
||||||
{:ok, _user_relationships} = User.mute(muter, user)
|
|
||||||
|
|
||||||
{:ok, _activity} = CommonAPI.post(user, %{status: "hey @#{muter.nickname}!"})
|
|
||||||
|
|
||||||
muter_id = muter.id
|
|
||||||
assert [%Notification{user_id: ^muter_id}] = Repo.all(Notification)
|
|
||||||
refute called(Push.send(:_))
|
|
||||||
end
|
|
||||||
|
|
||||||
test_with_mock "creates but does NOT send notification to thread-muter user",
|
|
||||||
Push,
|
|
||||||
[:passthrough],
|
|
||||||
[] do
|
|
||||||
user = insert(:user)
|
|
||||||
thread_muter = insert(:user)
|
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{thread_muter.nickname}!"})
|
|
||||||
|
|
||||||
{:ok, _} = CommonAPI.add_mute(thread_muter, activity)
|
|
||||||
|
|
||||||
{:ok, _same_context_activity} =
|
|
||||||
CommonAPI.post(user, %{
|
|
||||||
status: "hey-hey-hey @#{thread_muter.nickname}!",
|
|
||||||
in_reply_to_status_id: activity.id
|
|
||||||
})
|
|
||||||
|
|
||||||
[pre_mute_notification, post_mute_notification] =
|
|
||||||
Repo.all(from(n in Notification, where: n.user_id == ^thread_muter.id, order_by: n.id))
|
|
||||||
|
|
||||||
pre_mute_notification_id = pre_mute_notification.id
|
|
||||||
post_mute_notification_id = post_mute_notification.id
|
|
||||||
|
|
||||||
assert called(
|
|
||||||
Push.send(
|
|
||||||
:meck.is(fn
|
|
||||||
%Notification{id: ^pre_mute_notification_id} -> true
|
|
||||||
_ -> false
|
|
||||||
end)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
refute called(
|
|
||||||
Push.send(
|
|
||||||
:meck.is(fn
|
|
||||||
%Notification{id: ^post_mute_notification_id} -> true
|
|
||||||
_ -> false
|
|
||||||
end)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "create_notification" do
|
describe "create_notification" do
|
||||||
@tag needs_streamer: true
|
|
||||||
test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
|
|
||||||
%{user: user, token: oauth_token} = oauth_access(["read"])
|
|
||||||
|
|
||||||
task =
|
|
||||||
Task.async(fn ->
|
|
||||||
{:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token)
|
|
||||||
assert_receive {:render_with_user, _, _, _, _}, 4_000
|
|
||||||
end)
|
|
||||||
|
|
||||||
task_user_notification =
|
|
||||||
Task.async(fn ->
|
|
||||||
{:ok, _topic} =
|
|
||||||
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
|
|
||||||
|
|
||||||
assert_receive {:render_with_user, _, _, _, _}, 4_000
|
|
||||||
end)
|
|
||||||
|
|
||||||
activity = insert(:note_activity)
|
|
||||||
|
|
||||||
notify = Notification.create_notification(activity, user)
|
|
||||||
assert notify.user_id == user.id
|
|
||||||
Task.await(task)
|
|
||||||
Task.await(task_user_notification)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it creates a notification for user if the user blocks the activity author" do
|
|
||||||
activity = insert(:note_activity)
|
|
||||||
author = User.get_cached_by_ap_id(activity.data["actor"])
|
|
||||||
user = insert(:user)
|
|
||||||
{:ok, _user_relationship} = User.block(user, author)
|
|
||||||
|
|
||||||
assert Notification.create_notification(activity, user)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it creates a notification for the user if the user mutes the activity author" do
|
|
||||||
muter = insert(:user)
|
|
||||||
muted = insert(:user)
|
|
||||||
{:ok, _} = User.mute(muter, muted)
|
|
||||||
muter = Repo.get(User, muter.id)
|
|
||||||
{:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
|
|
||||||
|
|
||||||
notification = Notification.create_notification(activity, muter)
|
|
||||||
|
|
||||||
assert notification.id
|
|
||||||
assert notification.seen
|
|
||||||
end
|
|
||||||
|
|
||||||
test "notification created if user is muted without notifications" do
|
|
||||||
muter = insert(:user)
|
|
||||||
muted = insert(:user)
|
|
||||||
|
|
||||||
{:ok, _user_relationships} = User.mute(muter, muted, %{notifications: false})
|
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
|
|
||||||
|
|
||||||
assert Notification.create_notification(activity, muter)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it creates a notification for an activity from a muted thread" do
|
|
||||||
muter = insert(:user)
|
|
||||||
other_user = insert(:user)
|
|
||||||
{:ok, activity} = CommonAPI.post(muter, %{status: "hey"})
|
|
||||||
CommonAPI.add_mute(muter, activity)
|
|
||||||
|
|
||||||
{:ok, activity} =
|
|
||||||
CommonAPI.post(other_user, %{
|
|
||||||
status: "Hi @#{muter.nickname}",
|
|
||||||
in_reply_to_status_id: activity.id
|
|
||||||
})
|
|
||||||
|
|
||||||
notification = Notification.create_notification(activity, muter)
|
|
||||||
|
|
||||||
assert notification.id
|
|
||||||
assert notification.seen
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it disables notifications from strangers" do
|
test "it disables notifications from strangers" do
|
||||||
follower = insert(:user)
|
follower = insert(:user)
|
||||||
|
|
||||||
|
@ -680,7 +526,7 @@ test "it sends notifications to addressed users in new messages" do
|
||||||
status: "hey @#{other_user.nickname}!"
|
status: "hey @#{other_user.nickname}!"
|
||||||
})
|
})
|
||||||
|
|
||||||
{enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
|
enabled_receivers = Notification.get_notified_from_activity(activity)
|
||||||
|
|
||||||
assert other_user in enabled_receivers
|
assert other_user in enabled_receivers
|
||||||
end
|
end
|
||||||
|
@ -712,7 +558,7 @@ test "it sends notifications to mentioned users in new messages" do
|
||||||
|
|
||||||
{:ok, activity} = Transmogrifier.handle_incoming(create_activity)
|
{:ok, activity} = Transmogrifier.handle_incoming(create_activity)
|
||||||
|
|
||||||
{enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
|
enabled_receivers = Notification.get_notified_from_activity(activity)
|
||||||
|
|
||||||
assert other_user in enabled_receivers
|
assert other_user in enabled_receivers
|
||||||
end
|
end
|
||||||
|
@ -739,7 +585,7 @@ test "it does not send notifications to users who are only cc in new messages" d
|
||||||
|
|
||||||
{:ok, activity} = Transmogrifier.handle_incoming(create_activity)
|
{:ok, activity} = Transmogrifier.handle_incoming(create_activity)
|
||||||
|
|
||||||
{enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(activity)
|
enabled_receivers = Notification.get_notified_from_activity(activity)
|
||||||
|
|
||||||
assert other_user not in enabled_receivers
|
assert other_user not in enabled_receivers
|
||||||
end
|
end
|
||||||
|
@ -756,8 +602,7 @@ test "it does not send notification to mentioned users in likes" do
|
||||||
|
|
||||||
{:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
|
{:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
|
||||||
|
|
||||||
{enabled_receivers, _disabled_receivers} =
|
enabled_receivers = Notification.get_notified_from_activity(activity_two)
|
||||||
Notification.get_notified_from_activity(activity_two)
|
|
||||||
|
|
||||||
assert other_user not in enabled_receivers
|
assert other_user not in enabled_receivers
|
||||||
end
|
end
|
||||||
|
@ -779,7 +624,7 @@ test "it only notifies the post's author in likes" do
|
||||||
|> Map.put("to", [other_user.ap_id | like_data["to"]])
|
|> Map.put("to", [other_user.ap_id | like_data["to"]])
|
||||||
|> ActivityPub.persist(local: true)
|
|> ActivityPub.persist(local: true)
|
||||||
|
|
||||||
{enabled_receivers, _disabled_receivers} = Notification.get_notified_from_activity(like)
|
enabled_receivers = Notification.get_notified_from_activity(like)
|
||||||
|
|
||||||
assert other_user not in enabled_receivers
|
assert other_user not in enabled_receivers
|
||||||
end
|
end
|
||||||
|
@ -796,39 +641,36 @@ test "it does not send notification to mentioned users in announces" do
|
||||||
|
|
||||||
{:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
|
{:ok, activity_two} = CommonAPI.repeat(activity_one.id, third_user)
|
||||||
|
|
||||||
{enabled_receivers, _disabled_receivers} =
|
enabled_receivers = Notification.get_notified_from_activity(activity_two)
|
||||||
Notification.get_notified_from_activity(activity_two)
|
|
||||||
|
|
||||||
assert other_user not in enabled_receivers
|
assert other_user not in enabled_receivers
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it returns blocking recipient in disabled recipients list" do
|
test "it does not return blocking recipient in recipients list" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
{:ok, _user_relationship} = User.block(other_user, user)
|
{:ok, _user_relationship} = User.block(other_user, user)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
|
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
|
||||||
|
|
||||||
{enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
|
enabled_receivers = Notification.get_notified_from_activity(activity)
|
||||||
|
|
||||||
assert [] == enabled_receivers
|
assert [] == enabled_receivers
|
||||||
assert [other_user] == disabled_receivers
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it returns notification-muting recipient in disabled recipients list" do
|
test "it does not return notification-muting recipient in recipients list" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
{:ok, _user_relationships} = User.mute(other_user, user)
|
{:ok, _user_relationships} = User.mute(other_user, user)
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
|
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
|
||||||
|
|
||||||
{enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
|
enabled_receivers = Notification.get_notified_from_activity(activity)
|
||||||
|
|
||||||
assert [] == enabled_receivers
|
assert [] == enabled_receivers
|
||||||
assert [other_user] == disabled_receivers
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it returns thread-muting recipient in disabled recipients list" do
|
test "it does not return thread-muting recipient in recipients list" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
@ -842,14 +684,12 @@ test "it returns thread-muting recipient in disabled recipients list" do
|
||||||
in_reply_to_status_id: activity.id
|
in_reply_to_status_id: activity.id
|
||||||
})
|
})
|
||||||
|
|
||||||
{enabled_receivers, disabled_receivers} =
|
enabled_receivers = Notification.get_notified_from_activity(same_context_activity)
|
||||||
Notification.get_notified_from_activity(same_context_activity)
|
|
||||||
|
|
||||||
assert [other_user] == disabled_receivers
|
|
||||||
refute other_user in enabled_receivers
|
refute other_user in enabled_receivers
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it returns non-following domain-blocking recipient in disabled recipients list" do
|
test "it does not return non-following domain-blocking recipient in recipients list" do
|
||||||
blocked_domain = "blocked.domain"
|
blocked_domain = "blocked.domain"
|
||||||
user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
|
user = insert(:user, %{ap_id: "https://#{blocked_domain}/@actor"})
|
||||||
other_user = insert(:user)
|
other_user = insert(:user)
|
||||||
|
@ -858,10 +698,9 @@ test "it returns non-following domain-blocking recipient in disabled recipients
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
|
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
|
||||||
|
|
||||||
{enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
|
enabled_receivers = Notification.get_notified_from_activity(activity)
|
||||||
|
|
||||||
assert [] == enabled_receivers
|
assert [] == enabled_receivers
|
||||||
assert [other_user] == disabled_receivers
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it returns following domain-blocking recipient in enabled recipients list" do
|
test "it returns following domain-blocking recipient in enabled recipients list" do
|
||||||
|
@ -874,10 +713,9 @@ test "it returns following domain-blocking recipient in enabled recipients list"
|
||||||
|
|
||||||
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
|
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
|
||||||
|
|
||||||
{enabled_receivers, disabled_receivers} = Notification.get_notified_from_activity(activity)
|
enabled_receivers = Notification.get_notified_from_activity(activity)
|
||||||
|
|
||||||
assert [other_user] == enabled_receivers
|
assert [other_user] == enabled_receivers
|
||||||
assert [] == disabled_receivers
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it sends edited notifications to those who repeated a status" do
|
test "it sends edited notifications to those who repeated a status" do
|
||||||
|
@ -897,11 +735,10 @@ test "it sends edited notifications to those who repeated a status" do
|
||||||
status: "hey @#{other_user.nickname}! mew mew"
|
status: "hey @#{other_user.nickname}! mew mew"
|
||||||
})
|
})
|
||||||
|
|
||||||
{enabled_receivers, _disabled_receivers} =
|
enabled_receivers = Notification.get_notified_from_activity(edit_activity)
|
||||||
Notification.get_notified_from_activity(edit_activity)
|
|
||||||
|
|
||||||
assert repeated_user in enabled_receivers
|
assert repeated_user in enabled_receivers
|
||||||
assert other_user not in enabled_receivers
|
refute other_user in enabled_receivers
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1189,13 +1026,13 @@ test "it doesn't return notifications for muted thread", %{user: user} do
|
||||||
assert Notification.for_user(user) == []
|
assert Notification.for_user(user) == []
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it returns notifications from a muted user when with_muted is set", %{user: user} do
|
test "it doesn't return notifications from a muted user when with_muted is set", %{user: user} do
|
||||||
muted = insert(:user)
|
muted = insert(:user)
|
||||||
{:ok, _user_relationships} = User.mute(user, muted)
|
{:ok, _user_relationships} = User.mute(user, muted)
|
||||||
|
|
||||||
{:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
|
{:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
|
||||||
|
|
||||||
assert length(Notification.for_user(user, %{with_muted: true})) == 1
|
assert Enum.empty?(Notification.for_user(user, %{with_muted: true}))
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it doesn't return notifications from a blocked user when with_muted is set", %{
|
test "it doesn't return notifications from a blocked user when with_muted is set", %{
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.RuleTest do
|
||||||
|
use Pleroma.DataCase, async: true
|
||||||
|
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.Rule
|
||||||
|
|
||||||
|
test "getting a list of rules sorted by priority" do
|
||||||
|
%{id: id1} = Rule.create(%{text: "Example rule"})
|
||||||
|
%{id: id2} = Rule.create(%{text: "Second rule", priority: 2})
|
||||||
|
%{id: id3} = Rule.create(%{text: "Third rule", priority: 1})
|
||||||
|
|
||||||
|
rules =
|
||||||
|
Rule.query()
|
||||||
|
|> Repo.all()
|
||||||
|
|
||||||
|
assert [%{id: ^id1}, %{id: ^id3}, %{id: ^id2}] = rules
|
||||||
|
end
|
||||||
|
|
||||||
|
test "creating rules" do
|
||||||
|
%{id: id} = Rule.create(%{text: "Example rule"})
|
||||||
|
|
||||||
|
assert %{text: "Example rule"} = Rule.get(id)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "editing rules" do
|
||||||
|
%{id: id} = Rule.create(%{text: "Example rule"})
|
||||||
|
|
||||||
|
Rule.update(%{text: "There are no rules", priority: 2}, id)
|
||||||
|
|
||||||
|
assert %{text: "There are no rules", priority: 2} = Rule.get(id)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "deleting rules" do
|
||||||
|
%{id: id} = Rule.create(%{text: "Example rule"})
|
||||||
|
|
||||||
|
Rule.delete(id)
|
||||||
|
|
||||||
|
assert [] =
|
||||||
|
Rule.query()
|
||||||
|
|> Pleroma.Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
|
test "getting rules by ids" do
|
||||||
|
%{id: id1} = Rule.create(%{text: "Example rule"})
|
||||||
|
%{id: id2} = Rule.create(%{text: "Second rule"})
|
||||||
|
%{id: _id3} = Rule.create(%{text: "Third rule"})
|
||||||
|
|
||||||
|
rules = Rule.get([id1, id2])
|
||||||
|
|
||||||
|
assert Enum.all?(rules, &(&1.id in [id1, id2]))
|
||||||
|
assert length(rules) == 2
|
||||||
|
end
|
||||||
|
end
|
|
@ -827,31 +827,6 @@ test "creates a notification", %{announce: announce, poster: poster} do
|
||||||
{:ok, announce, _} = SideEffects.handle(announce)
|
{:ok, announce, _} = SideEffects.handle(announce)
|
||||||
assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id)
|
assert Repo.get_by(Notification, user_id: poster.id, activity_id: announce.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it streams out the announce", %{announce: announce} do
|
|
||||||
with_mocks([
|
|
||||||
{
|
|
||||||
Pleroma.Web.Streamer,
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
stream: fn _, _ -> nil end
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Pleroma.Web.Push,
|
|
||||||
[],
|
|
||||||
[
|
|
||||||
send: fn _ -> nil end
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]) do
|
|
||||||
{:ok, announce, _} = SideEffects.handle(announce)
|
|
||||||
|
|
||||||
assert called(Pleroma.Web.Streamer.stream(["user", "list"], announce))
|
|
||||||
|
|
||||||
assert called(Pleroma.Web.Push.send(:_))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "removing a follower" do
|
describe "removing a follower" do
|
||||||
|
|
|
@ -11,6 +11,7 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
|
||||||
alias Pleroma.ModerationLog
|
alias Pleroma.ModerationLog
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.ReportNote
|
alias Pleroma.ReportNote
|
||||||
|
alias Pleroma.Rule
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
|
@ -436,6 +437,34 @@ test "returns 403 when requested by anonymous" do
|
||||||
"error" => "Invalid credentials."
|
"error" => "Invalid credentials."
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "returns reports with specified role_id", %{conn: conn} do
|
||||||
|
[reporter, target_user] = insert_pair(:user)
|
||||||
|
|
||||||
|
%{id: rule_id} = Rule.create(%{text: "Example rule"})
|
||||||
|
|
||||||
|
rule_id = to_string(rule_id)
|
||||||
|
|
||||||
|
{:ok, %{id: report_id}} =
|
||||||
|
CommonAPI.report(reporter, %{
|
||||||
|
account_id: target_user.id,
|
||||||
|
comment: "",
|
||||||
|
rule_ids: [rule_id]
|
||||||
|
})
|
||||||
|
|
||||||
|
{:ok, _report} =
|
||||||
|
CommonAPI.report(reporter, %{
|
||||||
|
account_id: target_user.id,
|
||||||
|
comment: ""
|
||||||
|
})
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> get("/api/pleroma/admin/reports?rule_id=#{rule_id}")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
assert %{"reports" => [%{"id" => ^report_id}]} = response
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "POST /api/pleroma/admin/reports/:id/notes" do
|
describe "POST /api/pleroma/admin/reports/:id/notes" do
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.AdminAPI.RuleControllerTest do
|
||||||
|
use Pleroma.Web.ConnCase, async: true
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
alias Pleroma.Rule
|
||||||
|
|
||||||
|
setup do
|
||||||
|
admin = insert(:user, is_admin: true)
|
||||||
|
token = insert(:oauth_admin_token, user: admin)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, admin)
|
||||||
|
|> assign(:token, token)
|
||||||
|
|
||||||
|
{:ok, %{admin: admin, token: token, conn: conn}}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "GET /api/pleroma/admin/rules" do
|
||||||
|
test "sorts rules by priority", %{conn: conn} do
|
||||||
|
%{id: id1} = Rule.create(%{text: "Example rule"})
|
||||||
|
%{id: id2} = Rule.create(%{text: "Second rule", priority: 2})
|
||||||
|
%{id: id3} = Rule.create(%{text: "Third rule", priority: 1})
|
||||||
|
|
||||||
|
id1 = to_string(id1)
|
||||||
|
id2 = to_string(id2)
|
||||||
|
id3 = to_string(id3)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> get("/api/pleroma/admin/rules")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
assert [%{"id" => ^id1}, %{"id" => ^id3}, %{"id" => ^id2}] = response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "POST /api/pleroma/admin/rules" do
|
||||||
|
test "creates a rule", %{conn: conn} do
|
||||||
|
%{"id" => id} =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> post("/api/pleroma/admin/rules", %{text: "Example rule"})
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
assert %{text: "Example rule"} = Rule.get(id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "PATCH /api/pleroma/admin/rules" do
|
||||||
|
test "edits a rule", %{conn: conn} do
|
||||||
|
%{id: id} = Rule.create(%{text: "Example rule"})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> patch("/api/pleroma/admin/rules/#{id}", %{text: "There are no rules", priority: 2})
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
assert %{text: "There are no rules", priority: 2} = Rule.get(id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "DELETE /api/pleroma/admin/rules" do
|
||||||
|
test "deletes a rule", %{conn: conn} do
|
||||||
|
%{id: id} = Rule.create(%{text: "Example rule"})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> delete("/api/pleroma/admin/rules/#{id}")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
assert [] =
|
||||||
|
Rule.query()
|
||||||
|
|> Pleroma.Repo.all()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
alias Pleroma.Rule
|
||||||
alias Pleroma.Web.AdminAPI
|
alias Pleroma.Web.AdminAPI
|
||||||
alias Pleroma.Web.AdminAPI.Report
|
alias Pleroma.Web.AdminAPI.Report
|
||||||
alias Pleroma.Web.AdminAPI.ReportView
|
alias Pleroma.Web.AdminAPI.ReportView
|
||||||
|
@ -38,7 +39,8 @@ test "renders a report" do
|
||||||
statuses: [],
|
statuses: [],
|
||||||
notes: [],
|
notes: [],
|
||||||
state: "open",
|
state: "open",
|
||||||
id: activity.id
|
id: activity.id,
|
||||||
|
rules: []
|
||||||
}
|
}
|
||||||
|
|
||||||
result =
|
result =
|
||||||
|
@ -76,7 +78,8 @@ test "includes reported statuses" do
|
||||||
statuses: [StatusView.render("show.json", %{activity: activity})],
|
statuses: [StatusView.render("show.json", %{activity: activity})],
|
||||||
state: "open",
|
state: "open",
|
||||||
notes: [],
|
notes: [],
|
||||||
id: report_activity.id
|
id: report_activity.id,
|
||||||
|
rules: []
|
||||||
}
|
}
|
||||||
|
|
||||||
result =
|
result =
|
||||||
|
@ -168,4 +171,22 @@ test "reports are ordered newest first" do
|
||||||
assert report2.id == rendered |> Enum.at(0) |> Map.get(:id)
|
assert report2.id == rendered |> Enum.at(0) |> Map.get(:id)
|
||||||
assert report1.id == rendered |> Enum.at(1) |> Map.get(:id)
|
assert report1.id == rendered |> Enum.at(1) |> Map.get(:id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "renders included rules" do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
%{id: rule_id, text: text} = Rule.create(%{text: "Example rule"})
|
||||||
|
|
||||||
|
rule_id = to_string(rule_id)
|
||||||
|
|
||||||
|
{:ok, activity} =
|
||||||
|
CommonAPI.report(user, %{
|
||||||
|
account_id: other_user.id,
|
||||||
|
rule_ids: [rule_id]
|
||||||
|
})
|
||||||
|
|
||||||
|
assert %{rules: [%{id: ^rule_id, text: ^text}]} =
|
||||||
|
ReportView.render("show.json", Report.extract_report_info(activity))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.Rule
|
||||||
alias Pleroma.UnstubbedConfigMock, as: ConfigMock
|
alias Pleroma.UnstubbedConfigMock, as: ConfigMock
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
@ -1363,6 +1364,33 @@ test "updates state of multiple reports" do
|
||||||
assert first_report.data["state"] == "resolved"
|
assert first_report.data["state"] == "resolved"
|
||||||
assert second_report.data["state"] == "resolved"
|
assert second_report.data["state"] == "resolved"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "creates a report with provided rules" do
|
||||||
|
reporter = insert(:user)
|
||||||
|
target_user = insert(:user)
|
||||||
|
|
||||||
|
%{id: rule_id} = Rule.create(%{text: "There are no rules"})
|
||||||
|
|
||||||
|
reporter_ap_id = reporter.ap_id
|
||||||
|
target_ap_id = target_user.ap_id
|
||||||
|
|
||||||
|
report_data = %{
|
||||||
|
account_id: target_user.id,
|
||||||
|
rule_ids: [rule_id]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {:ok, flag_activity} = CommonAPI.report(reporter, report_data)
|
||||||
|
|
||||||
|
assert %Activity{
|
||||||
|
actor: ^reporter_ap_id,
|
||||||
|
data: %{
|
||||||
|
"type" => "Flag",
|
||||||
|
"object" => [^target_ap_id],
|
||||||
|
"state" => "open",
|
||||||
|
"rules" => [^rule_id]
|
||||||
|
}
|
||||||
|
} = flag_activity
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "reblog muting" do
|
describe "reblog muting" do
|
||||||
|
|
|
@ -6,6 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
|
||||||
# TODO: Should not need Cachex
|
# TODO: Should not need Cachex
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
|
alias Pleroma.Rule
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
@ -40,7 +41,8 @@ test "get instance information", %{conn: conn} do
|
||||||
"banner_upload_limit" => _,
|
"banner_upload_limit" => _,
|
||||||
"background_image" => from_config_background,
|
"background_image" => from_config_background,
|
||||||
"shout_limit" => _,
|
"shout_limit" => _,
|
||||||
"description_limit" => _
|
"description_limit" => _,
|
||||||
|
"rules" => _
|
||||||
} = result
|
} = result
|
||||||
|
|
||||||
assert result["pleroma"]["metadata"]["account_activation_required"] != nil
|
assert result["pleroma"]["metadata"]["account_activation_required"] != nil
|
||||||
|
@ -125,4 +127,29 @@ test "get instance information v2", %{conn: conn} do
|
||||||
assert get(conn, "/api/v2/instance")
|
assert get(conn, "/api/v2/instance")
|
||||||
|> json_response_and_validate_schema(200)
|
|> json_response_and_validate_schema(200)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "get instance rules", %{conn: conn} do
|
||||||
|
Rule.create(%{text: "Example rule", hint: "Rule description", priority: 1})
|
||||||
|
Rule.create(%{text: "Third rule", priority: 2})
|
||||||
|
Rule.create(%{text: "Second rule", priority: 1})
|
||||||
|
|
||||||
|
conn = get(conn, "/api/v1/instance")
|
||||||
|
|
||||||
|
assert result = json_response_and_validate_schema(conn, 200)
|
||||||
|
|
||||||
|
assert [
|
||||||
|
%{
|
||||||
|
"text" => "Example rule",
|
||||||
|
"hint" => "Rule description"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"text" => "Second rule",
|
||||||
|
"hint" => ""
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"text" => "Third rule",
|
||||||
|
"hint" => ""
|
||||||
|
}
|
||||||
|
] = result["rules"]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.ReportControllerTest do
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.Rule
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
@ -81,6 +82,44 @@ test "submit a report with statuses and comment", %{
|
||||||
|> json_response_and_validate_schema(200)
|
|> json_response_and_validate_schema(200)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "submit a report with rule_ids", %{
|
||||||
|
conn: conn,
|
||||||
|
target_user: target_user
|
||||||
|
} do
|
||||||
|
%{id: rule_id} = Rule.create(%{text: "There are no rules"})
|
||||||
|
|
||||||
|
rule_id = to_string(rule_id)
|
||||||
|
|
||||||
|
assert %{"action_taken" => false, "id" => id} =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> post("/api/v1/reports", %{
|
||||||
|
"account_id" => target_user.id,
|
||||||
|
"forward" => "false",
|
||||||
|
"rule_ids" => [rule_id]
|
||||||
|
})
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert %Activity{data: %{"rules" => [^rule_id]}} = Activity.get_report(id)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "rules field is empty if provided wrong rule id", %{
|
||||||
|
conn: conn,
|
||||||
|
target_user: target_user
|
||||||
|
} do
|
||||||
|
assert %{"id" => id} =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> post("/api/v1/reports", %{
|
||||||
|
"account_id" => target_user.id,
|
||||||
|
"forward" => "false",
|
||||||
|
"rule_ids" => ["-1"]
|
||||||
|
})
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert %Activity{data: %{"rules" => []}} = Activity.get_report(id)
|
||||||
|
end
|
||||||
|
|
||||||
test "account_id is required", %{
|
test "account_id is required", %{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
activity: activity
|
activity: activity
|
||||||
|
|
Loading…
Reference in New Issue