Merge remote-tracking branch 'origin/develop' into shigusegubu
* origin/develop: (33 commits) maybe_notify_subscribers: Don't create notifications from ingested messages TwitterAPI: Make change_email require body params instead of query TwitterAPI: Make change_password require body params instead of query Make the OPT recomendation clearer ObjectAgePolicy: Fix pattern matching on published fix: stream out Create Activity Improve readability Quarantine placeholders improve changelog entry Make transparency_exclusions use tuples in admin-fe Add key- and valuePlaceholders for quarantined_instances and mrf_simple Add transparency_exclusions also to the breaking changes Change docs quarantine instances info Change what nodeinfo returns without breaking backwards compatibility Return maps in node_info Add database migrations Fixed deprecation warning checks config/description.exs: Update quarantine settings to tuples make linter happy ...
This commit is contained in:
commit
9916734b76
52 changed files with 1372 additions and 322 deletions
|
|
@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
### Added
|
||||
|
||||
### Fixed
|
||||
- Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies
|
||||
|
||||
### Removed
|
||||
|
||||
|
|
@ -19,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
### Changed
|
||||
|
||||
- **Breaking:** Configuration: `:chat, enabled` moved to `:shout, enabled` and `:instance, chat_limit` moved to `:shout, limit`
|
||||
- **Breaking** Entries for simple_policy, transparency_exclusions and quarantined_instances now list both the instance and a reason.
|
||||
- Support for Erlang/OTP 24
|
||||
- The `application` metadata returned with statuses is no longer hardcoded. Apps that want to display these details will now have valid data for new posts after this change.
|
||||
- HTTPSecurityPlug now sends a response header to opt out of Google's FLoC (Federated Learning of Cohorts) targeted advertising.
|
||||
|
|
@ -34,6 +36,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- AdminAPI: return `created_at` date with users.
|
||||
- `AnalyzeMetadata` upload filter for extracting image/video attachment dimensions and generating blurhashes for images. Blurhashes for videos are not generated at this time.
|
||||
- Attachment dimensions and blurhashes are federated when available.
|
||||
- Mastodon API: support `poll` notification.
|
||||
- Pinned posts federation
|
||||
|
||||
### Fixed
|
||||
|
|
|
|||
|
|
@ -574,6 +574,7 @@ config :pleroma, Oban,
|
|||
mailer: 10,
|
||||
transmogrifier: 20,
|
||||
scheduled_activities: 10,
|
||||
poll_notifications: 10,
|
||||
background: 5,
|
||||
remote_fetcher: 2,
|
||||
attachments_cleanup: 1,
|
||||
|
|
|
|||
|
|
@ -687,12 +687,14 @@ config :pleroma, :config_description, [
|
|||
},
|
||||
%{
|
||||
key: :quarantined_instances,
|
||||
type: {:list, :string},
|
||||
type: {:list, :tuple},
|
||||
key_placeholder: "instance",
|
||||
value_placeholder: "reason",
|
||||
description:
|
||||
"List of ActivityPub instances where private (DMs, followers-only) activities will not be sent",
|
||||
"List of ActivityPub instances where private (DMs, followers-only) activities will not be sent and the reason for doing so",
|
||||
suggestions: [
|
||||
"quarantined.com",
|
||||
"*.quarantined.com"
|
||||
{"quarantined.com", "Reason"},
|
||||
{"*.quarantined.com", "Reason"}
|
||||
]
|
||||
},
|
||||
%{
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ To add configuration to your config file, you can copy it from the base config.
|
|||
* `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.
|
||||
* `allow_relay`: Permits remote instances to subscribe to all public posts of your instance. This may increase the visibility of your instance.
|
||||
* `public`: Makes the client API in authenticated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. Note that there is a dependent setting restricting or allowing unauthenticated access to specific resources, see `restrict_unauthenticated` for more details.
|
||||
* `quarantined_instances`: List of ActivityPub instances where private (DMs, followers-only) activities will not be send.
|
||||
* `quarantined_instances`: ActivityPub instances where private (DMs, followers-only) activities will not be send.
|
||||
* `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML).
|
||||
* `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with
|
||||
older software for theses nicknames.
|
||||
|
|
@ -135,15 +135,16 @@ To add configuration to your config file, you can copy it from the base config.
|
|||
Configuring MRF policies is not enough for them to take effect. You have to enable them by specifying their module in `policies` under [:mrf](#mrf) section.
|
||||
|
||||
#### :mrf_simple
|
||||
* `media_removal`: List of instances to remove media from.
|
||||
* `media_nsfw`: List of instances to put media as NSFW(sensitive) from.
|
||||
* `federated_timeline_removal`: List of instances to remove from Federated (aka The Whole Known Network) Timeline.
|
||||
* `reject`: List of instances to reject any activities from.
|
||||
* `accept`: List of instances to accept any activities from.
|
||||
* `followers_only`: List of instances to decrease post visibility to only the followers, including for DM mentions.
|
||||
* `report_removal`: List of instances to reject reports from.
|
||||
* `avatar_removal`: List of instances to strip avatars from.
|
||||
* `banner_removal`: List of instances to strip banners from.
|
||||
* `media_removal`: List of instances to strip media attachments from and the reason for doing so.
|
||||
* `media_nsfw`: List of instances to tag all media as NSFW (sensitive) from and the reason for doing so.
|
||||
* `federated_timeline_removal`: List of instances to remove from the Federated Timeline (aka The Whole Known Network) and the reason for doing so.
|
||||
* `reject`: List of instances to reject activities (except deletes) from and the reason for doing so.
|
||||
* `accept`: List of instances to only accept activities (except deletes) from and the reason for doing so.
|
||||
* `followers_only`: Force posts from the given instances to be visible by followers only and the reason for doing so.
|
||||
* `report_removal`: List of instances to reject reports from and the reason for doing so.
|
||||
* `avatar_removal`: List of instances to strip avatars from and the reason for doing so.
|
||||
* `banner_removal`: List of instances to strip banners from and the reason for doing so.
|
||||
* `reject_deletes`: List of instances to reject deletions from and the reason for doing so.
|
||||
|
||||
#### :mrf_subchain
|
||||
This policy processes messages through an alternate pipeline when a given message matches certain criteria.
|
||||
|
|
|
|||
|
|
@ -55,18 +55,18 @@ Servers should be configured as lists.
|
|||
|
||||
### Example
|
||||
|
||||
This example will enable `SimplePolicy`, block media from `illegalporn.biz`, mark media as NSFW from `porn.biz` and `porn.business`, reject messages from `spam.com`, remove messages from `spam.university` from the federated timeline and block reports (flags) from `whiny.whiner`:
|
||||
This example will enable `SimplePolicy`, block media from `illegalporn.biz`, mark media as NSFW from `porn.biz` and `porn.business`, reject messages from `spam.com`, remove messages from `spam.university` from the federated timeline and block reports (flags) from `whiny.whiner`. We also give a reason why the moderation was done:
|
||||
|
||||
```elixir
|
||||
config :pleroma, :mrf,
|
||||
policies: [Pleroma.Web.ActivityPub.MRF.SimplePolicy]
|
||||
|
||||
config :pleroma, :mrf_simple,
|
||||
media_removal: ["illegalporn.biz"],
|
||||
media_nsfw: ["porn.biz", "porn.business"],
|
||||
reject: ["spam.com"],
|
||||
federated_timeline_removal: ["spam.university"],
|
||||
report_removal: ["whiny.whiner"]
|
||||
media_removal: [{"illegalporn.biz", "Media can contain illegal contant"}],
|
||||
media_nsfw: [{"porn.biz", "unmarked nsfw media"}, {"porn.business", "A lot of unmarked nsfw media"}],
|
||||
reject: [{"spam.com", "They keep spamming our users"}],
|
||||
federated_timeline_removal: [{"spam.university", "Annoying low-quality posts who otherwise fill up TWKN"}],
|
||||
report_removal: [{"whiny.whiner", "Keep spamming us with irrelevant reports"}]
|
||||
```
|
||||
|
||||
### Use with Care
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
# Installing on Alpine Linux
|
||||
|
||||
{! backend/installation/otp_vs_from_source_source.include !}
|
||||
|
||||
## Installation
|
||||
|
||||
This guide is a step-by-step installation guide for Alpine Linux. The instructions were verified against Alpine v3.10 standard image. You might miss additional dependencies if you use `netboot` instead.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
# Installing on Arch Linux
|
||||
|
||||
{! backend/installation/otp_vs_from_source_source.include !}
|
||||
|
||||
## Installation
|
||||
|
||||
This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.archlinux.org/index.php/Sudo). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
# Installing on Debian Based Distributions
|
||||
|
||||
{! backend/installation/otp_vs_from_source_source.include !}
|
||||
|
||||
## Installation
|
||||
|
||||
This guide will assume you are on Debian 11 (“bullseye”) or later. This guide should also work with Ubuntu 18.04 (“Bionic Beaver”) and later. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-add-delete-and-grant-sudo-privileges-to-users-on-a-debian-vps). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
# Installing on Gentoo GNU/Linux
|
||||
|
||||
{! backend/installation/otp_vs_from_source_source.include !}
|
||||
|
||||
## Installation
|
||||
|
||||
This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.gentoo.org/wiki/Sudo). Lines that begin with `#` indicate that they should be run as the superuser. Lines using `$` should be run as the indicated user, e.g. `pleroma$` should be run as the `pleroma` user.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
# Switching a from-source install to OTP releases
|
||||
|
||||
## What are OTP releases?
|
||||
OTP releases are as close as you can get to binary releases with Erlang/Elixir. The release is self-contained, and provides everything needed to boot it, it is easily administered via the provided shell script to open up a remote console, start/stop/restart the release, start in the background, send remote commands, and more.
|
||||
{! backend/installation/otp_vs_from_source.include !}
|
||||
|
||||
In this guide we cover how you can migrate from a from source installation to one using OTP releases.
|
||||
|
||||
## Pre-requisites
|
||||
You will be running commands as root. If you aren't root already, please elevate your priviledges by executing `sudo su`/`su`.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
# Installing on Linux using OTP releases
|
||||
|
||||
{! backend/installation/otp_vs_from_source.include !}
|
||||
|
||||
This guide covers a installation using an OTP release. To install Pleroma from source, please check out the corresponding guide for your distro.
|
||||
|
||||
## Pre-requisites
|
||||
* A machine running Linux with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPU, you have root access to. If you are not sure if it's compatible see [Detecting flavour section](#detecting-flavour) below
|
||||
* A (sub)domain pointed to the machine
|
||||
|
|
|
|||
3
docs/installation/otp_vs_from_source.include
Normal file
3
docs/installation/otp_vs_from_source.include
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
## OTP releases vs from-source installations
|
||||
|
||||
There are two ways to install Pleroma. You can use OTP releases or do a from-source installation. OTP releases are as close as you can get to binary releases with Erlang/Elixir. The release is self-contained, and provides everything needed to boot it, it is easily administered via the provided shell script to open up a remote console, start/stop/restart the release, start in the background, send remote commands, and more. With from source installations you install Pleroma from source, meaning you have to install certain dependencies like Erlang+Elixir and compile Pleroma yourself.
|
||||
3
docs/installation/otp_vs_from_source_source.include
Normal file
3
docs/installation/otp_vs_from_source_source.include
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{! backend/installation/otp_vs_from_source.include !}
|
||||
|
||||
This guide covers a from-source installation. To install using OTP releases, please check out [the OTP guide](./otp_en.md).
|
||||
|
|
@ -20,6 +20,140 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
|||
"\n* `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`"}
|
||||
]
|
||||
|
||||
def check_simple_policy_tuples do
|
||||
has_strings =
|
||||
Config.get([:mrf_simple])
|
||||
|> Enum.any?(fn {_, v} -> Enum.any?(v, &is_binary/1) end)
|
||||
|
||||
if has_strings do
|
||||
Logger.warn("""
|
||||
!!!DEPRECATION WARNING!!!
|
||||
Your config is using strings in the SimplePolicy configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||
|
||||
```
|
||||
config :pleroma, :mrf_simple,
|
||||
media_removal: ["instance.tld"],
|
||||
media_nsfw: ["instance.tld"],
|
||||
federated_timeline_removal: ["instance.tld"],
|
||||
report_removal: ["instance.tld"],
|
||||
reject: ["instance.tld"],
|
||||
followers_only: ["instance.tld"],
|
||||
accept: ["instance.tld"],
|
||||
avatar_removal: ["instance.tld"],
|
||||
banner_removal: ["instance.tld"],
|
||||
reject_deletes: ["instance.tld"]
|
||||
```
|
||||
|
||||
Is now
|
||||
|
||||
|
||||
```
|
||||
config :pleroma, :mrf_simple,
|
||||
media_removal: [{"instance.tld", "Reason for media removal"}],
|
||||
media_nsfw: [{"instance.tld", "Reason for media nsfw"}],
|
||||
federated_timeline_removal: [{"instance.tld", "Reason for federated timeline removal"}],
|
||||
report_removal: [{"instance.tld", "Reason for report removal"}],
|
||||
reject: [{"instance.tld", "Reason for reject"}],
|
||||
followers_only: [{"instance.tld", "Reason for followers only"}],
|
||||
accept: [{"instance.tld", "Reason for accept"}],
|
||||
avatar_removal: [{"instance.tld", "Reason for avatar removal"}],
|
||||
banner_removal: [{"instance.tld", "Reason for banner removal"}],
|
||||
reject_deletes: [{"instance.tld", "Reason for reject deletes"}]
|
||||
```
|
||||
""")
|
||||
|
||||
new_config =
|
||||
Config.get([:mrf_simple])
|
||||
|> Enum.map(fn {k, v} ->
|
||||
{k,
|
||||
Enum.map(v, fn
|
||||
{instance, reason} -> {instance, reason}
|
||||
instance -> {instance, ""}
|
||||
end)}
|
||||
end)
|
||||
|
||||
Config.put([:mrf_simple], new_config)
|
||||
|
||||
:error
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def check_quarantined_instances_tuples do
|
||||
has_strings = Config.get([:instance, :quarantined_instances]) |> Enum.any?(&is_binary/1)
|
||||
|
||||
if has_strings do
|
||||
Logger.warn("""
|
||||
!!!DEPRECATION WARNING!!!
|
||||
Your config is using strings in the quarantined_instances configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||
|
||||
```
|
||||
config :pleroma, :instance,
|
||||
quarantined_instances: ["instance.tld"]
|
||||
```
|
||||
|
||||
Is now
|
||||
|
||||
|
||||
```
|
||||
config :pleroma, :instance,
|
||||
quarantined_instances: [{"instance.tld", "Reason for quarantine"}]
|
||||
```
|
||||
""")
|
||||
|
||||
new_config =
|
||||
Config.get([:instance, :quarantined_instances])
|
||||
|> Enum.map(fn
|
||||
{instance, reason} -> {instance, reason}
|
||||
instance -> {instance, ""}
|
||||
end)
|
||||
|
||||
Config.put([:instance, :quarantined_instances], new_config)
|
||||
|
||||
:error
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def check_transparency_exclusions_tuples do
|
||||
has_strings = Config.get([:mrf, :transparency_exclusions]) |> Enum.any?(&is_binary/1)
|
||||
|
||||
if has_strings do
|
||||
Logger.warn("""
|
||||
!!!DEPRECATION WARNING!!!
|
||||
Your config is using strings in the transparency_exclusions configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||
|
||||
```
|
||||
config :pleroma, :mrf,
|
||||
transparency_exclusions: ["instance.tld"]
|
||||
```
|
||||
|
||||
Is now
|
||||
|
||||
|
||||
```
|
||||
config :pleroma, :mrf,
|
||||
transparency_exclusions: [{"instance.tld", "Reason to exlude transparency"}]
|
||||
```
|
||||
""")
|
||||
|
||||
new_config =
|
||||
Config.get([:mrf, :transparency_exclusions])
|
||||
|> Enum.map(fn
|
||||
{instance, reason} -> {instance, reason}
|
||||
instance -> {instance, ""}
|
||||
end)
|
||||
|
||||
Config.put([:mrf, :transparency_exclusions], new_config)
|
||||
|
||||
:error
|
||||
else
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
def check_hellthread_threshold do
|
||||
if Config.get([:mrf_hellthread, :threshold]) do
|
||||
Logger.warn("""
|
||||
|
|
@ -34,20 +168,24 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
|||
end
|
||||
|
||||
def warn do
|
||||
with :ok <- check_hellthread_threshold(),
|
||||
:ok <- check_old_mrf_config(),
|
||||
:ok <- check_media_proxy_whitelist_config(),
|
||||
:ok <- check_welcome_message_config(),
|
||||
:ok <- check_gun_pool_options(),
|
||||
:ok <- check_activity_expiration_config(),
|
||||
:ok <- check_remote_ip_plug_name(),
|
||||
:ok <- check_uploders_s3_public_endpoint(),
|
||||
:ok <- check_old_chat_shoutbox() do
|
||||
:ok
|
||||
else
|
||||
_ ->
|
||||
:error
|
||||
end
|
||||
[
|
||||
check_hellthread_threshold(),
|
||||
check_old_mrf_config(),
|
||||
check_media_proxy_whitelist_config(),
|
||||
check_welcome_message_config(),
|
||||
check_gun_pool_options(),
|
||||
check_activity_expiration_config(),
|
||||
check_remote_ip_plug_name(),
|
||||
check_uploders_s3_public_endpoint(),
|
||||
check_old_chat_shoutbox(),
|
||||
check_quarantined_instances_tuples(),
|
||||
check_transparency_exclusions_tuples(),
|
||||
check_simple_policy_tuples()
|
||||
]
|
||||
|> Enum.reduce(:ok, fn
|
||||
:ok, :ok -> :ok
|
||||
_, _ -> :error
|
||||
end)
|
||||
end
|
||||
|
||||
def check_welcome_message_config do
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ defmodule Pleroma.Notification do
|
|||
pleroma:emoji_reaction
|
||||
pleroma:report
|
||||
reblog
|
||||
poll
|
||||
}
|
||||
|
||||
def changeset(%Notification{} = notification, attrs) do
|
||||
|
|
@ -379,7 +380,7 @@ defmodule Pleroma.Notification do
|
|||
notifications =
|
||||
Enum.map(potential_receivers, fn user ->
|
||||
do_send = do_send && user in enabled_receivers
|
||||
create_notification(activity, user, do_send)
|
||||
create_notification(activity, user, do_send: do_send)
|
||||
end)
|
||||
|> Enum.reject(&is_nil/1)
|
||||
|
||||
|
|
@ -435,15 +436,18 @@ defmodule Pleroma.Notification do
|
|||
end
|
||||
|
||||
# TODO move to sql, too.
|
||||
def create_notification(%Activity{} = activity, %User{} = user, do_send \\ true) do
|
||||
unless skip?(activity, user) 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))
|
||||
|
||||
unless skip?(activity, user, opts) do
|
||||
{:ok, %{notification: notification}} =
|
||||
Multi.new()
|
||||
|> Multi.insert(:notification, %Notification{
|
||||
user_id: user.id,
|
||||
activity: activity,
|
||||
seen: mark_as_read?(activity, user),
|
||||
type: type_from_activity(activity)
|
||||
type: type
|
||||
})
|
||||
|> Marker.multi_set_last_read_id(user, "notifications")
|
||||
|> Repo.transaction()
|
||||
|
|
@ -457,6 +461,28 @@ defmodule Pleroma.Notification do
|
|||
end
|
||||
end
|
||||
|
||||
def create_poll_notifications(%Activity{} = activity) do
|
||||
with %Object{data: %{"type" => "Question", "actor" => actor} = data} <-
|
||||
Object.normalize(activity) do
|
||||
voters =
|
||||
case data do
|
||||
%{"voters" => voters} when is_list(voters) -> voters
|
||||
_ -> []
|
||||
end
|
||||
|
||||
notifications =
|
||||
Enum.reduce([actor | voters], [], fn ap_id, acc ->
|
||||
with %User{local: true} = user <- User.get_by_ap_id(ap_id) do
|
||||
[create_notification(activity, user, type: "poll") | acc]
|
||||
else
|
||||
_ -> acc
|
||||
end
|
||||
end)
|
||||
|
||||
{:ok, notifications}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns a tuple with 2 elements:
|
||||
{notification-enabled receivers, currently disabled receivers (blocking / [thread] muting)}
|
||||
|
|
@ -572,8 +598,10 @@ defmodule Pleroma.Notification do
|
|||
Enum.uniq(ap_ids) -- thread_muter_ap_ids
|
||||
end
|
||||
|
||||
@spec skip?(Activity.t(), User.t()) :: boolean()
|
||||
def skip?(%Activity{} = activity, %User{} = user) do
|
||||
def skip?(activity, user, opts \\ [])
|
||||
|
||||
@spec skip?(Activity.t(), User.t(), Keyword.t()) :: boolean()
|
||||
def skip?(%Activity{} = activity, %User{} = user, opts) do
|
||||
[
|
||||
:self,
|
||||
:invisible,
|
||||
|
|
@ -581,17 +609,21 @@ defmodule Pleroma.Notification do
|
|||
:recently_followed,
|
||||
:filtered
|
||||
]
|
||||
|> Enum.find(&skip?(&1, activity, user))
|
||||
|> Enum.find(&skip?(&1, activity, user, opts))
|
||||
end
|
||||
|
||||
def skip?(_, _), do: false
|
||||
def skip?(_activity, _user, _opts), do: false
|
||||
|
||||
@spec skip?(atom(), Activity.t(), User.t()) :: boolean()
|
||||
def skip?(:self, %Activity{} = activity, %User{} = user) do
|
||||
activity.data["actor"] == user.ap_id
|
||||
@spec skip?(atom(), Activity.t(), User.t(), Keyword.t()) :: boolean()
|
||||
def skip?(:self, %Activity{} = activity, %User{} = user, opts) do
|
||||
cond do
|
||||
opts[:type] == "poll" -> false
|
||||
activity.data["actor"] == user.ap_id -> true
|
||||
true -> false
|
||||
end
|
||||
end
|
||||
|
||||
def skip?(:invisible, %Activity{} = activity, _) do
|
||||
def skip?(:invisible, %Activity{} = activity, _user, _opts) do
|
||||
actor = activity.data["actor"]
|
||||
user = User.get_cached_by_ap_id(actor)
|
||||
User.invisible?(user)
|
||||
|
|
@ -600,15 +632,27 @@ defmodule Pleroma.Notification do
|
|||
def skip?(
|
||||
:block_from_strangers,
|
||||
%Activity{} = activity,
|
||||
%User{notification_settings: %{block_from_strangers: true}} = user
|
||||
%User{notification_settings: %{block_from_strangers: true}} = user,
|
||||
opts
|
||||
) do
|
||||
actor = activity.data["actor"]
|
||||
follower = User.get_cached_by_ap_id(actor)
|
||||
!User.following?(follower, user)
|
||||
|
||||
cond do
|
||||
opts[:type] == "poll" -> false
|
||||
user.ap_id == actor -> false
|
||||
!User.following?(follower, user) -> true
|
||||
true -> false
|
||||
end
|
||||
end
|
||||
|
||||
# To do: consider defining recency in hours and checking FollowingRelationship with a single SQL
|
||||
def skip?(:recently_followed, %Activity{data: %{"type" => "Follow"}} = activity, %User{} = user) do
|
||||
def skip?(
|
||||
:recently_followed,
|
||||
%Activity{data: %{"type" => "Follow"}} = activity,
|
||||
%User{} = user,
|
||||
_opts
|
||||
) do
|
||||
actor = activity.data["actor"]
|
||||
|
||||
Notification.for_user(user)
|
||||
|
|
@ -618,9 +662,10 @@ defmodule Pleroma.Notification do
|
|||
end)
|
||||
end
|
||||
|
||||
def skip?(:filtered, %{data: %{"type" => type}}, _) when type in ["Follow", "Move"], do: false
|
||||
def skip?(:filtered, %{data: %{"type" => type}}, _user, _opts) when type in ["Follow", "Move"],
|
||||
do: false
|
||||
|
||||
def skip?(:filtered, activity, user) do
|
||||
def skip?(:filtered, activity, user, _opts) do
|
||||
object = Object.normalize(activity, fetch: false)
|
||||
|
||||
cond do
|
||||
|
|
@ -638,7 +683,7 @@ defmodule Pleroma.Notification do
|
|||
end
|
||||
end
|
||||
|
||||
def skip?(_, _, _), do: false
|
||||
def skip?(_type, _activity, _user, _opts), do: false
|
||||
|
||||
def mark_as_read?(activity, target_user) do
|
||||
user = Activity.user_actor(activity)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
alias Pleroma.Web.Streamer
|
||||
alias Pleroma.Web.WebFinger
|
||||
alias Pleroma.Workers.BackgroundWorker
|
||||
alias Pleroma.Workers.PollWorker
|
||||
|
||||
import Ecto.Query
|
||||
import Pleroma.Web.ActivityPub.Utils
|
||||
|
|
@ -288,6 +289,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
{:quick_insert, false, activity} <- {:quick_insert, quick_insert?, activity},
|
||||
{:ok, _actor} <- increase_note_count_if_public(actor, activity),
|
||||
_ <- notify_and_stream(activity),
|
||||
:ok <- maybe_schedule_poll_notifications(activity),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
|
|
@ -302,6 +304,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
end
|
||||
|
||||
defp maybe_schedule_poll_notifications(activity) do
|
||||
PollWorker.schedule_poll_end(activity)
|
||||
:ok
|
||||
end
|
||||
|
||||
@spec listen(map()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def listen(%{to: to, actor: actor, context: context, object: object} = params) do
|
||||
additional = params[:additional] || %{}
|
||||
|
|
|
|||
|
|
@ -33,9 +33,11 @@ defmodule Pleroma.Web.ActivityPub.MRF do
|
|||
%{
|
||||
key: :transparency_exclusions,
|
||||
label: "MRF transparency exclusions",
|
||||
type: {:list, :string},
|
||||
type: {:list, :tuple},
|
||||
key_placeholder: "instance",
|
||||
value_placeholder: "reason",
|
||||
description:
|
||||
"Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value.",
|
||||
"Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. You can also provide a reason for excluding these instance names. The instances and reasons won't be publicly disclosed.",
|
||||
suggestions: [
|
||||
"exclusion.com"
|
||||
]
|
||||
|
|
@ -100,6 +102,11 @@ defmodule Pleroma.Web.ActivityPub.MRF do
|
|||
Enum.any?(domains, fn domain -> Regex.match?(domain, host) end)
|
||||
end
|
||||
|
||||
@spec instance_list_from_tuples([{String.t(), String.t()}]) :: [String.t()]
|
||||
def instance_list_from_tuples(list) do
|
||||
Enum.map(list, fn {instance, _} -> instance end)
|
||||
end
|
||||
|
||||
def describe(policies) do
|
||||
{:ok, policy_configs} =
|
||||
policies
|
||||
|
|
|
|||
|
|
@ -159,6 +159,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
|
|||
%{
|
||||
key: :replace,
|
||||
type: {:list, :tuple},
|
||||
key_placeholder: "instance",
|
||||
value_placeholder: "reason",
|
||||
description: """
|
||||
**Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
|
|||
message
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|> Kernel.put_in(["object", "to"], to)
|
||||
|> Kernel.put_in(["object", "cc"], cc)
|
||||
|
||||
{:ok, message}
|
||||
else
|
||||
|
|
@ -70,6 +72,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
|
|||
message
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|> Kernel.put_in(["object", "to"], to)
|
||||
|> Kernel.put_in(["object", "cc"], cc)
|
||||
|
||||
{:ok, message}
|
||||
else
|
||||
|
|
@ -82,7 +86,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
|
|||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Create", "published" => _} = message) do
|
||||
def filter(%{"type" => "Create", "object" => %{"published" => _}} = message) do
|
||||
with actions <- Config.get([:mrf_object_age, :actions]),
|
||||
{:reject, _} <- check_date(message),
|
||||
{:ok, message} <- check_reject(message, actions),
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
|
|||
|
||||
@impl true
|
||||
def describe,
|
||||
do: {:ok, %{mrf_rejectnonpublic: Config.get(:mrf_rejectnonpublic) |> Enum.into(%{})}}
|
||||
do: {:ok, %{mrf_rejectnonpublic: Config.get(:mrf_rejectnonpublic) |> Map.new()}}
|
||||
|
||||
@impl true
|
||||
def config_description do
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|
||||
defp check_accept(%{host: actor_host} = _actor_info, object) do
|
||||
accepts =
|
||||
Config.get([:mrf_simple, :accept])
|
||||
instance_list(:accept)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
cond do
|
||||
|
|
@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|
||||
defp check_reject(%{host: actor_host} = _actor_info, object) do
|
||||
rejects =
|
||||
Config.get([:mrf_simple, :reject])
|
||||
instance_list(:reject)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
if MRF.subdomain_match?(rejects, actor_host) do
|
||||
|
|
@ -44,7 +44,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
)
|
||||
when length(child_attachment) > 0 do
|
||||
media_removal =
|
||||
Config.get([:mrf_simple, :media_removal])
|
||||
instance_list(:media_removal)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
object =
|
||||
|
|
@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
} = object
|
||||
) do
|
||||
media_nsfw =
|
||||
Config.get([:mrf_simple, :media_nsfw])
|
||||
instance_list(:media_nsfw)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
object =
|
||||
|
|
@ -85,7 +85,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|
||||
defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do
|
||||
timeline_removal =
|
||||
Config.get([:mrf_simple, :federated_timeline_removal])
|
||||
instance_list(:federated_timeline_removal)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
object =
|
||||
|
|
@ -112,7 +112,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|
||||
defp check_followers_only(%{host: actor_host} = _actor_info, object) do
|
||||
followers_only =
|
||||
Config.get([:mrf_simple, :followers_only])
|
||||
instance_list(:followers_only)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
object =
|
||||
|
|
@ -137,7 +137,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|
||||
defp check_report_removal(%{host: actor_host} = _actor_info, %{"type" => "Flag"} = object) do
|
||||
report_removal =
|
||||
Config.get([:mrf_simple, :report_removal])
|
||||
instance_list(:report_removal)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
if MRF.subdomain_match?(report_removal, actor_host) do
|
||||
|
|
@ -151,7 +151,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|
||||
defp check_avatar_removal(%{host: actor_host} = _actor_info, %{"icon" => _icon} = object) do
|
||||
avatar_removal =
|
||||
Config.get([:mrf_simple, :avatar_removal])
|
||||
instance_list(:avatar_removal)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
if MRF.subdomain_match?(avatar_removal, actor_host) do
|
||||
|
|
@ -165,7 +165,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|
||||
defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image} = object) do
|
||||
banner_removal =
|
||||
Config.get([:mrf_simple, :banner_removal])
|
||||
instance_list(:banner_removal)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
if MRF.subdomain_match?(banner_removal, actor_host) do
|
||||
|
|
@ -185,12 +185,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|
||||
defp check_object(object), do: {:ok, object}
|
||||
|
||||
defp instance_list(config_key) do
|
||||
Config.get([:mrf_simple, config_key])
|
||||
|> MRF.instance_list_from_tuples()
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Delete", "actor" => actor} = object) do
|
||||
%{host: actor_host} = URI.parse(actor)
|
||||
|
||||
reject_deletes =
|
||||
Config.get([:mrf_simple, :reject_deletes])
|
||||
instance_list(:reject_deletes)
|
||||
|> MRF.subdomains_regex()
|
||||
|
||||
if MRF.subdomain_match?(reject_deletes, actor_host) do
|
||||
|
|
@ -253,14 +258,42 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|
||||
@impl true
|
||||
def describe do
|
||||
exclusions = Config.get([:mrf, :transparency_exclusions])
|
||||
exclusions = Config.get([:mrf, :transparency_exclusions]) |> MRF.instance_list_from_tuples()
|
||||
|
||||
mrf_simple_excluded =
|
||||
Config.get(:mrf_simple)
|
||||
|> Enum.map(fn {rule, instances} ->
|
||||
{rule, Enum.reject(instances, fn {host, _} -> host in exclusions end)}
|
||||
end)
|
||||
|
||||
mrf_simple =
|
||||
Config.get(:mrf_simple)
|
||||
|> Enum.map(fn {k, v} -> {k, Enum.reject(v, fn v -> v in exclusions end)} end)
|
||||
|> Enum.into(%{})
|
||||
mrf_simple_excluded
|
||||
|> Enum.map(fn {rule, instances} ->
|
||||
{rule, Enum.map(instances, fn {host, _} -> host end)}
|
||||
end)
|
||||
|> Map.new()
|
||||
|
||||
{:ok, %{mrf_simple: mrf_simple}}
|
||||
# This is for backwards compatibility. We originally didn't sent
|
||||
# extra info like a reason why an instance was rejected/quarantined/etc.
|
||||
# Because we didn't want to break backwards compatibility it was decided
|
||||
# to add an extra "info" key.
|
||||
mrf_simple_info =
|
||||
mrf_simple_excluded
|
||||
|> Enum.map(fn {rule, instances} ->
|
||||
{rule, Enum.reject(instances, fn {_, reason} -> reason == "" end)}
|
||||
end)
|
||||
|> Enum.reject(fn {_, instances} -> instances == [] end)
|
||||
|> Enum.map(fn {rule, instances} ->
|
||||
instances =
|
||||
instances
|
||||
|> Enum.map(fn {host, reason} -> {host, %{"reason" => reason}} end)
|
||||
|> Map.new()
|
||||
|
||||
{rule, instances}
|
||||
end)
|
||||
|> Map.new()
|
||||
|
||||
{:ok, %{mrf_simple: mrf_simple, mrf_simple_info: mrf_simple_info}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
|
@ -270,70 +303,67 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
related_policy: "Pleroma.Web.ActivityPub.MRF.SimplePolicy",
|
||||
label: "MRF Simple",
|
||||
description: "Simple ingress policies",
|
||||
children: [
|
||||
%{
|
||||
key: :media_removal,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to strip media attachments from",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
},
|
||||
%{
|
||||
key: :media_nsfw,
|
||||
label: "Media NSFW",
|
||||
type: {:list, :string},
|
||||
description: "List of instances to tag all media as NSFW (sensitive) from",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
},
|
||||
%{
|
||||
key: :federated_timeline_removal,
|
||||
type: {:list, :string},
|
||||
description:
|
||||
"List of instances to remove from the Federated (aka The Whole Known Network) Timeline",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
},
|
||||
%{
|
||||
key: :reject,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to reject activities from (except deletes)",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
},
|
||||
%{
|
||||
key: :accept,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to only accept activities from (except deletes)",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
},
|
||||
%{
|
||||
key: :followers_only,
|
||||
type: {:list, :string},
|
||||
description: "Force posts from the given instances to be visible by followers only",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
},
|
||||
%{
|
||||
key: :report_removal,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to reject reports from",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
},
|
||||
%{
|
||||
key: :avatar_removal,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to strip avatars from",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
},
|
||||
%{
|
||||
key: :banner_removal,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to strip banners from",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
},
|
||||
%{
|
||||
key: :reject_deletes,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to reject deletions from",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
}
|
||||
]
|
||||
children:
|
||||
[
|
||||
%{
|
||||
key: :media_removal,
|
||||
description:
|
||||
"List of instances to strip media attachments from and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :media_nsfw,
|
||||
label: "Media NSFW",
|
||||
description:
|
||||
"List of instances to tag all media as NSFW (sensitive) from and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :federated_timeline_removal,
|
||||
description:
|
||||
"List of instances to remove from the Federated (aka The Whole Known Network) Timeline and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :reject,
|
||||
description:
|
||||
"List of instances to reject activities from (except deletes) and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :accept,
|
||||
description:
|
||||
"List of instances to only accept activities from (except deletes) and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :followers_only,
|
||||
description:
|
||||
"Force posts from the given instances to be visible by followers only and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :report_removal,
|
||||
description: "List of instances to reject reports from and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :avatar_removal,
|
||||
description: "List of instances to strip avatars from and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :banner_removal,
|
||||
description: "List of instances to strip banners from and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :reject_deletes,
|
||||
description: "List of instances to reject deletions from and the reason for doing so"
|
||||
}
|
||||
]
|
||||
|> Enum.map(fn setting ->
|
||||
Map.merge(
|
||||
setting,
|
||||
%{
|
||||
type: {:list, :tuple},
|
||||
key_placeholder: "instance",
|
||||
value_placeholder: "reason",
|
||||
suggestions: [{"example.com", "Some reason"}, {"*.example.com", "Another reason"}]
|
||||
}
|
||||
)
|
||||
end)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do
|
|||
def describe do
|
||||
mrf_user_allowlist =
|
||||
Config.get([:mrf_user_allowlist], [])
|
||||
|> Enum.into(%{}, fn {k, v} -> {k, length(v)} end)
|
||||
|> Map.new(fn {k, v} -> {k, length(v)} end)
|
||||
|
||||
{:ok, %{mrf_user_allowlist: mrf_user_allowlist}}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
|
|||
|
||||
@impl true
|
||||
def describe,
|
||||
do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary) |> Enum.into(%{})}}
|
||||
do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary) |> Map.new()}}
|
||||
|
||||
@impl true
|
||||
def config_description do
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
|
||||
quarantined_instances =
|
||||
Config.get([:instance, :quarantined_instances], [])
|
||||
|> Pleroma.Web.ActivityPub.MRF.instance_list_from_tuples()
|
||||
|> Pleroma.Web.ActivityPub.MRF.subdomains_regex()
|
||||
|
||||
!Pleroma.Web.ActivityPub.MRF.subdomain_match?(quarantined_instances, host)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
collection, and so on.
|
||||
"""
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Activity.Ir.Topics
|
||||
alias Pleroma.Chat
|
||||
alias Pleroma.Chat.MessageReference
|
||||
alias Pleroma.FollowingRelationship
|
||||
|
|
@ -24,6 +23,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.Push
|
||||
alias Pleroma.Web.Streamer
|
||||
alias Pleroma.Workers.PollWorker
|
||||
|
||||
require Logger
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
# - Set up notifications
|
||||
@impl true
|
||||
def handle(%{data: %{"type" => "Create"}} = activity, meta) do
|
||||
with {:ok, object, meta} <- handle_object_creation(meta[:object_data], 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
|
||||
{:ok, notifications} = Notification.create_notifications(activity, do_send: false)
|
||||
{:ok, _user} = ActivityPub.increase_note_count_if_public(user, object)
|
||||
|
|
@ -225,6 +225,8 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
meta
|
||||
|> add_notifications(notifications)
|
||||
|
||||
ap_streamer().stream_out(activity)
|
||||
|
||||
{:ok, activity, meta}
|
||||
else
|
||||
e -> Repo.rollback(e)
|
||||
|
|
@ -245,9 +247,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
if !User.is_internal_user?(user) do
|
||||
Notification.create_notifications(object)
|
||||
|
||||
object
|
||||
|> Topics.get_activity_topics()
|
||||
|> Streamer.stream(object)
|
||||
ap_streamer().stream_out(object)
|
||||
end
|
||||
|
||||
{:ok, object, meta}
|
||||
|
|
@ -389,7 +389,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
{:ok, object, meta}
|
||||
end
|
||||
|
||||
def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do
|
||||
def handle_object_creation(%{"type" => "ChatMessage"} = object, _activity, meta) do
|
||||
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
||||
actor = User.get_cached_by_ap_id(object.data["actor"])
|
||||
recipient = User.get_cached_by_ap_id(hd(object.data["to"]))
|
||||
|
|
@ -424,7 +424,14 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
end
|
||||
end
|
||||
|
||||
def handle_object_creation(%{"type" => "Answer"} = object_map, meta) do
|
||||
def handle_object_creation(%{"type" => "Question"} = object, activity, meta) do
|
||||
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
||||
PollWorker.schedule_poll_end(activity)
|
||||
{:ok, object, meta}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_object_creation(%{"type" => "Answer"} = object_map, _activity, meta) do
|
||||
with {:ok, object, meta} <- Pipeline.common_pipeline(object_map, meta) do
|
||||
Object.increase_vote_count(
|
||||
object.data["inReplyTo"],
|
||||
|
|
@ -436,15 +443,15 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
|||
end
|
||||
end
|
||||
|
||||
def handle_object_creation(%{"type" => objtype} = object, meta)
|
||||
when objtype in ~w[Audio Video Question Event Article Note Page] do
|
||||
def handle_object_creation(%{"type" => objtype} = object, _activity, meta)
|
||||
when objtype in ~w[Audio Video Event Article Note Page] do
|
||||
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
||||
{:ok, object, meta}
|
||||
end
|
||||
end
|
||||
|
||||
# Nothing to do
|
||||
def handle_object_creation(object, meta) do
|
||||
def handle_object_creation(object, _activity, meta) do
|
||||
{:ok, object, meta}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -195,7 +195,8 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
|
|||
"pleroma:chat_mention",
|
||||
"pleroma:report",
|
||||
"move",
|
||||
"follow_request"
|
||||
"follow_request",
|
||||
"poll"
|
||||
],
|
||||
description: """
|
||||
The type of event that resulted in the notification.
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
|
|||
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
||||
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
|
||||
|
||||
import Pleroma.Web.ApiSpec.Helpers
|
||||
|
||||
def open_api_operation(action) do
|
||||
operation = String.to_existing_atom("#{action}_operation")
|
||||
apply(__MODULE__, operation, [])
|
||||
|
|
@ -63,17 +65,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
|
|||
summary: "Change account password",
|
||||
security: [%{"oAuth" => ["write:accounts"]}],
|
||||
operationId: "UtilController.change_password",
|
||||
parameters: [
|
||||
Operation.parameter(:password, :query, :string, "Current password", required: true),
|
||||
Operation.parameter(:new_password, :query, :string, "New password", required: true),
|
||||
Operation.parameter(
|
||||
:new_password_confirmation,
|
||||
:query,
|
||||
:string,
|
||||
"New password, confirmation",
|
||||
required: true
|
||||
)
|
||||
],
|
||||
requestBody: request_body("Parameters", change_password_request(), required: true),
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response("Success", "application/json", %Schema{
|
||||
|
|
@ -86,17 +78,30 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
|
|||
}
|
||||
end
|
||||
|
||||
defp change_password_request do
|
||||
%Schema{
|
||||
title: "ChangePasswordRequest",
|
||||
description: "POST body for changing the account's passowrd",
|
||||
type: :object,
|
||||
required: [:password, :new_password, :new_password_confirmation],
|
||||
properties: %{
|
||||
password: %Schema{type: :string, description: "Current password"},
|
||||
new_password: %Schema{type: :string, description: "New password"},
|
||||
new_password_confirmation: %Schema{
|
||||
type: :string,
|
||||
description: "New password, confirmation"
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def change_email_operation do
|
||||
%Operation{
|
||||
tags: ["Account credentials"],
|
||||
summary: "Change account email",
|
||||
security: [%{"oAuth" => ["write:accounts"]}],
|
||||
operationId: "UtilController.change_email",
|
||||
parameters: [
|
||||
Operation.parameter(:password, :query, :string, "Current password", required: true),
|
||||
Operation.parameter(:email, :query, :string, "New email", required: true)
|
||||
],
|
||||
requestBody: nil,
|
||||
requestBody: request_body("Parameters", change_email_request(), required: true),
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response("Success", "application/json", %Schema{
|
||||
|
|
@ -109,6 +114,19 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
|
|||
}
|
||||
end
|
||||
|
||||
defp change_email_request do
|
||||
%Schema{
|
||||
title: "ChangeEmailRequest",
|
||||
description: "POST body for changing the account's email",
|
||||
type: :object,
|
||||
required: [:email, :password],
|
||||
properties: %{
|
||||
email: %Schema{type: :string, description: "New email"},
|
||||
password: %Schema{type: :string, description: "Current password"}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def update_notificaton_settings_operation do
|
||||
%Operation{
|
||||
tags: ["Accounts"],
|
||||
|
|
|
|||
|
|
@ -412,19 +412,14 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
|
||||
def maybe_notify_mentioned_recipients(recipients, _), do: recipients
|
||||
|
||||
# Do not notify subscribers if author is making a reply
|
||||
def maybe_notify_subscribers(recipients, %Activity{
|
||||
object: %Object{data: %{"inReplyTo" => _ap_id}}
|
||||
}) do
|
||||
recipients
|
||||
end
|
||||
|
||||
def maybe_notify_subscribers(
|
||||
recipients,
|
||||
%Activity{data: %{"actor" => actor, "type" => type}} = activity
|
||||
)
|
||||
when type == "Create" do
|
||||
with %User{} = user <- User.get_cached_by_ap_id(actor) do
|
||||
%Activity{data: %{"actor" => actor, "type" => "Create"}} = activity
|
||||
) do
|
||||
# Do not notify subscribers if author is making a reply
|
||||
with %Object{data: object} <- Object.normalize(activity, fetch: false),
|
||||
nil <- object["inReplyTo"],
|
||||
%User{} = user <- User.get_cached_by_ap_id(actor) do
|
||||
subscriber_ids =
|
||||
user
|
||||
|> User.subscriber_users()
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
|
|||
favourite
|
||||
move
|
||||
pleroma:emoji_reaction
|
||||
poll
|
||||
}
|
||||
def index(%{assigns: %{user: user}} = conn, params) do
|
||||
params =
|
||||
|
|
|
|||
|
|
@ -95,7 +95,20 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
|
|||
{:ok, data} = MRF.describe()
|
||||
|
||||
data
|
||||
|> Map.merge(%{quarantined_instances: quarantined})
|
||||
|> Map.put(
|
||||
:quarantined_instances,
|
||||
Enum.map(quarantined, fn {instance, _reason} -> instance end)
|
||||
)
|
||||
# This is for backwards compatibility. We originally didn't sent
|
||||
# extra info like a reason why an instance was rejected/quarantined/etc.
|
||||
# Because we didn't want to break backwards compatibility it was decided
|
||||
# to add an extra "info" key.
|
||||
|> Map.put(:quarantined_instances_info, %{
|
||||
"quarantined_instances" =>
|
||||
quarantined
|
||||
|> Enum.map(fn {instance, reason} -> {instance, %{"reason" => reason}} end)
|
||||
|> Map.new()
|
||||
})
|
||||
else
|
||||
%{}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -112,6 +112,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|
|||
"move" ->
|
||||
put_target(response, activity, reading_user, %{})
|
||||
|
||||
"poll" ->
|
||||
put_status(response, activity, reading_user, status_render_opts)
|
||||
|
||||
"pleroma:emoji_reaction" ->
|
||||
response
|
||||
|> put_status(parent_activity_fn.(), reading_user, status_render_opts)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ defmodule Pleroma.Web.Push.Subscription do
|
|||
end
|
||||
|
||||
# credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
|
||||
@supported_alert_types ~w[follow favourite mention reblog pleroma:chat_mention pleroma:emoji_reaction]a
|
||||
@supported_alert_types ~w[follow favourite mention reblog poll pleroma:chat_mention pleroma:emoji_reaction]a
|
||||
|
||||
defp alerts(%{data: %{alerts: alerts}}) do
|
||||
alerts = Map.take(alerts, @supported_alert_types)
|
||||
|
|
|
|||
|
|
@ -81,17 +81,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
end
|
||||
end
|
||||
|
||||
def change_password(%{assigns: %{user: user}} = conn, %{
|
||||
password: password,
|
||||
new_password: new_password,
|
||||
new_password_confirmation: new_password_confirmation
|
||||
}) do
|
||||
case CommonAPI.Utils.confirm_current_password(user, password) do
|
||||
def change_password(%{assigns: %{user: user}, body_params: body_params} = conn, %{}) do
|
||||
case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
|
||||
{:ok, user} ->
|
||||
with {:ok, _user} <-
|
||||
User.reset_password(user, %{
|
||||
password: new_password,
|
||||
password_confirmation: new_password_confirmation
|
||||
password: body_params.new_password,
|
||||
password_confirmation: body_params.new_password_confirmation
|
||||
}) do
|
||||
json(conn, %{status: "success"})
|
||||
else
|
||||
|
|
@ -108,10 +104,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
end
|
||||
end
|
||||
|
||||
def change_email(%{assigns: %{user: user}} = conn, %{password: password, email: email}) do
|
||||
case CommonAPI.Utils.confirm_current_password(user, password) do
|
||||
def change_email(%{assigns: %{user: user}, body_params: body_params} = conn, %{}) do
|
||||
case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
|
||||
{:ok, user} ->
|
||||
with {:ok, _user} <- User.change_email(user, email) do
|
||||
with {:ok, _user} <- User.change_email(user, body_params.email) do
|
||||
json(conn, %{status: "success"})
|
||||
else
|
||||
{:error, changeset} ->
|
||||
|
|
|
|||
45
lib/pleroma/workers/poll_worker.ex
Normal file
45
lib/pleroma/workers/poll_worker.ex
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Workers.PollWorker do
|
||||
@moduledoc """
|
||||
Generates notifications when a poll ends.
|
||||
"""
|
||||
use Pleroma.Workers.WorkerHelper, queue: "poll_notifications"
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Object
|
||||
|
||||
@impl Oban.Worker
|
||||
def perform(%Job{args: %{"op" => "poll_end", "activity_id" => activity_id}}) do
|
||||
with %Activity{} = activity <- find_poll_activity(activity_id) do
|
||||
Notification.create_poll_notifications(activity)
|
||||
end
|
||||
end
|
||||
|
||||
defp find_poll_activity(activity_id) do
|
||||
with nil <- Activity.get_by_id(activity_id) do
|
||||
{:error, :poll_activity_not_found}
|
||||
end
|
||||
end
|
||||
|
||||
def schedule_poll_end(%Activity{data: %{"type" => "Create"}, id: activity_id} = activity) do
|
||||
with %Object{data: %{"type" => "Question", "closed" => closed}} when is_binary(closed) <-
|
||||
Object.normalize(activity),
|
||||
{:ok, end_time} <- NaiveDateTime.from_iso8601(closed),
|
||||
:gt <- NaiveDateTime.compare(end_time, NaiveDateTime.utc_now()) do
|
||||
%{
|
||||
op: "poll_end",
|
||||
activity_id: activity_id
|
||||
}
|
||||
|> new(scheduled_at: end_time)
|
||||
|> Oban.insert()
|
||||
else
|
||||
_ -> {:error, activity}
|
||||
end
|
||||
end
|
||||
|
||||
def schedule_poll_end(activity), do: {:error, activity}
|
||||
end
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
defmodule Pleroma.Repo.Migrations.SimplePolicyStringToTuple do
|
||||
use Ecto.Migration
|
||||
|
||||
alias Pleroma.ConfigDB
|
||||
|
||||
def up, do: ConfigDB.get_by_params(%{group: :pleroma, key: :mrf_simple}) |> update_to_tuples
|
||||
def down, do: ConfigDB.get_by_params(%{group: :pleroma, key: :mrf_simple}) |> update_to_strings
|
||||
|
||||
defp update_to_tuples(%{value: value}) do
|
||||
new_value =
|
||||
value
|
||||
|> Enum.map(fn {k, v} ->
|
||||
{k,
|
||||
Enum.map(v, fn
|
||||
{instance, reason} -> {instance, reason}
|
||||
instance -> {instance, ""}
|
||||
end)}
|
||||
end)
|
||||
|
||||
ConfigDB.update_or_create(%{group: :pleroma, key: :mrf_simple, value: new_value})
|
||||
end
|
||||
|
||||
defp update_to_tuples(nil), do: {:ok, nil}
|
||||
|
||||
defp update_to_strings(%{value: value}) do
|
||||
new_value =
|
||||
value
|
||||
|> Enum.map(fn {k, v} ->
|
||||
{k,
|
||||
Enum.map(v, fn
|
||||
{instance, _} -> instance
|
||||
instance -> instance
|
||||
end)}
|
||||
end)
|
||||
|
||||
ConfigDB.update_or_create(%{group: :pleroma, key: :mrf_simple, value: new_value})
|
||||
end
|
||||
|
||||
defp update_to_strings(nil), do: {:ok, nil}
|
||||
end
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
defmodule Pleroma.Repo.Migrations.QuarantainedStringToTuple do
|
||||
use Ecto.Migration
|
||||
|
||||
alias Pleroma.ConfigDB
|
||||
|
||||
def up,
|
||||
do:
|
||||
ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
|
||||
|> update_quarantined_instances_to_tuples
|
||||
|
||||
def down,
|
||||
do:
|
||||
ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
|
||||
|> update_quarantined_instances_to_strings
|
||||
|
||||
defp update_quarantined_instances_to_tuples(%{value: settings}) do
|
||||
settings |> List.keyfind(:quarantined_instances, 0) |> update_to_tuples
|
||||
end
|
||||
|
||||
defp update_quarantined_instances_to_tuples(nil), do: {:ok, nil}
|
||||
|
||||
defp update_to_tuples({:quarantined_instances, instance_list}) do
|
||||
new_value =
|
||||
instance_list
|
||||
|> Enum.map(fn
|
||||
{v, r} -> {v, r}
|
||||
v -> {v, ""}
|
||||
end)
|
||||
|
||||
ConfigDB.update_or_create(%{
|
||||
group: :pleroma,
|
||||
key: :instance,
|
||||
value: [quarantined_instances: new_value]
|
||||
})
|
||||
end
|
||||
|
||||
defp update_to_tuples(nil), do: {:ok, nil}
|
||||
|
||||
defp update_quarantined_instances_to_strings(%{value: settings}) do
|
||||
settings |> List.keyfind(:quarantined_instances, 0) |> update_to_strings
|
||||
end
|
||||
|
||||
defp update_quarantined_instances_to_strings(nil), do: {:ok, nil}
|
||||
|
||||
defp update_to_strings({:quarantined_instances, instance_list}) do
|
||||
new_value =
|
||||
instance_list
|
||||
|> Enum.map(fn
|
||||
{v, _} -> v
|
||||
v -> v
|
||||
end)
|
||||
|
||||
ConfigDB.update_or_create(%{
|
||||
group: :pleroma,
|
||||
key: :instance,
|
||||
value: [quarantined_instances: new_value]
|
||||
})
|
||||
end
|
||||
|
||||
defp update_to_strings(nil), do: {:ok, nil}
|
||||
end
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
defmodule Pleroma.Repo.Migrations.TransparencyExclusionsStringToTuple do
|
||||
use Ecto.Migration
|
||||
|
||||
alias Pleroma.ConfigDB
|
||||
|
||||
def up,
|
||||
do:
|
||||
ConfigDB.get_by_params(%{group: :pleroma, key: :mrf})
|
||||
|> update_transparency_exclusions_instances_to_tuples
|
||||
|
||||
def down,
|
||||
do:
|
||||
ConfigDB.get_by_params(%{group: :pleroma, key: :mrf})
|
||||
|> update_transparency_exclusions_instances_to_strings
|
||||
|
||||
defp update_transparency_exclusions_instances_to_tuples(%{value: settings}) do
|
||||
settings |> List.keyfind(:transparency_exclusions, 0) |> update_to_tuples
|
||||
end
|
||||
|
||||
defp update_transparency_exclusions_instances_to_tuples(nil), do: {:ok, nil}
|
||||
|
||||
defp update_to_tuples({:transparency_exclusions, instance_list}) do
|
||||
new_value =
|
||||
instance_list
|
||||
|> Enum.map(fn
|
||||
{v, r} -> {v, r}
|
||||
v -> {v, ""}
|
||||
end)
|
||||
|
||||
ConfigDB.update_or_create(%{
|
||||
group: :pleroma,
|
||||
key: :mrf,
|
||||
value: [transparency_exclusions: new_value]
|
||||
})
|
||||
end
|
||||
|
||||
defp update_to_tuples(nil), do: {:ok, nil}
|
||||
|
||||
defp update_transparency_exclusions_instances_to_strings(%{value: settings}) do
|
||||
settings |> List.keyfind(:transparency_exclusions, 0) |> update_to_strings
|
||||
end
|
||||
|
||||
defp update_transparency_exclusions_instances_to_strings(nil), do: {:ok, nil}
|
||||
|
||||
defp update_to_strings({:transparency_exclusions, instance_list}) do
|
||||
new_value =
|
||||
instance_list
|
||||
|> Enum.map(fn
|
||||
{v, _} -> v
|
||||
v -> v
|
||||
end)
|
||||
|
||||
ConfigDB.update_or_create(%{
|
||||
group: :pleroma,
|
||||
key: :mrf,
|
||||
value: [transparency_exclusions: new_value]
|
||||
})
|
||||
end
|
||||
|
||||
defp update_to_strings(nil), do: {:ok, nil}
|
||||
end
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
defmodule Pleroma.Repo.Migrations.AddPollToNotificationsEnum do
|
||||
use Ecto.Migration
|
||||
|
||||
@disable_ddl_transaction true
|
||||
|
||||
def up do
|
||||
"""
|
||||
alter type notification_type add value 'poll'
|
||||
"""
|
||||
|> execute()
|
||||
end
|
||||
|
||||
def down do
|
||||
alter table(:notifications) do
|
||||
modify(:type, :string)
|
||||
end
|
||||
|
||||
"""
|
||||
delete from notifications where type = 'poll'
|
||||
"""
|
||||
|> execute()
|
||||
|
||||
"""
|
||||
drop type if exists notification_type
|
||||
"""
|
||||
|> execute()
|
||||
|
||||
"""
|
||||
create type notification_type as enum (
|
||||
'follow',
|
||||
'follow_request',
|
||||
'mention',
|
||||
'move',
|
||||
'pleroma:emoji_reaction',
|
||||
'pleroma:chat_mention',
|
||||
'reblog',
|
||||
'favourite',
|
||||
'pleroma:report'
|
||||
)
|
||||
"""
|
||||
|> execute()
|
||||
|
||||
"""
|
||||
alter table notifications
|
||||
alter column type type notification_type using (type::notification_type)
|
||||
"""
|
||||
|> execute()
|
||||
end
|
||||
end
|
||||
|
|
@ -11,6 +11,183 @@ defmodule Pleroma.Config.DeprecationWarningsTest do
|
|||
alias Pleroma.Config
|
||||
alias Pleroma.Config.DeprecationWarnings
|
||||
|
||||
describe "simple policy tuples" do
|
||||
test "gives warning when there are still strings" do
|
||||
clear_config([:mrf_simple],
|
||||
media_removal: ["some.removal"],
|
||||
media_nsfw: ["some.nsfw"],
|
||||
federated_timeline_removal: ["some.tl.removal"],
|
||||
report_removal: ["some.report.removal"],
|
||||
reject: ["some.reject"],
|
||||
followers_only: ["some.followers.only"],
|
||||
accept: ["some.accept"],
|
||||
avatar_removal: ["some.avatar.removal"],
|
||||
banner_removal: ["some.banner.removal"],
|
||||
reject_deletes: ["some.reject.deletes"]
|
||||
)
|
||||
|
||||
assert capture_log(fn -> DeprecationWarnings.check_simple_policy_tuples() end) =~
|
||||
"""
|
||||
!!!DEPRECATION WARNING!!!
|
||||
Your config is using strings in the SimplePolicy configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||
|
||||
```
|
||||
config :pleroma, :mrf_simple,
|
||||
media_removal: ["instance.tld"],
|
||||
media_nsfw: ["instance.tld"],
|
||||
federated_timeline_removal: ["instance.tld"],
|
||||
report_removal: ["instance.tld"],
|
||||
reject: ["instance.tld"],
|
||||
followers_only: ["instance.tld"],
|
||||
accept: ["instance.tld"],
|
||||
avatar_removal: ["instance.tld"],
|
||||
banner_removal: ["instance.tld"],
|
||||
reject_deletes: ["instance.tld"]
|
||||
```
|
||||
|
||||
Is now
|
||||
|
||||
|
||||
```
|
||||
config :pleroma, :mrf_simple,
|
||||
media_removal: [{"instance.tld", "Reason for media removal"}],
|
||||
media_nsfw: [{"instance.tld", "Reason for media nsfw"}],
|
||||
federated_timeline_removal: [{"instance.tld", "Reason for federated timeline removal"}],
|
||||
report_removal: [{"instance.tld", "Reason for report removal"}],
|
||||
reject: [{"instance.tld", "Reason for reject"}],
|
||||
followers_only: [{"instance.tld", "Reason for followers only"}],
|
||||
accept: [{"instance.tld", "Reason for accept"}],
|
||||
avatar_removal: [{"instance.tld", "Reason for avatar removal"}],
|
||||
banner_removal: [{"instance.tld", "Reason for banner removal"}],
|
||||
reject_deletes: [{"instance.tld", "Reason for reject deletes"}]
|
||||
```
|
||||
"""
|
||||
end
|
||||
|
||||
test "transforms config to tuples" do
|
||||
clear_config([:mrf_simple],
|
||||
media_removal: ["some.removal", {"some.other.instance", "Some reason"}]
|
||||
)
|
||||
|
||||
expected_config = [
|
||||
{:media_removal, [{"some.removal", ""}, {"some.other.instance", "Some reason"}]}
|
||||
]
|
||||
|
||||
capture_log(fn -> DeprecationWarnings.warn() end)
|
||||
|
||||
assert Config.get([:mrf_simple]) == expected_config
|
||||
end
|
||||
|
||||
test "doesn't give a warning with correct config" do
|
||||
clear_config([:mrf_simple],
|
||||
media_removal: [{"some.removal", ""}, {"some.other.instance", "Some reason"}]
|
||||
)
|
||||
|
||||
assert capture_log(fn -> DeprecationWarnings.check_simple_policy_tuples() end) == ""
|
||||
end
|
||||
end
|
||||
|
||||
describe "quarantined_instances tuples" do
|
||||
test "gives warning when there are still strings" do
|
||||
clear_config([:instance, :quarantined_instances], [
|
||||
{"domain.com", "some reason"},
|
||||
"somedomain.tld"
|
||||
])
|
||||
|
||||
assert capture_log(fn -> DeprecationWarnings.check_quarantined_instances_tuples() end) =~
|
||||
"""
|
||||
!!!DEPRECATION WARNING!!!
|
||||
Your config is using strings in the quarantined_instances configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||
|
||||
```
|
||||
config :pleroma, :instance,
|
||||
quarantined_instances: ["instance.tld"]
|
||||
```
|
||||
|
||||
Is now
|
||||
|
||||
|
||||
```
|
||||
config :pleroma, :instance,
|
||||
quarantined_instances: [{"instance.tld", "Reason for quarantine"}]
|
||||
```
|
||||
"""
|
||||
end
|
||||
|
||||
test "transforms config to tuples" do
|
||||
clear_config([:instance, :quarantined_instances], [
|
||||
{"domain.com", "some reason"},
|
||||
"some.tld"
|
||||
])
|
||||
|
||||
expected_config = [{"domain.com", "some reason"}, {"some.tld", ""}]
|
||||
|
||||
capture_log(fn -> DeprecationWarnings.warn() end)
|
||||
|
||||
assert Config.get([:instance, :quarantined_instances]) == expected_config
|
||||
end
|
||||
|
||||
test "doesn't give a warning with correct config" do
|
||||
clear_config([:instance, :quarantined_instances], [
|
||||
{"domain.com", "some reason"},
|
||||
{"some.tld", ""}
|
||||
])
|
||||
|
||||
assert capture_log(fn -> DeprecationWarnings.check_quarantined_instances_tuples() end) == ""
|
||||
end
|
||||
end
|
||||
|
||||
describe "transparency_exclusions tuples" do
|
||||
test "gives warning when there are still strings" do
|
||||
clear_config([:mrf, :transparency_exclusions], [
|
||||
{"domain.com", "some reason"},
|
||||
"somedomain.tld"
|
||||
])
|
||||
|
||||
assert capture_log(fn -> DeprecationWarnings.check_transparency_exclusions_tuples() end) =~
|
||||
"""
|
||||
!!!DEPRECATION WARNING!!!
|
||||
Your config is using strings in the transparency_exclusions configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||
|
||||
```
|
||||
config :pleroma, :mrf,
|
||||
transparency_exclusions: ["instance.tld"]
|
||||
```
|
||||
|
||||
Is now
|
||||
|
||||
|
||||
```
|
||||
config :pleroma, :mrf,
|
||||
transparency_exclusions: [{"instance.tld", "Reason to exlude transparency"}]
|
||||
```
|
||||
"""
|
||||
end
|
||||
|
||||
test "transforms config to tuples" do
|
||||
clear_config([:mrf, :transparency_exclusions], [
|
||||
{"domain.com", "some reason"},
|
||||
"some.tld"
|
||||
])
|
||||
|
||||
expected_config = [{"domain.com", "some reason"}, {"some.tld", ""}]
|
||||
|
||||
capture_log(fn -> DeprecationWarnings.warn() end)
|
||||
|
||||
assert Config.get([:mrf, :transparency_exclusions]) == expected_config
|
||||
end
|
||||
|
||||
test "doesn't give a warning with correct config" do
|
||||
clear_config([:mrf, :transparency_exclusions], [
|
||||
{"domain.com", "some reason"},
|
||||
{"some.tld", ""}
|
||||
])
|
||||
|
||||
assert capture_log(fn -> DeprecationWarnings.check_transparency_exclusions_tuples() end) ==
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
test "check_old_mrf_config/0" do
|
||||
clear_config([:instance, :rewrite_policy], [])
|
||||
clear_config([:instance, :mrf_transparency], true)
|
||||
|
|
|
|||
|
|
@ -129,6 +129,19 @@ defmodule Pleroma.NotificationTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "create_poll_notifications/1" do
|
||||
[user1, user2, user3, _, _] = insert_list(5, :user)
|
||||
question = insert(:question, user: user1)
|
||||
activity = insert(:question_activity, question: question)
|
||||
|
||||
{:ok, _, _} = CommonAPI.vote(user2, question, [0])
|
||||
{:ok, _, _} = CommonAPI.vote(user3, question, [1])
|
||||
|
||||
{:ok, notifications} = Notification.create_poll_notifications(activity)
|
||||
|
||||
assert [user2.id, user3.id, user1.id] == Enum.map(notifications, & &1.user_id)
|
||||
end
|
||||
|
||||
describe "CommonApi.post/2 notification-related functionality" do
|
||||
test_with_mock "creates but does NOT send notification to blocker user",
|
||||
Push,
|
||||
|
|
|
|||
|
|
@ -480,7 +480,7 @@ defmodule Pleroma.UserTest do
|
|||
)
|
||||
|
||||
test "it sends a welcome chat message when Simple policy applied to local instance" do
|
||||
clear_config([:mrf_simple, :media_nsfw], ["localhost"])
|
||||
clear_config([:mrf_simple, :media_nsfw], [{"localhost", ""}])
|
||||
|
||||
welcome_user = insert(:user)
|
||||
clear_config([:welcome, :chat_message, :enabled], true)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
|
|||
defp get_old_message do
|
||||
File.read!("test/fixtures/mastodon-post-activity.json")
|
||||
|> Jason.decode!()
|
||||
|> Map.drop(["published"])
|
||||
end
|
||||
|
||||
defp get_new_message do
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "has a matching host" do
|
||||
clear_config([:mrf_simple, :media_removal], ["remote.instance"])
|
||||
clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}])
|
||||
media_message = build_media_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
clear_config([:mrf_simple, :media_removal], ["*.remote.instance"])
|
||||
clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}])
|
||||
media_message = build_media_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "has a matching host" do
|
||||
clear_config([:mrf_simple, :media_nsfw], ["remote.instance"])
|
||||
clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
|
||||
media_message = build_media_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
clear_config([:mrf_simple, :media_nsfw], ["*.remote.instance"])
|
||||
clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}])
|
||||
media_message = build_media_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
|
|
@ -115,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "has a matching host" do
|
||||
clear_config([:mrf_simple, :report_removal], ["remote.instance"])
|
||||
clear_config([:mrf_simple, :report_removal], [{"remote.instance", "muh"}])
|
||||
report_message = build_report_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
clear_config([:mrf_simple, :report_removal], ["*.remote.instance"])
|
||||
clear_config([:mrf_simple, :report_removal], [{"*.remote.instance", "suya"}])
|
||||
report_message = build_report_message()
|
||||
local_message = build_local_message()
|
||||
|
||||
|
|
@ -159,7 +159,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
|> URI.parse()
|
||||
|> Map.fetch!(:host)
|
||||
|
||||
clear_config([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host])
|
||||
clear_config([:mrf_simple, :federated_timeline_removal], [{ftl_message_actor_host, "uwu"}])
|
||||
local_message = build_local_message()
|
||||
|
||||
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
|
||||
|
|
@ -180,7 +180,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
|> URI.parse()
|
||||
|> Map.fetch!(:host)
|
||||
|
||||
clear_config([:mrf_simple, :federated_timeline_removal], ["*." <> ftl_message_actor_host])
|
||||
clear_config([:mrf_simple, :federated_timeline_removal], [
|
||||
{"*." <> ftl_message_actor_host, "owo"}
|
||||
])
|
||||
|
||||
local_message = build_local_message()
|
||||
|
||||
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
|
||||
|
|
@ -203,7 +206,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
|
||||
ftl_message = Map.put(ftl_message, "cc", [])
|
||||
|
||||
clear_config([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host])
|
||||
clear_config([:mrf_simple, :federated_timeline_removal], [
|
||||
{ftl_message_actor_host, "spiderwaifu goes 88w88"}
|
||||
])
|
||||
|
||||
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
|
||||
refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
|
||||
|
|
@ -232,7 +237,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "activity has a matching host" do
|
||||
clear_config([:mrf_simple, :reject], ["remote.instance"])
|
||||
clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
|
||||
|
||||
remote_message = build_remote_message()
|
||||
|
||||
|
|
@ -240,7 +245,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "activity matches with wildcard domain" do
|
||||
clear_config([:mrf_simple, :reject], ["*.remote.instance"])
|
||||
clear_config([:mrf_simple, :reject], [{"*.remote.instance", ""}])
|
||||
|
||||
remote_message = build_remote_message()
|
||||
|
||||
|
|
@ -248,7 +253,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "actor has a matching host" do
|
||||
clear_config([:mrf_simple, :reject], ["remote.instance"])
|
||||
clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
|
|
@ -256,7 +261,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "reject Announce when object would be rejected" do
|
||||
clear_config([:mrf_simple, :reject], ["blocked.tld"])
|
||||
clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
|
||||
|
||||
announce = %{
|
||||
"type" => "Announce",
|
||||
|
|
@ -268,7 +273,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "reject by URI object" do
|
||||
clear_config([:mrf_simple, :reject], ["blocked.tld"])
|
||||
clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
|
||||
|
||||
announce = %{
|
||||
"type" => "Announce",
|
||||
|
|
@ -322,7 +327,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
|> URI.parse()
|
||||
|> Map.fetch!(:host)
|
||||
|
||||
clear_config([:mrf_simple, :followers_only], [actor_domain])
|
||||
clear_config([:mrf_simple, :followers_only], [{actor_domain, ""}])
|
||||
|
||||
assert {:ok, new_activity} = SimplePolicy.filter(activity)
|
||||
assert actor.follower_address in new_activity["cc"]
|
||||
|
|
@ -350,7 +355,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "is not empty but activity doesn't have a matching host" do
|
||||
clear_config([:mrf_simple, :accept], ["non.matching.remote"])
|
||||
clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
|
||||
|
||||
local_message = build_local_message()
|
||||
remote_message = build_remote_message()
|
||||
|
|
@ -360,7 +365,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "activity has a matching host" do
|
||||
clear_config([:mrf_simple, :accept], ["remote.instance"])
|
||||
clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
|
||||
|
||||
local_message = build_local_message()
|
||||
remote_message = build_remote_message()
|
||||
|
|
@ -370,7 +375,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "activity matches with wildcard domain" do
|
||||
clear_config([:mrf_simple, :accept], ["*.remote.instance"])
|
||||
clear_config([:mrf_simple, :accept], [{"*.remote.instance", ""}])
|
||||
|
||||
local_message = build_local_message()
|
||||
remote_message = build_remote_message()
|
||||
|
|
@ -380,7 +385,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "actor has a matching host" do
|
||||
clear_config([:mrf_simple, :accept], ["remote.instance"])
|
||||
clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
|
|
@ -398,7 +403,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "is not empty but it doesn't have a matching host" do
|
||||
clear_config([:mrf_simple, :avatar_removal], ["non.matching.remote"])
|
||||
clear_config([:mrf_simple, :avatar_removal], [{"non.matching.remote", ""}])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
|
|
@ -406,7 +411,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "has a matching host" do
|
||||
clear_config([:mrf_simple, :avatar_removal], ["remote.instance"])
|
||||
clear_config([:mrf_simple, :avatar_removal], [{"remote.instance", ""}])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
||||
|
|
@ -415,7 +420,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
clear_config([:mrf_simple, :avatar_removal], ["*.remote.instance"])
|
||||
clear_config([:mrf_simple, :avatar_removal], [{"*.remote.instance", ""}])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
||||
|
|
@ -434,7 +439,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "is not empty but it doesn't have a matching host" do
|
||||
clear_config([:mrf_simple, :banner_removal], ["non.matching.remote"])
|
||||
clear_config([:mrf_simple, :banner_removal], [{"non.matching.remote", ""}])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
|
|
@ -442,7 +447,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "has a matching host" do
|
||||
clear_config([:mrf_simple, :banner_removal], ["remote.instance"])
|
||||
clear_config([:mrf_simple, :banner_removal], [{"remote.instance", ""}])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
||||
|
|
@ -451,7 +456,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
clear_config([:mrf_simple, :banner_removal], ["*.remote.instance"])
|
||||
clear_config([:mrf_simple, :banner_removal], [{"*.remote.instance", ""}])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
{:ok, filtered} = SimplePolicy.filter(remote_user)
|
||||
|
|
@ -464,7 +469,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
setup do: clear_config([:mrf_simple, :reject_deletes], [])
|
||||
|
||||
test "it accepts deletions even from rejected servers" do
|
||||
clear_config([:mrf_simple, :reject], ["remote.instance"])
|
||||
clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
|
||||
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
||||
|
|
@ -472,7 +477,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "it accepts deletions even from non-whitelisted servers" do
|
||||
clear_config([:mrf_simple, :accept], ["non.matching.remote"])
|
||||
clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
|
||||
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
||||
|
|
@ -481,10 +486,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
describe "when :reject_deletes is not empty but it doesn't have a matching host" do
|
||||
setup do: clear_config([:mrf_simple, :reject_deletes], ["non.matching.remote"])
|
||||
setup do: clear_config([:mrf_simple, :reject_deletes], [{"non.matching.remote", ""}])
|
||||
|
||||
test "it accepts deletions even from rejected servers" do
|
||||
clear_config([:mrf_simple, :reject], ["remote.instance"])
|
||||
clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
|
||||
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
||||
|
|
@ -492,7 +497,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
test "it accepts deletions even from non-whitelisted servers" do
|
||||
clear_config([:mrf_simple, :accept], ["non.matching.remote"])
|
||||
clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
|
||||
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
||||
|
|
@ -501,7 +506,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
describe "when :reject_deletes has a matching host" do
|
||||
setup do: clear_config([:mrf_simple, :reject_deletes], ["remote.instance"])
|
||||
setup do: clear_config([:mrf_simple, :reject_deletes], [{"remote.instance", ""}])
|
||||
|
||||
test "it rejects the deletion" do
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
|
@ -511,7 +516,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
end
|
||||
|
||||
describe "when :reject_deletes match with wildcard domain" do
|
||||
setup do: clear_config([:mrf_simple, :reject_deletes], ["*.remote.instance"])
|
||||
setup do: clear_config([:mrf_simple, :reject_deletes], [{"*.remote.instance", ""}])
|
||||
|
||||
test "it rejects the deletion" do
|
||||
deletion_message = build_remote_deletion_message()
|
||||
|
|
|
|||
|
|
@ -63,6 +63,15 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "instance_list_from_tuples/1" do
|
||||
test "returns a list of instances from a list of {instance, reason} tuples" do
|
||||
list = [{"some.tld", "a reason"}, {"other.tld", "another reason"}]
|
||||
expected = ["some.tld", "other.tld"]
|
||||
|
||||
assert MRF.instance_list_from_tuples(list) == expected
|
||||
end
|
||||
end
|
||||
|
||||
describe "describe/0" do
|
||||
test "it works as expected with noop policy" do
|
||||
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoOpPolicy])
|
||||
|
|
|
|||
|
|
@ -267,6 +267,80 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
|
|||
end
|
||||
|
||||
describe "publish/2" do
|
||||
test_with_mock "doesn't publish a non-public activity to quarantined instances.",
|
||||
Pleroma.Web.Federator.Publisher,
|
||||
[:passthrough],
|
||||
[] do
|
||||
Config.put([:instance, :quarantined_instances], [{"domain.com", "some reason"}])
|
||||
|
||||
follower =
|
||||
insert(:user, %{
|
||||
local: false,
|
||||
inbox: "https://domain.com/users/nick1/inbox",
|
||||
ap_enabled: true
|
||||
})
|
||||
|
||||
actor = insert(:user, follower_address: follower.ap_id)
|
||||
|
||||
{:ok, follower, actor} = Pleroma.User.follow(follower, actor)
|
||||
actor = refresh_record(actor)
|
||||
|
||||
note_activity =
|
||||
insert(:followers_only_note_activity,
|
||||
user: actor,
|
||||
recipients: [follower.ap_id]
|
||||
)
|
||||
|
||||
res = Publisher.publish(actor, note_activity)
|
||||
|
||||
assert res == :ok
|
||||
|
||||
assert not called(
|
||||
Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
|
||||
inbox: "https://domain.com/users/nick1/inbox",
|
||||
actor_id: actor.id,
|
||||
id: note_activity.data["id"]
|
||||
})
|
||||
)
|
||||
end
|
||||
|
||||
test_with_mock "Publishes a non-public activity to non-quarantined instances.",
|
||||
Pleroma.Web.Federator.Publisher,
|
||||
[:passthrough],
|
||||
[] do
|
||||
Config.put([:instance, :quarantined_instances], [{"somedomain.com", "some reason"}])
|
||||
|
||||
follower =
|
||||
insert(:user, %{
|
||||
local: false,
|
||||
inbox: "https://domain.com/users/nick1/inbox",
|
||||
ap_enabled: true
|
||||
})
|
||||
|
||||
actor = insert(:user, follower_address: follower.ap_id)
|
||||
|
||||
{:ok, follower, actor} = Pleroma.User.follow(follower, actor)
|
||||
actor = refresh_record(actor)
|
||||
|
||||
note_activity =
|
||||
insert(:followers_only_note_activity,
|
||||
user: actor,
|
||||
recipients: [follower.ap_id]
|
||||
)
|
||||
|
||||
res = Publisher.publish(actor, note_activity)
|
||||
|
||||
assert res == :ok
|
||||
|
||||
assert called(
|
||||
Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
|
||||
inbox: "https://domain.com/users/nick1/inbox",
|
||||
actor_id: actor.id,
|
||||
id: note_activity.data["id"]
|
||||
})
|
||||
)
|
||||
end
|
||||
|
||||
test_with_mock "publishes an activity with BCC to all relevant peers.",
|
||||
Pleroma.Web.Federator.Publisher,
|
||||
[:passthrough],
|
||||
|
|
|
|||
|
|
@ -157,6 +157,30 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "Question objects" do
|
||||
setup do
|
||||
user = insert(:user)
|
||||
question = build(:question, user: user)
|
||||
question_activity = build(:question_activity, question: question)
|
||||
activity_data = Map.put(question_activity.data, "object", question.data["id"])
|
||||
meta = [object_data: question.data, local: false]
|
||||
|
||||
{:ok, activity, meta} = ActivityPub.persist(activity_data, meta)
|
||||
|
||||
%{activity: activity, meta: meta}
|
||||
end
|
||||
|
||||
test "enqueues the poll end", %{activity: activity, meta: meta} do
|
||||
{:ok, activity, meta} = SideEffects.handle(activity, meta)
|
||||
|
||||
assert_enqueued(
|
||||
worker: Pleroma.Workers.PollWorker,
|
||||
args: %{op: "poll_end", activity_id: activity.id},
|
||||
scheduled_at: NaiveDateTime.from_iso8601!(meta[:object_data]["closed"])
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete users with confirmation pending" do
|
||||
setup do
|
||||
user = insert(:user, is_confirmed: false)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
alias Pleroma.Web.AdminAPI.AccountView
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Workers.PollWorker
|
||||
|
||||
import Pleroma.Factory
|
||||
import Mock
|
||||
|
|
@ -48,6 +49,12 @@ defmodule Pleroma.Web.CommonAPITest do
|
|||
|
||||
assert object.data["type"] == "Question"
|
||||
assert object.data["oneOf"] |> length() == 2
|
||||
|
||||
assert_enqueued(
|
||||
worker: PollWorker,
|
||||
args: %{op: "poll_end", activity_id: activity.id},
|
||||
scheduled_at: NaiveDateTime.from_iso8601!(object.data["closed"])
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Workers.ScheduledActivityWorker
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
|
|
@ -705,11 +706,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
|||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert {:ok, %{id: activity_id}} =
|
||||
perform_job(Pleroma.Workers.ScheduledActivityWorker, %{
|
||||
perform_job(ScheduledActivityWorker, %{
|
||||
activity_id: scheduled_id
|
||||
})
|
||||
|
||||
assert Repo.all(Oban.Job) == []
|
||||
refute_enqueued(worker: ScheduledActivityWorker)
|
||||
|
||||
object =
|
||||
Activity
|
||||
|
|
|
|||
|
|
@ -196,6 +196,27 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
|
|||
test_notifications_rendering([notification], user, [expected])
|
||||
end
|
||||
|
||||
test "Poll notification" do
|
||||
user = insert(:user)
|
||||
activity = insert(:question_activity, user: user)
|
||||
{:ok, [notification]} = Notification.create_poll_notifications(activity)
|
||||
|
||||
expected = %{
|
||||
id: to_string(notification.id),
|
||||
pleroma: %{is_seen: false, is_muted: false},
|
||||
type: "poll",
|
||||
account:
|
||||
AccountView.render("show.json", %{
|
||||
user: user,
|
||||
for: user
|
||||
}),
|
||||
status: StatusView.render("show.json", %{activity: activity, for: user}),
|
||||
created_at: Utils.to_masto_date(notification.inserted_at)
|
||||
}
|
||||
|
||||
test_notifications_rendering([notification], user, [expected])
|
||||
end
|
||||
|
||||
test "Report notification" do
|
||||
reporting_user = insert(:user)
|
||||
reported_user = insert(:user)
|
||||
|
|
|
|||
|
|
@ -150,37 +150,127 @@ defmodule Pleroma.Web.NodeInfoTest do
|
|||
)
|
||||
end
|
||||
|
||||
test "it shows MRF transparency data if enabled", %{conn: conn} do
|
||||
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
|
||||
clear_config([:mrf, :transparency], true)
|
||||
describe "Quarantined instances" do
|
||||
setup do
|
||||
clear_config([:mrf, :transparency], true)
|
||||
quarantined_instances = [{"example.com", "reason to quarantine"}]
|
||||
clear_config([:instance, :quarantined_instances], quarantined_instances)
|
||||
end
|
||||
|
||||
simple_config = %{"reject" => ["example.com"]}
|
||||
clear_config(:mrf_simple, simple_config)
|
||||
test "shows quarantined instances data if enabled", %{conn: conn} do
|
||||
expected_config = ["example.com"]
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/nodeinfo/2.1.json")
|
||||
|> json_response(:ok)
|
||||
response =
|
||||
conn
|
||||
|> get("/nodeinfo/2.1.json")
|
||||
|> json_response(:ok)
|
||||
|
||||
assert response["metadata"]["federation"]["mrf_simple"] == simple_config
|
||||
assert response["metadata"]["federation"]["quarantined_instances"] == expected_config
|
||||
end
|
||||
|
||||
test "shows extra information in the quarantined_info field for relevant entries", %{
|
||||
conn: conn
|
||||
} do
|
||||
clear_config([:mrf, :transparency], true)
|
||||
|
||||
expected_config = %{
|
||||
"quarantined_instances" => %{
|
||||
"example.com" => %{"reason" => "reason to quarantine"}
|
||||
}
|
||||
}
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/nodeinfo/2.1.json")
|
||||
|> json_response(:ok)
|
||||
|
||||
assert response["metadata"]["federation"]["quarantined_instances_info"] == expected_config
|
||||
end
|
||||
end
|
||||
|
||||
test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do
|
||||
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
|
||||
clear_config([:mrf, :transparency], true)
|
||||
clear_config([:mrf, :transparency_exclusions], ["other.site"])
|
||||
describe "MRF SimplePolicy" do
|
||||
setup do
|
||||
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
|
||||
clear_config([:mrf, :transparency], true)
|
||||
end
|
||||
|
||||
simple_config = %{"reject" => ["example.com", "other.site"]}
|
||||
clear_config(:mrf_simple, simple_config)
|
||||
test "shows MRF transparency data if enabled", %{conn: conn} do
|
||||
simple_config = %{"reject" => [{"example.com", ""}]}
|
||||
clear_config(:mrf_simple, simple_config)
|
||||
|
||||
expected_config = %{"reject" => ["example.com"]}
|
||||
expected_config = %{"reject" => ["example.com"]}
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/nodeinfo/2.1.json")
|
||||
|> json_response(:ok)
|
||||
response =
|
||||
conn
|
||||
|> get("/nodeinfo/2.1.json")
|
||||
|> json_response(:ok)
|
||||
|
||||
assert response["metadata"]["federation"]["mrf_simple"] == expected_config
|
||||
assert response["metadata"]["federation"]["exclusions"] == true
|
||||
assert response["metadata"]["federation"]["mrf_simple"] == expected_config
|
||||
end
|
||||
|
||||
test "performs exclusions from MRF transparency data if configured", %{conn: conn} do
|
||||
clear_config([:mrf, :transparency_exclusions], [
|
||||
{"other.site", "We don't want them to know"}
|
||||
])
|
||||
|
||||
simple_config = %{"reject" => [{"example.com", ""}, {"other.site", ""}]}
|
||||
clear_config(:mrf_simple, simple_config)
|
||||
|
||||
expected_config = %{"reject" => ["example.com"]}
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/nodeinfo/2.1.json")
|
||||
|> json_response(:ok)
|
||||
|
||||
assert response["metadata"]["federation"]["mrf_simple"] == expected_config
|
||||
assert response["metadata"]["federation"]["exclusions"] == true
|
||||
end
|
||||
|
||||
test "shows extra information in the mrf_simple_info field for relevant entries", %{
|
||||
conn: conn
|
||||
} do
|
||||
simple_config = %{
|
||||
media_removal: [{"no.media", "LEEWWWDD >//<"}],
|
||||
media_nsfw: [],
|
||||
federated_timeline_removal: [{"no.ftl", ""}],
|
||||
report_removal: [],
|
||||
reject: [
|
||||
{"example.instance", "Some reason"},
|
||||
{"uwu.owo", "awoo to much"},
|
||||
{"no.reason", ""}
|
||||
],
|
||||
followers_only: [],
|
||||
accept: [],
|
||||
avatar_removal: [],
|
||||
banner_removal: [],
|
||||
reject_deletes: [
|
||||
{"peak.me", "I want to peak at what they don't want me to see, eheh"}
|
||||
]
|
||||
}
|
||||
|
||||
clear_config(:mrf_simple, simple_config)
|
||||
|
||||
clear_config([:mrf, :transparency_exclusions], [
|
||||
{"peak.me", "I don't want them to know"}
|
||||
])
|
||||
|
||||
expected_config = %{
|
||||
"media_removal" => %{
|
||||
"no.media" => %{"reason" => "LEEWWWDD >//<"}
|
||||
},
|
||||
"reject" => %{
|
||||
"example.instance" => %{"reason" => "Some reason"},
|
||||
"uwu.owo" => %{"reason" => "awoo to much"}
|
||||
}
|
||||
}
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/nodeinfo/2.1.json")
|
||||
|> json_response(:ok)
|
||||
|
||||
assert response["metadata"]["federation"]["mrf_simple_info"] == expected_config
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -261,11 +261,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
conn =
|
||||
conn
|
||||
|> assign(:token, nil)
|
||||
|> post(
|
||||
"/api/pleroma/change_email?#{
|
||||
URI.encode_query(%{password: "hi", email: "test@test.com"})
|
||||
}"
|
||||
)
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/pleroma/change_email", %{password: "hi", email: "test@test.com"})
|
||||
|
||||
assert json_response_and_validate_schema(conn, 403) == %{
|
||||
"error" => "Insufficient permissions: write:accounts."
|
||||
|
|
@ -274,12 +271,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
|
||||
test "with proper permissions and invalid password", %{conn: conn} do
|
||||
conn =
|
||||
post(
|
||||
conn,
|
||||
"/api/pleroma/change_email?#{
|
||||
URI.encode_query(%{password: "hi", email: "test@test.com"})
|
||||
}"
|
||||
)
|
||||
conn
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/pleroma/change_email", %{password: "hi", email: "test@test.com"})
|
||||
|
||||
assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."}
|
||||
end
|
||||
|
|
@ -288,10 +282,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
conn: conn
|
||||
} do
|
||||
conn =
|
||||
post(
|
||||
conn,
|
||||
"/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: "foobar"})}"
|
||||
)
|
||||
conn
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/pleroma/change_email", %{password: "test", email: "foobar"})
|
||||
|
||||
assert json_response_and_validate_schema(conn, 200) == %{
|
||||
"error" => "Email has invalid format."
|
||||
|
|
@ -301,7 +294,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
test "with proper permissions, valid password and no email", %{
|
||||
conn: conn
|
||||
} do
|
||||
conn = post(conn, "/api/pleroma/change_email?#{URI.encode_query(%{password: "test"})}")
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/pleroma/change_email", %{password: "test"})
|
||||
|
||||
assert %{"error" => "Missing field: email."} = json_response_and_validate_schema(conn, 400)
|
||||
end
|
||||
|
|
@ -310,10 +306,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
conn: conn
|
||||
} do
|
||||
conn =
|
||||
post(
|
||||
conn,
|
||||
"/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: ""})}"
|
||||
)
|
||||
conn
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/pleroma/change_email", %{password: "test", email: ""})
|
||||
|
||||
assert json_response_and_validate_schema(conn, 200) == %{"error" => "Email can't be blank."}
|
||||
end
|
||||
|
|
@ -324,10 +319,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
user = insert(:user)
|
||||
|
||||
conn =
|
||||
post(
|
||||
conn,
|
||||
"/api/pleroma/change_email?#{URI.encode_query(%{password: "test", email: user.email})}"
|
||||
)
|
||||
conn
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/pleroma/change_email", %{password: "test", email: user.email})
|
||||
|
||||
assert json_response_and_validate_schema(conn, 200) == %{
|
||||
"error" => "Email has already been taken."
|
||||
|
|
@ -338,12 +332,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
conn: conn
|
||||
} do
|
||||
conn =
|
||||
post(
|
||||
conn,
|
||||
"/api/pleroma/change_email?#{
|
||||
URI.encode_query(%{password: "test", email: "cofe@foobar.com"})
|
||||
}"
|
||||
)
|
||||
conn
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/pleroma/change_email", %{password: "test", email: "cofe@foobar.com"})
|
||||
|
||||
assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
|
||||
end
|
||||
|
|
@ -356,15 +347,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
conn =
|
||||
conn
|
||||
|> assign(:token, nil)
|
||||
|> post(
|
||||
"/api/pleroma/change_password?#{
|
||||
URI.encode_query(%{
|
||||
password: "hi",
|
||||
new_password: "newpass",
|
||||
new_password_confirmation: "newpass"
|
||||
})
|
||||
}"
|
||||
)
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/pleroma/change_password", %{
|
||||
"password" => "hi",
|
||||
"new_password" => "newpass",
|
||||
"new_password_confirmation" => "newpass"
|
||||
})
|
||||
|
||||
assert json_response_and_validate_schema(conn, 403) == %{
|
||||
"error" => "Insufficient permissions: write:accounts."
|
||||
|
|
@ -373,16 +361,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
|
||||
test "with proper permissions and invalid password", %{conn: conn} do
|
||||
conn =
|
||||
post(
|
||||
conn,
|
||||
"/api/pleroma/change_password?#{
|
||||
URI.encode_query(%{
|
||||
password: "hi",
|
||||
new_password: "newpass",
|
||||
new_password_confirmation: "newpass"
|
||||
})
|
||||
}"
|
||||
)
|
||||
conn
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/pleroma/change_password", %{
|
||||
"password" => "hi",
|
||||
"new_password" => "newpass",
|
||||
"new_password_confirmation" => "newpass"
|
||||
})
|
||||
|
||||
assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."}
|
||||
end
|
||||
|
|
@ -392,16 +377,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
conn: conn
|
||||
} do
|
||||
conn =
|
||||
post(
|
||||
conn,
|
||||
"/api/pleroma/change_password?#{
|
||||
URI.encode_query(%{
|
||||
password: "test",
|
||||
new_password: "newpass",
|
||||
new_password_confirmation: "notnewpass"
|
||||
})
|
||||
}"
|
||||
)
|
||||
conn
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/pleroma/change_password", %{
|
||||
"password" => "test",
|
||||
"new_password" => "newpass",
|
||||
"new_password_confirmation" => "notnewpass"
|
||||
})
|
||||
|
||||
assert json_response_and_validate_schema(conn, 200) == %{
|
||||
"error" => "New password does not match confirmation."
|
||||
|
|
@ -412,12 +394,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
conn: conn
|
||||
} do
|
||||
conn =
|
||||
post(
|
||||
conn,
|
||||
"/api/pleroma/change_password?#{
|
||||
URI.encode_query(%{password: "test", new_password: "", new_password_confirmation: ""})
|
||||
}"
|
||||
)
|
||||
conn
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post("/api/pleroma/change_password", %{
|
||||
password: "test",
|
||||
new_password: "",
|
||||
new_password_confirmation: ""
|
||||
})
|
||||
|
||||
assert json_response_and_validate_schema(conn, 200) == %{
|
||||
"error" => "New password can't be blank."
|
||||
|
|
@ -429,15 +412,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
user: user
|
||||
} do
|
||||
conn =
|
||||
post(
|
||||
conn,
|
||||
"/api/pleroma/change_password?#{
|
||||
URI.encode_query(%{
|
||||
password: "test",
|
||||
new_password: "newpass",
|
||||
new_password_confirmation: "newpass"
|
||||
})
|
||||
}"
|
||||
conn
|
||||
|> put_req_header("content-type", "multipart/form-data")
|
||||
|> post(
|
||||
"/api/pleroma/change_password",
|
||||
%{
|
||||
password: "test",
|
||||
new_password: "newpass",
|
||||
new_password_confirmation: "newpass"
|
||||
}
|
||||
)
|
||||
|
||||
assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
|
||||
|
|
|
|||
|
|
@ -142,6 +142,11 @@ defmodule Pleroma.Factory do
|
|||
}
|
||||
end
|
||||
|
||||
def followers_only_note_factory(attrs \\ %{}) do
|
||||
%Pleroma.Object{data: data} = note_factory(attrs)
|
||||
%Pleroma.Object{data: Map.merge(data, %{"to" => [data["actor"] <> "/followers"]})}
|
||||
end
|
||||
|
||||
def audio_factory(attrs \\ %{}) do
|
||||
text = sequence(:text, &"lain radio episode #{&1}")
|
||||
|
||||
|
|
@ -208,6 +213,38 @@ defmodule Pleroma.Factory do
|
|||
}
|
||||
end
|
||||
|
||||
def question_factory(attrs \\ %{}) do
|
||||
user = attrs[:user] || insert(:user)
|
||||
|
||||
data = %{
|
||||
"id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
|
||||
"type" => "Question",
|
||||
"actor" => user.ap_id,
|
||||
"attributedTo" => user.ap_id,
|
||||
"attachment" => [],
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"cc" => [user.follower_address],
|
||||
"context" => Pleroma.Web.ActivityPub.Utils.generate_context_id(),
|
||||
"closed" => DateTime.utc_now() |> DateTime.add(86_400) |> DateTime.to_iso8601(),
|
||||
"oneOf" => [
|
||||
%{
|
||||
"type" => "Note",
|
||||
"name" => "chocolate",
|
||||
"replies" => %{"totalItems" => 0, "type" => "Collection"}
|
||||
},
|
||||
%{
|
||||
"type" => "Note",
|
||||
"name" => "vanilla",
|
||||
"replies" => %{"totalItems" => 0, "type" => "Collection"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
%Pleroma.Object{
|
||||
data: merge_attributes(data, Map.get(attrs, :data, %{}))
|
||||
}
|
||||
end
|
||||
|
||||
def direct_note_activity_factory do
|
||||
dm = insert(:direct_note)
|
||||
|
||||
|
|
@ -267,6 +304,33 @@ defmodule Pleroma.Factory do
|
|||
|> Map.merge(attrs)
|
||||
end
|
||||
|
||||
def followers_only_note_activity_factory(attrs \\ %{}) do
|
||||
user = attrs[:user] || insert(:user)
|
||||
note = insert(:followers_only_note, user: user)
|
||||
|
||||
data_attrs = attrs[:data_attrs] || %{}
|
||||
attrs = Map.drop(attrs, [:user, :note, :data_attrs])
|
||||
|
||||
data =
|
||||
%{
|
||||
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
|
||||
"type" => "Create",
|
||||
"actor" => note.data["actor"],
|
||||
"to" => note.data["to"],
|
||||
"object" => note.data,
|
||||
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
|
||||
"context" => note.data["context"]
|
||||
}
|
||||
|> Map.merge(data_attrs)
|
||||
|
||||
%Pleroma.Activity{
|
||||
data: data,
|
||||
actor: data["actor"],
|
||||
recipients: data["to"]
|
||||
}
|
||||
|> Map.merge(attrs)
|
||||
end
|
||||
|
||||
def note_activity_factory(attrs \\ %{}) do
|
||||
user = attrs[:user] || insert(:user)
|
||||
note = attrs[:note] || insert(:note, user: user)
|
||||
|
|
@ -396,6 +460,33 @@ defmodule Pleroma.Factory do
|
|||
}
|
||||
end
|
||||
|
||||
def question_activity_factory(attrs \\ %{}) do
|
||||
user = attrs[:user] || insert(:user)
|
||||
question = attrs[:question] || insert(:question, user: user)
|
||||
|
||||
data_attrs = attrs[:data_attrs] || %{}
|
||||
attrs = Map.drop(attrs, [:user, :question, :data_attrs])
|
||||
|
||||
data =
|
||||
%{
|
||||
"id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
|
||||
"type" => "Create",
|
||||
"actor" => question.data["actor"],
|
||||
"to" => question.data["to"],
|
||||
"object" => question.data["id"],
|
||||
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
|
||||
"context" => question.data["context"]
|
||||
}
|
||||
|> Map.merge(data_attrs)
|
||||
|
||||
%Pleroma.Activity{
|
||||
data: data,
|
||||
actor: data["actor"],
|
||||
recipients: data["to"]
|
||||
}
|
||||
|> Map.merge(attrs)
|
||||
end
|
||||
|
||||
def oauth_app_factory do
|
||||
%Pleroma.Web.OAuth.App{
|
||||
client_name: sequence(:client_name, &"Some client #{&1}"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue