Compare commits
67 Commits
feature/sa
...
features/a
Author | SHA1 | Date | |
---|---|---|---|
|
1d49a440b2 | ||
|
84ec0fbeaa | ||
|
f9bafc17fb | ||
|
2d9f803dc6 | ||
|
773708cfe8 | ||
|
ba6049aa81 | ||
|
b901b73057 | ||
|
a2eacfc525 | ||
|
97eb160c3e | ||
|
edd2a38e53 | ||
|
7a9113deb1 | ||
|
61ba54897e | ||
|
b7bbf42acd | ||
|
21720db859 | ||
|
7afabe1cc6 | ||
|
6455b967ec | ||
|
3a7b54be4a | ||
|
3ca39ccf69 | ||
|
436fac3bac | ||
|
7247c29653 | ||
|
7c1243178b | ||
|
197cdebca9 | ||
|
8679a57a71 | ||
|
09dcb2b522 | ||
|
6c0ebc65fd | ||
|
438ad0d3f9 | ||
|
c64eae40a2 | ||
|
f4af74b0fc | ||
|
901204df22 | ||
|
6384d78035 | ||
|
ee5def34da | ||
|
c45b3bde94 | ||
|
8f730f70cb | ||
|
ad09bdb376 | ||
|
ee26f2c91b | ||
|
cd706c0335 | ||
|
b0926a71b2 | ||
|
f4028c908c | ||
|
9418424048 | ||
|
506bf16363 | ||
|
03030b47c2 | ||
|
47fc57bbcc | ||
|
7fdc3cde06 | ||
|
1f52246a02 | ||
|
c0489f9fac | ||
|
64002e92ad | ||
|
b674ba658b | ||
|
3c5a497b19 | ||
|
dfeb3862da | ||
|
e0c7d77197 | ||
|
27fe7b0274 | ||
|
dd947d9bc8 | ||
|
4ba0beb60c | ||
|
647087d7fd | ||
|
5f5dc24027 | ||
|
44ede0657f | ||
|
5c5571c668 | ||
|
69ebfb29fb | ||
|
85d71d4f1d | ||
|
62bf6d67e3 | ||
|
70f1496eb8 | ||
|
0b1c05ca1e | ||
|
6a6e42c9bf | ||
|
cbd1a10c16 | ||
|
0114754db2 | ||
|
1f093cb216 | ||
|
9bc1e79c56 |
@ -7,18 +7,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
## Unreleased
|
||||
|
||||
### Changed
|
||||
- MastodonAPI: Allow to pass arbitrary URLs when creating a status
|
||||
|
||||
### Added
|
||||
|
||||
### Fixed
|
||||
- Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies
|
||||
|
||||
### Removed
|
||||
|
||||
## Unreleased-patch
|
||||
- Mastodon API: Activity Search fallbacks on status fetching after a DB Timeout/Error
|
||||
|
||||
## 2.4.0 - 2021-08-xx
|
||||
|
||||
### 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 +40,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
|
||||
|
@ -560,6 +560,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"}
|
||||
]
|
||||
},
|
||||
%{
|
||||
|
@ -62,6 +62,7 @@ if File.exists?("./config/dev.secret.exs") do
|
||||
import_config "dev.secret.exs"
|
||||
else
|
||||
IO.puts(
|
||||
:stderr,
|
||||
"!!! RUNNING IN LOCALHOST DEV MODE! !!!\nFEDERATION WON'T WORK UNTIL YOU CONFIGURE A dev.secret.exs"
|
||||
)
|
||||
end
|
||||
|
@ -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).
|
@ -26,6 +26,7 @@ defmodule Pleroma.Activity.Search do
|
||||
:plain
|
||||
end
|
||||
|
||||
try do
|
||||
Activity
|
||||
|> Activity.with_preloaded_object()
|
||||
|> Activity.restrict_deactivated_users()
|
||||
@ -39,6 +40,9 @@ defmodule Pleroma.Activity.Search do
|
||||
:offset
|
||||
)
|
||||
|> maybe_fetch(user, search_query)
|
||||
rescue
|
||||
_ -> maybe_fetch([], user, search_query)
|
||||
end
|
||||
end
|
||||
|
||||
def maybe_restrict_author(query, %User{} = author) do
|
||||
|
@ -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] || %{}
|
||||
|
@ -15,6 +15,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
alias Pleroma.Web.CommonAPI.ActivityDraft
|
||||
|
||||
require Pleroma.Constants
|
||||
|
||||
@ -125,6 +126,37 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
||||
|> Pleroma.Maps.put_if_present("context", context), []}
|
||||
end
|
||||
|
||||
@spec note(ActivityDraft.t()) :: {:ok, map(), keyword()}
|
||||
def note(%ActivityDraft{} = draft) do
|
||||
data =
|
||||
%{
|
||||
"type" => "Note",
|
||||
"to" => draft.to,
|
||||
"cc" => draft.cc,
|
||||
"content" => draft.content_html,
|
||||
"summary" => draft.summary,
|
||||
"sensitive" => draft.sensitive,
|
||||
"context" => draft.context,
|
||||
"attachment" => draft.attachments,
|
||||
"actor" => draft.user.ap_id,
|
||||
"tag" => Keyword.values(draft.tags) |> Enum.uniq()
|
||||
}
|
||||
|> add_in_reply_to(draft.in_reply_to)
|
||||
|> Map.merge(draft.extra)
|
||||
|
||||
{:ok, data, []}
|
||||
end
|
||||
|
||||
defp add_in_reply_to(object, nil), do: object
|
||||
|
||||
defp add_in_reply_to(object, in_reply_to) do
|
||||
with %Object{} = in_reply_to_object <- Object.normalize(in_reply_to, fetch: false) do
|
||||
Map.put(object, "inReplyTo", in_reply_to_object.data["id"])
|
||||
else
|
||||
_ -> object
|
||||
end
|
||||
end
|
||||
|
||||
def chat_message(actor, recipient, content, opts \\ []) do
|
||||
basic = %{
|
||||
"id" => Utils.generate_object_id(),
|
||||
|
@ -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: [
|
||||
children:
|
||||
[
|
||||
%{
|
||||
key: :media_removal,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to strip media attachments from",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
description:
|
||||
"List of instances to strip media attachments from and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
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"]
|
||||
description:
|
||||
"List of instances to tag all media as NSFW (sensitive) from and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
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"]
|
||||
"List of instances to remove from the Federated (aka The Whole Known Network) Timeline and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :reject,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to reject activities from (except deletes)",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
description:
|
||||
"List of instances to reject activities from (except deletes) and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :accept,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to only accept activities from (except deletes)",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
description:
|
||||
"List of instances to only accept activities from (except deletes) and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :followers_only,
|
||||
type: {:list, :string},
|
||||
description: "Force posts from the given instances to be visible by followers only",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
description:
|
||||
"Force posts from the given instances to be visible by followers only and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :report_removal,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to reject reports from",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
description: "List of instances to reject reports from and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :avatar_removal,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to strip avatars from",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
description: "List of instances to strip avatars from and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :banner_removal,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to strip banners from",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
description: "List of instances to strip banners from and the reason for doing so"
|
||||
},
|
||||
%{
|
||||
key: :reject_deletes,
|
||||
type: {:list, :string},
|
||||
description: "List of instances to reject deletions from",
|
||||
suggestions: ["example.com", "*.example.com"]
|
||||
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
|
||||
|
@ -93,6 +93,51 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
|
||||
def filter(message), do: {:ok, message}
|
||||
|
||||
@impl true
|
||||
@spec config_description :: %{
|
||||
children: [
|
||||
%{
|
||||
description: <<_::272, _::_*256>>,
|
||||
key: :hosts | :rejected_shortcodes | :size_limit,
|
||||
suggestions: [any(), ...],
|
||||
type: {:list, :string} | {:list, :string} | :integer
|
||||
},
|
||||
...
|
||||
],
|
||||
description: <<_::448>>,
|
||||
key: :mrf_steal_emoji,
|
||||
label: <<_::80>>,
|
||||
related_policy: <<_::352>>
|
||||
}
|
||||
def config_description do
|
||||
%{
|
||||
key: :mrf_steal_emoji,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy",
|
||||
label: "MRF Emojis",
|
||||
description: "Steals emojis from selected instances when it sees them.",
|
||||
children: [
|
||||
%{
|
||||
key: :hosts,
|
||||
type: {:list, :string},
|
||||
description: "List of hosts to steal emojis from",
|
||||
suggestions: [""]
|
||||
},
|
||||
%{
|
||||
key: :rejected_shortcodes,
|
||||
type: {:list, :string},
|
||||
description: "Regex-list of shortcodes to reject",
|
||||
suggestions: [""]
|
||||
},
|
||||
%{
|
||||
key: :size_limit,
|
||||
type: :integer,
|
||||
description: "File size limit (in bytes), checked before an emoji is saved to the disk",
|
||||
suggestions: ["100000"]
|
||||
}
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def describe do
|
||||
{:ok, %{}}
|
||||
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
|
||||
|
||||
|
@ -35,6 +35,12 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do
|
||||
end
|
||||
|
||||
defp installed do
|
||||
File.ls!(Pleroma.Frontend.dir())
|
||||
frontend_directory = Pleroma.Frontend.dir()
|
||||
|
||||
if File.exists?(frontend_directory) do
|
||||
File.ls!(frontend_directory)
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -13,7 +13,9 @@ defmodule Pleroma.Web.AdminAPI.Report do
|
||||
account = User.get_cached_by_ap_id(account_ap_id)
|
||||
|
||||
statuses =
|
||||
Enum.map(status_ap_ids, fn
|
||||
status_ap_ids
|
||||
|> Enum.reject(&is_nil(&1))
|
||||
|> Enum.map(fn
|
||||
act when is_map(act) -> Activity.get_by_ap_id_with_object(act["id"])
|
||||
act when is_binary(act) -> Activity.get_by_ap_id_with_object(act)
|
||||
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.
|
||||
|
@ -453,7 +453,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
|
||||
nullable: true,
|
||||
type: :array,
|
||||
items: %Schema{type: :string},
|
||||
description: "Array of Attachment ids to be attached as media."
|
||||
description: "Array of Attachment ids or URLs to be attached as media."
|
||||
},
|
||||
poll: poll_params(),
|
||||
in_reply_to_id: %Schema{
|
||||
|
@ -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"],
|
||||
|
@ -6,6 +6,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Web.ActivityPub.Builder
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.CommonAPI.Utils
|
||||
|
||||
@ -213,8 +214,10 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
|
||||
|
||||
emoji = Map.merge(emoji, summary_emoji)
|
||||
|
||||
{:ok, note_data, _meta} = Builder.note(draft)
|
||||
|
||||
object =
|
||||
Utils.make_note_data(draft)
|
||||
note_data
|
||||
|> Map.put("emoji", emoji)
|
||||
|> Map.put("source", draft.status)
|
||||
|> Map.put("generator", draft.params[:generator])
|
||||
|
@ -23,6 +23,19 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
||||
require Logger
|
||||
require Pleroma.Constants
|
||||
|
||||
defp raw_url_to_attachment(url, desc \\ nil) do
|
||||
%{
|
||||
"type" => "Document",
|
||||
"name" => desc,
|
||||
"url" => [
|
||||
%{
|
||||
"type" => "Link",
|
||||
"href" => url
|
||||
}
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
def attachments_from_ids(%{media_ids: ids, descriptions: desc}) do
|
||||
attachments_from_ids_descs(ids, desc)
|
||||
end
|
||||
@ -36,7 +49,11 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
||||
def attachments_from_ids_no_descs([]), do: []
|
||||
|
||||
def attachments_from_ids_no_descs(ids) do
|
||||
Enum.map(ids, fn media_id ->
|
||||
Enum.map(ids, fn
|
||||
"http" <> _ = id ->
|
||||
raw_url_to_attachment(id)
|
||||
|
||||
media_id ->
|
||||
case Repo.get(Object, media_id) do
|
||||
%Object{data: data} -> data
|
||||
_ -> nil
|
||||
@ -50,7 +67,11 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
||||
def attachments_from_ids_descs(ids, descs_str) do
|
||||
{_, descs} = Jason.decode(descs_str)
|
||||
|
||||
Enum.map(ids, fn media_id ->
|
||||
Enum.map(ids, fn
|
||||
"http" <> _ = media_id ->
|
||||
raw_url_to_attachment(media_id, descs[media_id])
|
||||
|
||||
media_id ->
|
||||
with %Object{data: data} <- Repo.get(Object, media_id) do
|
||||
Map.put(data, "name", descs[media_id])
|
||||
end
|
||||
@ -291,33 +312,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
||||
|> Formatter.html_escape("text/html")
|
||||
end
|
||||
|
||||
def make_note_data(%ActivityDraft{} = draft) do
|
||||
%{
|
||||
"type" => "Note",
|
||||
"to" => draft.to,
|
||||
"cc" => draft.cc,
|
||||
"content" => draft.content_html,
|
||||
"summary" => draft.summary,
|
||||
"sensitive" => draft.sensitive,
|
||||
"context" => draft.context,
|
||||
"attachment" => draft.attachments,
|
||||
"actor" => draft.user.ap_id,
|
||||
"tag" => Keyword.values(draft.tags) |> Enum.uniq()
|
||||
}
|
||||
|> add_in_reply_to(draft.in_reply_to)
|
||||
|> Map.merge(draft.extra)
|
||||
end
|
||||
|
||||
defp add_in_reply_to(object, nil), do: object
|
||||
|
||||
defp add_in_reply_to(object, in_reply_to) do
|
||||
with %Object{} = in_reply_to_object <- Object.normalize(in_reply_to, fetch: false) do
|
||||
Map.put(object, "inReplyTo", in_reply_to_object.data["id"])
|
||||
else
|
||||
_ -> object
|
||||
end
|
||||
end
|
||||
|
||||
def format_naive_asctime(date) do
|
||||
date |> DateTime.from_naive!("Etc/UTC") |> format_asctime
|
||||
end
|
||||
@ -412,19 +406,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)
|
||||
|
@ -65,10 +65,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||
|
||||
defp get_context_id(_), do: nil
|
||||
|
||||
defp reblogged?(activity, user) do
|
||||
object = Object.normalize(activity, fetch: false) || %{}
|
||||
present?(user && user.ap_id in (object.data["announcements"] || []))
|
||||
# Check if the user reblogged this status
|
||||
defp reblogged?(activity, %User{ap_id: ap_id}) do
|
||||
with %Object{data: %{"announcements" => announcements}} when is_list(announcements) <-
|
||||
Object.normalize(activity, fetch: false) do
|
||||
ap_id in announcements
|
||||
else
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
|
||||
# False if the user is logged out
|
||||
defp reblogged?(_activity, _user), do: false
|
||||
|
||||
def render("index.json", opts) do
|
||||
reading_user = opts[:for]
|
||||
|
23
lib/pleroma/web/plugs/user_is_staff_plug.ex
Normal file
23
lib/pleroma/web/plugs/user_is_staff_plug.ex
Normal file
@ -0,0 +1,23 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.Plugs.UserIsStaffPlug do
|
||||
import Pleroma.Web.TranslationHelpers
|
||||
import Plug.Conn
|
||||
|
||||
alias Pleroma.User
|
||||
|
||||
def init(options) do
|
||||
options
|
||||
end
|
||||
|
||||
def call(%{assigns: %{user: %User{is_admin: true}}} = conn, _), do: conn
|
||||
def call(%{assigns: %{user: %User{is_moderator: true}}} = conn, _), do: conn
|
||||
|
||||
def call(conn, _) do
|
||||
conn
|
||||
|> render_error(:forbidden, "User is not a staff member.")
|
||||
|> halt()
|
||||
end
|
||||
end
|
@ -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)
|
||||
|
@ -96,10 +96,14 @@ defmodule Pleroma.Web.Router do
|
||||
plug(Pleroma.Web.Plugs.AdminSecretAuthenticationPlug)
|
||||
plug(:after_auth)
|
||||
plug(Pleroma.Web.Plugs.EnsureAuthenticatedPlug)
|
||||
plug(Pleroma.Web.Plugs.UserIsAdminPlug)
|
||||
plug(Pleroma.Web.Plugs.UserIsStaffPlug)
|
||||
plug(Pleroma.Web.Plugs.IdempotencyPlug)
|
||||
end
|
||||
|
||||
pipeline :require_admin do
|
||||
plug(Pleroma.Web.Plugs.UserIsAdminPlug)
|
||||
end
|
||||
|
||||
pipeline :mastodon_html do
|
||||
plug(:browser)
|
||||
plug(:authenticate)
|
||||
@ -160,7 +164,7 @@ defmodule Pleroma.Web.Router do
|
||||
end
|
||||
|
||||
scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do
|
||||
pipe_through(:admin_api)
|
||||
pipe_through([:admin_api, :require_admin])
|
||||
|
||||
put("/users/disable_mfa", AdminAPIController, :disable_mfa)
|
||||
put("/users/tag", AdminAPIController, :tag_users)
|
||||
@ -265,7 +269,7 @@ defmodule Pleroma.Web.Router do
|
||||
|
||||
scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do
|
||||
scope "/pack" do
|
||||
pipe_through(:admin_api)
|
||||
pipe_through([:admin_api, :require_admin])
|
||||
|
||||
post("/", EmojiPackController, :create)
|
||||
patch("/", EmojiPackController, :update)
|
||||
@ -280,7 +284,7 @@ defmodule Pleroma.Web.Router do
|
||||
|
||||
# Modifying packs
|
||||
scope "/packs" do
|
||||
pipe_through(:admin_api)
|
||||
pipe_through([:admin_api, :require_admin])
|
||||
|
||||
get("/import", EmojiPackController, :import_from_filesystem)
|
||||
get("/remote", EmojiPackController, :remote)
|
||||
|
@ -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
|
2
mix.exs
2
mix.exs
@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
|
||||
def project do
|
||||
[
|
||||
app: :pleroma,
|
||||
version: version("2.4.0"),
|
||||
version: version("2.4.50"),
|
||||
elixir: "~> 1.9",
|
||||
elixirc_paths: elixirc_paths(Mix.env()),
|
||||
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
||||
|
@ -3,8 +3,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-05-13 16:37+0000\n"
|
||||
"PO-Revision-Date: 2020-07-09 14:40+0000\n"
|
||||
"Last-Translator: Ben Is <srsbzns@cock.li>\n"
|
||||
"PO-Revision-Date: 2021-08-13 15:42+0000\n"
|
||||
"Last-Translator: marcin mikołajczak <me@mkljczk.pl>\n"
|
||||
"Language-Team: Polish <https://translate.pleroma.social/projects/pleroma/"
|
||||
"pleroma/pl/>\n"
|
||||
"Language: pl\n"
|
||||
@ -13,7 +13,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 4.0.4\n"
|
||||
"X-Generator: Weblate 4.6.2\n"
|
||||
|
||||
## This file is a PO Template file.
|
||||
##
|
||||
@ -68,49 +68,49 @@ msgstr[2] "powinno mieć %{count} znaków"
|
||||
|
||||
msgid "should have %{count} item(s)"
|
||||
msgid_plural "should have %{count} item(s)"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
msgstr[0] "powinno zawierać %{count} element"
|
||||
msgstr[1] "powinno zawierać %{count} elementy"
|
||||
msgstr[2] "powinno zawierać %{count} elementów"
|
||||
|
||||
msgid "should be at least %{count} character(s)"
|
||||
msgid_plural "should be at least %{count} character(s)"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
msgstr[0] "powinno zawierać przynajmniej %{count} znak"
|
||||
msgstr[1] "powinno zawierać przynajmniej %{count} znaki"
|
||||
msgstr[2] "powinno zawierać przynajmniej %{count} znaków"
|
||||
|
||||
msgid "should have at least %{count} item(s)"
|
||||
msgid_plural "should have at least %{count} item(s)"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
msgstr[0] "powinno zawierać przynajmniej %{count} element"
|
||||
msgstr[1] "powinno zawierać przynajmniej %{count} elementy"
|
||||
msgstr[2] "powinno zawierać przynajmniej %{count} elementów"
|
||||
|
||||
msgid "should be at most %{count} character(s)"
|
||||
msgid_plural "should be at most %{count} character(s)"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
msgstr[0] "powinno zawierać najwyżej %{count} znak"
|
||||
msgstr[1] "powinno zawierać najwyżej %{count} znaki"
|
||||
msgstr[2] "powinno zawierać najwyżej %{count} znaków"
|
||||
|
||||
msgid "should have at most %{count} item(s)"
|
||||
msgid_plural "should have at most %{count} item(s)"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
msgstr[0] "powinno zawierać najwyżej %{count} element"
|
||||
msgstr[1] "powinno zawierać najwyżej %{count} elementy"
|
||||
msgstr[2] "powinno zawierać najwyżej %{count} elementów"
|
||||
|
||||
## From Ecto.Changeset.validate_number/3
|
||||
msgid "must be less than %{number}"
|
||||
msgstr ""
|
||||
msgstr "musi wynosić mniej niż %{number}"
|
||||
|
||||
msgid "must be greater than %{number}"
|
||||
msgstr ""
|
||||
msgstr "musi wynosić więcej niż %{number}"
|
||||
|
||||
msgid "must be less than or equal to %{number}"
|
||||
msgstr ""
|
||||
msgstr "musi być mniejsze lub równe %{number}"
|
||||
|
||||
msgid "must be greater than or equal to %{number}"
|
||||
msgstr ""
|
||||
msgstr "musi być większe lub równe %{number}"
|
||||
|
||||
msgid "must be equal to %{number}"
|
||||
msgstr ""
|
||||
msgstr "musi być równe %{number}"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:421
|
||||
#, elixir-format
|
||||
@ -152,7 +152,7 @@ msgstr "Nie znaleziono użytkownika"
|
||||
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:114
|
||||
#, elixir-format
|
||||
msgid "Can't get favorites"
|
||||
msgstr ""
|
||||
msgstr "Nie można uzyskać ulubionych"
|
||||
|
||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:437
|
||||
#, elixir-format
|
||||
@ -172,7 +172,7 @@ msgstr "Komentarz może mieć co najwyżej %{max_size} znaków"
|
||||
#: lib/pleroma/config/config_db.ex:222
|
||||
#, elixir-format
|
||||
msgid "Config with params %{params} not found"
|
||||
msgstr ""
|
||||
msgstr "Nie znaleziono konfiguracji z parametrami %{params}"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:95
|
||||
#, elixir-format
|
||||
@ -213,38 +213,38 @@ msgstr "Nie udało się cofnąć powtórzenia"
|
||||
#: lib/pleroma/web/common_api/common_api.ex:437
|
||||
#, elixir-format
|
||||
msgid "Could not update state"
|
||||
msgstr ""
|
||||
msgstr "Nie można zaktualizować stanu"
|
||||
|
||||
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:202
|
||||
#, elixir-format
|
||||
msgid "Error."
|
||||
msgstr ""
|
||||
msgstr "Błąd."
|
||||
|
||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:106
|
||||
#, elixir-format
|
||||
msgid "Invalid CAPTCHA"
|
||||
msgstr ""
|
||||
msgstr "Niewłaściwa CAPTCHA"
|
||||
|
||||
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:117
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:569
|
||||
#, elixir-format
|
||||
msgid "Invalid credentials"
|
||||
msgstr ""
|
||||
msgstr "Nieprawidłowe dane uwierzytelniania"
|
||||
|
||||
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
|
||||
#, elixir-format
|
||||
msgid "Invalid credentials."
|
||||
msgstr ""
|
||||
msgstr "Nieprawidłowe dane uwierzytelniania."
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:265
|
||||
#, elixir-format
|
||||
msgid "Invalid indices"
|
||||
msgstr ""
|
||||
msgstr "Nieprawidłowe indeksy"
|
||||
|
||||
#: lib/pleroma/web/admin_api/admin_api_controller.ex:1147
|
||||
#, elixir-format
|
||||
msgid "Invalid parameters"
|
||||
msgstr ""
|
||||
msgstr "Nieprawidłowe parametry"
|
||||
|
||||
#: lib/pleroma/web/common_api/utils.ex:411
|
||||
#, elixir-format
|
||||
@ -307,7 +307,7 @@ msgstr "Coś się zepsuło"
|
||||
#: lib/pleroma/web/common_api/activity_draft.ex:107
|
||||
#, elixir-format
|
||||
msgid "The message visibility must be direct"
|
||||
msgstr ""
|
||||
msgstr "Widoczność wiadomości musi być „Bezpośrednia”"
|
||||
|
||||
#: lib/pleroma/web/common_api/utils.ex:566
|
||||
#, elixir-format
|
||||
@ -317,17 +317,17 @@ msgstr "Ten status przekracza limit znaków"
|
||||
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
|
||||
#, elixir-format
|
||||
msgid "This resource requires authentication."
|
||||
msgstr ""
|
||||
msgstr "Ten zasób wymaga uwierzytelnienia."
|
||||
|
||||
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
|
||||
#, elixir-format
|
||||
msgid "Throttled"
|
||||
msgstr ""
|
||||
msgstr "Ograniczono"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:266
|
||||
#, elixir-format
|
||||
msgid "Too many choices"
|
||||
msgstr ""
|
||||
msgstr "Zbyt wiele wyborów"
|
||||
|
||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:442
|
||||
#, elixir-format
|
||||
@ -349,17 +349,18 @@ msgstr "Twoje konto jest obecnie nieaktywne"
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:332
|
||||
#, elixir-format
|
||||
msgid "Your login is missing a confirmed e-mail address"
|
||||
msgstr ""
|
||||
msgstr "Twój adres e-mail nie został potwierdzony"
|
||||
|
||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:389
|
||||
#, elixir-format
|
||||
msgid "can't read inbox of %{nickname} as %{as_nickname}"
|
||||
msgstr ""
|
||||
msgstr "Nie można odczytać skrzynki odbiorczej %{nickname} jako %{as_nickname}"
|
||||
|
||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:472
|
||||
#, elixir-format
|
||||
msgid "can't update outbox of %{nickname} as %{as_nickname}"
|
||||
msgstr ""
|
||||
"Nie można zaktualizować skrzynki nadawczcej %{nickname} jako %{as_nickname}"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:388
|
||||
#, elixir-format
|
||||
@ -405,12 +406,12 @@ msgstr "Nie udało się"
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:411
|
||||
#, elixir-format
|
||||
msgid "Failed to authenticate: %{message}."
|
||||
msgstr ""
|
||||
msgstr "Nie udało się uwierzytelnić: %{message}."
|
||||
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:442
|
||||
#, elixir-format
|
||||
msgid "Failed to set up user account."
|
||||
msgstr ""
|
||||
msgstr "Nie udało się skonfigurować konta użytkownika."
|
||||
|
||||
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
|
||||
#, elixir-format
|
||||
@ -431,7 +432,7 @@ msgstr "Nieprawidłowa nazwa użytkownika lub hasło"
|
||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:118
|
||||
#, elixir-format
|
||||
msgid "Invalid answer data"
|
||||
msgstr ""
|
||||
msgstr "Nieprawidłowe dane odpowiedzi"
|
||||
|
||||
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:128
|
||||
#, elixir-format
|
||||
@ -441,7 +442,7 @@ msgstr "Nieobsługiwana wersja schematu Nodeinfo"
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:169
|
||||
#, elixir-format
|
||||
msgid "This action is outside the authorized scopes"
|
||||
msgstr ""
|
||||
msgstr "Ta akcja wykracza poza dozwolone zakresy"
|
||||
|
||||
#: lib/pleroma/web/oauth/fallback_controller.ex:14
|
||||
#, elixir-format
|
||||
@ -477,12 +478,12 @@ msgstr "Błąd CAPTCHA"
|
||||
#: lib/pleroma/web/common_api/common_api.ex:200
|
||||
#, elixir-format
|
||||
msgid "Could not add reaction emoji"
|
||||
msgstr ""
|
||||
msgstr "Nie można dodać reakcji emoji"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:211
|
||||
#, elixir-format
|
||||
msgid "Could not remove reaction emoji"
|
||||
msgstr ""
|
||||
msgstr "Nie można usunąć reakcji emoji"
|
||||
|
||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:129
|
||||
#, elixir-format
|
||||
@ -535,6 +536,8 @@ msgstr "Wymagany reset hasła"
|
||||
#, elixir-format
|
||||
msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
|
||||
msgstr ""
|
||||
"Naruszenie bezpieczeństwa: sprawdzanie zakresów OAuth nie zostało ani "
|
||||
"wykonane, ani celowo pominięte."
|
||||
|
||||
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
|
||||
#, elixir-format
|
||||
@ -569,7 +572,7 @@ msgstr "Nieoczekiwany błąd podczas zmieniania metadanych paczki."
|
||||
#: lib/pleroma/plugs/user_is_admin_plug.ex:21
|
||||
#, elixir-format
|
||||
msgid "User is not an admin."
|
||||
msgstr ""
|
||||
msgstr "Użytkownik nie jest administratorem."
|
||||
|
||||
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
|
||||
#, elixir-format
|
||||
|
@ -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)
|
||||
|
48
test/pleroma/web/activity_pub/builder_test.exs
Normal file
48
test/pleroma/web/activity_pub/builder_test.exs
Normal file
@ -0,0 +1,48 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.BuilderTest do
|
||||
alias Pleroma.Web.ActivityPub.Builder
|
||||
alias Pleroma.Web.CommonAPI.ActivityDraft
|
||||
use Pleroma.DataCase
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
describe "note/1" do
|
||||
test "returns note data" do
|
||||
user = insert(:user)
|
||||
note = insert(:note)
|
||||
user2 = insert(:user)
|
||||
user3 = insert(:user)
|
||||
|
||||
draft = %ActivityDraft{
|
||||
user: user,
|
||||
to: [user2.ap_id],
|
||||
context: "2hu",
|
||||
content_html: "<h1>This is :moominmamma: note</h1>",
|
||||
in_reply_to: note.id,
|
||||
tags: [name: "jimm"],
|
||||
summary: "test summary",
|
||||
cc: [user3.ap_id],
|
||||
extra: %{"custom_tag" => "test"}
|
||||
}
|
||||
|
||||
expected = %{
|
||||
"actor" => user.ap_id,
|
||||
"attachment" => [],
|
||||
"cc" => [user3.ap_id],
|
||||
"content" => "<h1>This is :moominmamma: note</h1>",
|
||||
"context" => "2hu",
|
||||
"sensitive" => false,
|
||||
"summary" => "test summary",
|
||||
"tag" => ["jimm"],
|
||||
"to" => [user2.ap_id],
|
||||
"type" => "Note",
|
||||
"custom_tag" => "test"
|
||||
}
|
||||
|
||||
assert {:ok, ^expected, []} = Builder.note(draft)
|
||||
end
|
||||
end
|
||||
end
|
@ -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)
|
||||
|
@ -42,6 +42,20 @@ defmodule Pleroma.Web.AdminAPI.FrontendControllerTest do
|
||||
|
||||
refute Enum.any?(response, fn frontend -> frontend["installed"] == true end)
|
||||
end
|
||||
|
||||
test "it lists available frontends when no frontend folder was created yet", %{conn: conn} do
|
||||
File.rm_rf(@dir)
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/api/pleroma/admin/frontends")
|
||||
|> json_response_and_validate_schema(:ok)
|
||||
|
||||
assert Enum.map(response, & &1["name"]) ==
|
||||
Enum.map(Config.get([:frontends, :available]), fn {_, map} -> map["name"] end)
|
||||
|
||||
refute Enum.any?(response, fn frontend -> frontend["installed"] == true end)
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST /api/pleroma/admin/frontends/install" do
|
||||
|
@ -305,7 +305,7 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
|
||||
|> get("/api/pleroma/admin/reports")
|
||||
|
||||
assert json_response(conn, :forbidden) ==
|
||||
%{"error" => "User is not an admin."}
|
||||
%{"error" => "User is not a staff member."}
|
||||
end
|
||||
|
||||
test "returns 403 when requested by anonymous" do
|
||||
|
@ -655,6 +655,16 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
|
||||
assert Utils.attachments_from_ids(%{media_ids: ["#{object.id}"]}) == [object.data]
|
||||
end
|
||||
|
||||
test "returns attachment object with raw URL" do
|
||||
assert Utils.attachments_from_ids(%{media_ids: ["https://example.org/corndog.jpeg"]}) == [
|
||||
%{
|
||||
"name" => nil,
|
||||
"type" => "Document",
|
||||
"url" => [%{"href" => "https://example.org/corndog.jpeg", "type" => "Link"}]
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
test "returns [] when not pass media_ids" do
|
||||
assert Utils.attachments_from_ids(%{}) == []
|
||||
end
|
||||
@ -681,41 +691,6 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
|
||||
end
|
||||
end
|
||||
|
||||
describe "make_note_data/1" do
|
||||
test "returns note data" do
|
||||
user = insert(:user)
|
||||
note = insert(:note)
|
||||
user2 = insert(:user)
|
||||
user3 = insert(:user)
|
||||
|
||||
draft = %ActivityDraft{
|
||||
user: user,
|
||||
to: [user2.ap_id],
|
||||
context: "2hu",
|
||||
content_html: "<h1>This is :moominmamma: note</h1>",
|
||||
in_reply_to: note.id,
|
||||
tags: [name: "jimm"],
|
||||
summary: "test summary",
|
||||
cc: [user3.ap_id],
|
||||
extra: %{"custom_tag" => "test"}
|
||||
}
|
||||
|
||||
assert Utils.make_note_data(draft) == %{
|
||||
"actor" => user.ap_id,
|
||||
"attachment" => [],
|
||||
"cc" => [user3.ap_id],
|
||||
"content" => "<h1>This is :moominmamma: note</h1>",
|
||||
"context" => "2hu",
|
||||
"sensitive" => false,
|
||||
"summary" => "test summary",
|
||||
"tag" => ["jimm"],
|
||||
"to" => [user2.ap_id],
|
||||
"type" => "Note",
|
||||
"custom_tag" => "test"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe "maybe_add_attachments/3" do
|
||||
test "returns parsed results when attachment_links is false" do
|
||||
assert Utils.maybe_add_attachments(
|
||||
|
@ -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
|
||||
|
||||
@ -181,6 +182,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
||||
assert json_response_and_validate_schema(conn, 200)
|
||||
end
|
||||
|
||||
test "posting an undefined status with arbitrary URL as attachment", %{conn: conn} do
|
||||
assert response =
|
||||
conn
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> post("/api/v1/statuses", %{
|
||||
"media_ids" => ["https://example.org/corndog.jpeg"]
|
||||
})
|
||||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert [%{"url" => "https://example.org/corndog.jpeg"}] = response["media_attachments"]
|
||||
end
|
||||
|
||||
test "replying to a status", %{user: user, conn: conn} do
|
||||
{:ok, replied_to} = CommonAPI.post(user, %{status: "cofe"})
|
||||
|
||||
@ -705,11 +718,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,27 +150,70 @@ 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])
|
||||
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)
|
||||
|
||||
assert response["metadata"]["federation"]["mrf_simple"] == simple_config
|
||||
assert response["metadata"]["federation"]["quarantined_instances"] == expected_config
|
||||
end
|
||||
|
||||
test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do
|
||||
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
|
||||
|
||||
describe "MRF SimplePolicy" do
|
||||
setup do
|
||||
clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
|
||||
clear_config([:mrf, :transparency], true)
|
||||
clear_config([:mrf, :transparency_exclusions], ["other.site"])
|
||||
end
|
||||
|
||||
simple_config = %{"reject" => ["example.com", "other.site"]}
|
||||
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"]}
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/nodeinfo/2.1.json")
|
||||
|> json_response(:ok)
|
||||
|
||||
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"]}
|
||||
@ -183,4 +226,51 @@ defmodule Pleroma.Web.NodeInfoTest do
|
||||
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
|
||||
|
47
test/pleroma/web/plugs/user_is_staff_plug_test.exs
Normal file
47
test/pleroma/web/plugs/user_is_staff_plug_test.exs
Normal file
@ -0,0 +1,47 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.Plugs.UserIsStaffPlugTest do
|
||||
use Pleroma.Web.ConnCase, async: true
|
||||
|
||||
alias Pleroma.Web.Plugs.UserIsStaffPlug
|
||||
import Pleroma.Factory
|
||||
|
||||
test "accepts a user that is an admin" do
|
||||
user = insert(:user, is_admin: true)
|
||||
|
||||
conn = assign(build_conn(), :user, user)
|
||||
|
||||
ret_conn = UserIsStaffPlug.call(conn, %{})
|
||||
|
||||
assert conn == ret_conn
|
||||
end
|
||||
|
||||
test "accepts a user that is a moderator" do
|
||||
user = insert(:user, is_moderator: true)
|
||||
|
||||
conn = assign(build_conn(), :user, user)
|
||||
|
||||
ret_conn = UserIsStaffPlug.call(conn, %{})
|
||||
|
||||
assert conn == ret_conn
|
||||
end
|
||||
|
||||
test "denies a user that isn't a staff member" do
|
||||
user = insert(:user)
|
||||
|
||||
conn =
|
||||
build_conn()
|
||||
|> assign(:user, user)
|
||||
|> UserIsStaffPlug.call(%{})
|
||||
|
||||
assert conn.status == 403
|
||||
end
|
||||
|
||||
test "denies when a user isn't set" do
|
||||
conn = UserIsStaffPlug.call(build_conn(), %{})
|
||||
|
||||
assert conn.status == 403
|
||||
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(%{
|
||||
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…
Reference in New Issue
Block a user