diff --git a/.gitignore b/.gitignore
index de23220784..8ba6813204 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,3 +61,6 @@ pleroma.iml
*~
*#
*.swp
+
+archive-*
+.gitlab-ci-local
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 21d7b22425..9e471eb38c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,4 +1,4 @@
-image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.13.4-otp-24
+image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.13.4-otp-25
variables: &global_variables
# Only used for the release
@@ -18,9 +18,7 @@ workflow:
- if: $CI_COMMIT_BRANCH
cache: &global_cache_policy
- key:
- files:
- - mix.lock
+ key: $CI_JOB_IMAGE-$CI_COMMIT_SHORT_SHA
paths:
- deps
- _build
@@ -72,7 +70,7 @@ check-changelog:
tags:
- amd64
-build-1.13.4:
+build-1.13.4-otp-25:
extends:
- .build_changes_policy
- .using-ci-base
@@ -80,13 +78,12 @@ build-1.13.4:
script:
- mix compile --force
-build-1.15.7-otp-25:
+build-1.15.8-otp-26:
extends:
- .build_changes_policy
- .using-ci-base
stage: build
- image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15-otp25
- allow_failure: true
+ image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15.8-otp-26
script:
- mix compile --force
@@ -121,7 +118,7 @@ benchmark:
- mix ecto.migrate
- mix pleroma.load_testing
-unit-testing-1.12.3:
+unit-testing-1.13.4-otp-25:
extends:
- .build_changes_policy
- .using-ci-base
@@ -136,7 +133,7 @@ unit-testing-1.12.3:
script: &testing_script
- mix ecto.create
- mix ecto.migrate
- - mix test --cover --preload-modules
+ - mix pleroma.test_runner --cover --preload-modules
coverage: '/^Line total: ([^ ]*%)$/'
artifacts:
reports:
@@ -144,34 +141,19 @@ unit-testing-1.12.3:
coverage_format: cobertura
path: coverage.xml
-unit-testing-1.15.7-otp-25:
+unit-testing-1.15.8-otp-26:
extends:
- .build_changes_policy
- .using-ci-base
stage: test
- image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15-otp25
- allow_failure: true
+ image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15.8-otp-26
cache: *testing_cache_policy
services: *testing_services
script: *testing_script
-unit-testing-1.12-erratic:
- extends:
- - .build_changes_policy
- - .using-ci-base
- stage: test
- retry: 2
- allow_failure: true
- cache: *testing_cache_policy
- services: *testing_services
- script:
- - mix ecto.create
- - mix ecto.migrate
- - mix test --only=erratic
-
-formatting-1.13:
+formatting-1.15:
extends: .build_changes_policy
- image: &formatting_elixir elixir:1.13-alpine
+ image: &formatting_elixir elixir:1.15-alpine
stage: lint
cache: *testing_cache_policy
before_script: ¤t_bfr_script
diff --git a/changelog.d/3280-fix-emoji-ids.fix b/changelog.d/3280-fix-emoji-ids.fix
new file mode 100644
index 0000000000..1bce5b653e
--- /dev/null
+++ b/changelog.d/3280-fix-emoji-ids.fix
@@ -0,0 +1 @@
+Fix Emoji object IDs not always being valid
diff --git a/changelog.d/adminfe-logger.change b/changelog.d/adminfe-logger.change
new file mode 100644
index 0000000000..e1a5fc4546
--- /dev/null
+++ b/changelog.d/adminfe-logger.change
@@ -0,0 +1 @@
+Elixir Logger configuration is now longer permitted through AdminFE and ConfigDB
diff --git a/changelog.d/akkoma-prune-options.add b/changelog.d/akkoma-prune-options.add
new file mode 100644
index 0000000000..6bc5e7f926
--- /dev/null
+++ b/changelog.d/akkoma-prune-options.add
@@ -0,0 +1 @@
+Add options to the mix prune_objects task
diff --git a/changelog.d/bandit_update_1.5.2.change b/changelog.d/bandit_update_1.5.2.change
new file mode 100644
index 0000000000..c4aae16367
--- /dev/null
+++ b/changelog.d/bandit_update_1.5.2.change
@@ -0,0 +1 @@
+Update Bandit to 1.5.2
diff --git a/changelog.d/ci-cache.skip b/changelog.d/ci-cache.skip
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/changelog.d/ci-erratic.skip b/changelog.d/ci-erratic.skip
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/changelog.d/ci-otp-update.skip b/changelog.d/ci-otp-update.skip
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/changelog.d/cleanup.skip b/changelog.d/cleanup.skip
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/changelog.d/cowboy-stream-chunked.fix b/changelog.d/cowboy-stream-chunked.fix
new file mode 100644
index 0000000000..07211bf181
--- /dev/null
+++ b/changelog.d/cowboy-stream-chunked.fix
@@ -0,0 +1 @@
+Restore Cowboy's ability to stream MediaProxy responses without Chunked encoding.
diff --git a/changelog.d/debug-logs.skip b/changelog.d/debug-logs.skip
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/changelog.d/deps-bump-2024-06-07.skip b/changelog.d/deps-bump-2024-06-07.skip
new file mode 100644
index 0000000000..4f377a4d75
--- /dev/null
+++ b/changelog.d/deps-bump-2024-06-07.skip
@@ -0,0 +1,2 @@
+Update dependencies held back due to old Elixir version
+
diff --git a/changelog.d/docs-netbsd-update.change b/changelog.d/docs-netbsd-update.change
new file mode 100644
index 0000000000..29599e8f28
--- /dev/null
+++ b/changelog.d/docs-netbsd-update.change
@@ -0,0 +1 @@
+Update and extend NetBSD installation docs
diff --git a/changelog.d/elixir-1.15.fix b/changelog.d/elixir-1.15.fix
new file mode 100644
index 0000000000..d446aaabce
--- /dev/null
+++ b/changelog.d/elixir-1.15.fix
@@ -0,0 +1 @@
+Elixir 1.15 compatibility
diff --git a/changelog.d/gun_pool4.fix b/changelog.d/gun_pool4.fix
new file mode 100644
index 0000000000..f68c1c9704
--- /dev/null
+++ b/changelog.d/gun_pool4.fix
@@ -0,0 +1 @@
+Gun Connection Pool was not retrying to acquire a connection if the pool was full and stale connections were reclaimed
diff --git a/changelog.d/ipfs-dialyzer.skip b/changelog.d/ipfs-dialyzer.skip
new file mode 100644
index 0000000000..b3e74cd19a
--- /dev/null
+++ b/changelog.d/ipfs-dialyzer.skip
@@ -0,0 +1 @@
+no comment
diff --git a/changelog.d/missing-fks.add b/changelog.d/missing-fks.add
new file mode 100644
index 0000000000..cf74de03bc
--- /dev/null
+++ b/changelog.d/missing-fks.add
@@ -0,0 +1 @@
+Add missing indexes on foreign key relationships
diff --git a/changelog.d/mix-indexer.add b/changelog.d/mix-indexer.add
new file mode 100644
index 0000000000..6effb959bd
--- /dev/null
+++ b/changelog.d/mix-indexer.add
@@ -0,0 +1 @@
+Permit passing --chunk and --step values to the Pleroma.Search.Indexer Mix task
diff --git a/changelog.d/mrf-nsfw-otp25.skip b/changelog.d/mrf-nsfw-otp25.skip
new file mode 100644
index 0000000000..e804f19a00
--- /dev/null
+++ b/changelog.d/mrf-nsfw-otp25.skip
@@ -0,0 +1 @@
+noop
diff --git a/changelog.d/notification-spex.skip b/changelog.d/notification-spex.skip
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/changelog.d/pinned-collection-fetch.security b/changelog.d/pinned-collection-fetch.security
new file mode 100644
index 0000000000..4e87469242
--- /dev/null
+++ b/changelog.d/pinned-collection-fetch.security
@@ -0,0 +1 @@
+Use proper workers for fetching pins instead of an ad-hoc task, fixing a potential fetch loop
diff --git a/changelog.d/rich_media_backfill.change b/changelog.d/rich_media_backfill.change
new file mode 100644
index 0000000000..d746ac8ce6
--- /dev/null
+++ b/changelog.d/rich_media_backfill.change
@@ -0,0 +1 @@
+Rich Media backfilling is now an Oban job
diff --git a/changelog.d/rich_media_config.skip b/changelog.d/rich_media_config.skip
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/changelog.d/spex-error-log.skip b/changelog.d/spex-error-log.skip
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/changelog.d/stream-end-poll.fix b/changelog.d/stream-end-poll.fix
new file mode 100644
index 0000000000..db513efdcd
--- /dev/null
+++ b/changelog.d/stream-end-poll.fix
@@ -0,0 +1 @@
+End of poll notifications were not streamed over websockets or web push
diff --git a/changelog.d/user-refresh-rework.skip b/changelog.d/user-refresh-rework.skip
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/changelog.d/user-refresh.change b/changelog.d/user-refresh.change
new file mode 100644
index 0000000000..b91169a9e8
--- /dev/null
+++ b/changelog.d/user-refresh.change
@@ -0,0 +1 @@
+User profile refreshes are now asynchronous
diff --git a/changelog.d/video-thumbs.fix b/changelog.d/video-thumbs.fix
new file mode 100644
index 0000000000..03e862f3db
--- /dev/null
+++ b/changelog.d/video-thumbs.fix
@@ -0,0 +1 @@
+Video thumbnails were not being generated due to a negative cache lookup logic error
diff --git a/changelog.d/web_push_actor_regression.skip b/changelog.d/web_push_actor_regression.skip
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/changelog.d/webpush-polls.change b/changelog.d/webpush-polls.change
new file mode 100644
index 0000000000..5607d6bfcb
--- /dev/null
+++ b/changelog.d/webpush-polls.change
@@ -0,0 +1 @@
+Render nice web push notifications for polls
diff --git a/ci/elixir-1.13/Dockerfile b/ci/elixir-1.13.4-otp-25/Dockerfile
similarity index 91%
rename from ci/elixir-1.13/Dockerfile
rename to ci/elixir-1.13.4-otp-25/Dockerfile
index b8bceb3d97..25a1639e89 100644
--- a/ci/elixir-1.13/Dockerfile
+++ b/ci/elixir-1.13.4-otp-25/Dockerfile
@@ -1,4 +1,4 @@
-FROM elixir:1.13.4-otp-24
+FROM elixir:1.13.4-otp-25
# Single RUN statement, otherwise intermediate images are created
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
diff --git a/ci/elixir-1.13/build_and_push.sh b/ci/elixir-1.13.4-otp-25/build_and_push.sh
similarity index 52%
rename from ci/elixir-1.13/build_and_push.sh
rename to ci/elixir-1.13.4-otp-25/build_and_push.sh
index 64e1856db1..b8ca1d24d7 100755
--- a/ci/elixir-1.13/build_and_push.sh
+++ b/ci/elixir-1.13.4-otp-25/build_and_push.sh
@@ -1 +1 @@
-docker buildx build --platform linux/amd64,linux/arm64 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.13.4-otp-24 --push .
+docker buildx build --platform linux/amd64,linux/arm64 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.13.4-otp-25 --push .
diff --git a/ci/elixir-1.15-otp25/build_and_push.sh b/ci/elixir-1.15-otp25/build_and_push.sh
deleted file mode 100755
index a28e0d33ce..0000000000
--- a/ci/elixir-1.15-otp25/build_and_push.sh
+++ /dev/null
@@ -1 +0,0 @@
-docker buildx build --platform linux/amd64,linux/arm64 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15-otp25 --push .
diff --git a/ci/elixir-1.15-otp25/Dockerfile b/ci/elixir-1.15.8-otp-26/Dockerfile
similarity index 91%
rename from ci/elixir-1.15-otp25/Dockerfile
rename to ci/elixir-1.15.8-otp-26/Dockerfile
index 3335c6e369..7142ace047 100644
--- a/ci/elixir-1.15-otp25/Dockerfile
+++ b/ci/elixir-1.15.8-otp-26/Dockerfile
@@ -1,4 +1,4 @@
-FROM elixir:1.15.7-otp-25
+FROM elixir:1.15.8-otp-26
# Single RUN statement, otherwise intermediate images are created
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
diff --git a/ci/elixir-1.15.8-otp-26/build_and_push.sh b/ci/elixir-1.15.8-otp-26/build_and_push.sh
new file mode 100755
index 0000000000..59bc634549
--- /dev/null
+++ b/ci/elixir-1.15.8-otp-26/build_and_push.sh
@@ -0,0 +1 @@
+docker buildx build --platform linux/amd64,linux/arm64 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15.8-otp-26 --push .
diff --git a/config/config.exs b/config/config.exs
index 35b1716a6e..b3f70ab4c9 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -83,8 +83,8 @@
scheme: "https://"
config :pleroma, Pleroma.Uploaders.IPFS,
- post_gateway_url: nil,
- get_gateway_url: nil
+ post_gateway_url: "http://localhost:5001",
+ get_gateway_url: "http://localhost:8080"
config :pleroma, :emoji,
shortcode_globs: ["/emoji/custom/**/*.png"],
@@ -132,6 +132,8 @@
]
# Configures Elixir's Logger
+config :logger, backends: [:console]
+
config :logger, :console,
level: :debug,
format: "\n$time $metadata[$level] $message\n",
diff --git a/config/description.exs b/config/description.exs
index 9b3b5457d1..46e0b13abd 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -1266,79 +1266,6 @@
}
]
},
- %{
- group: :logger,
- type: :group,
- description: "Logger-related settings",
- children: [
- %{
- key: :backends,
- type: [:atom, :tuple, :module],
- description:
- "Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :ex_syslogger } - to syslog, Quack.Logger - to Slack.",
- suggestions: [:console, {ExSyslogger, :ex_syslogger}]
- }
- ]
- },
- %{
- group: :logger,
- type: :group,
- key: :ex_syslogger,
- label: "ExSyslogger",
- description: "ExSyslogger-related settings",
- children: [
- %{
- key: :level,
- type: {:dropdown, :atom},
- description: "Log level",
- suggestions: [:debug, :info, :warning, :error]
- },
- %{
- key: :ident,
- type: :string,
- description:
- "A string that's prepended to every message, and is typically set to the app name",
- suggestions: ["pleroma"]
- },
- %{
- key: :format,
- type: :string,
- description: "Default: \"$date $time [$level] $levelpad$node $metadata $message\"",
- suggestions: ["$metadata[$level] $message"]
- },
- %{
- key: :metadata,
- type: {:list, :atom},
- suggestions: [:request_id]
- }
- ]
- },
- %{
- group: :logger,
- type: :group,
- key: :console,
- label: "Console Logger",
- description: "Console logger settings",
- children: [
- %{
- key: :level,
- type: {:dropdown, :atom},
- description: "Log level",
- suggestions: [:debug, :info, :warning, :error]
- },
- %{
- key: :format,
- type: :string,
- description: "Default: \"$date $time [$level] $levelpad$node $metadata $message\"",
- suggestions: ["$metadata[$level] $message"]
- },
- %{
- key: :metadata,
- type: {:list, :atom},
- suggestions: [:request_id]
- }
- ]
- },
%{
group: :pleroma,
key: :frontend_configurations,
diff --git a/config/dev.exs b/config/dev.exs
index f23719fe3d..14cf4a6dc1 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -36,7 +36,7 @@
# different ports.
# Do not include timestamps in development logs
-config :logger, :console, format: "$metadata[$level] $message\n"
+config :logger, Logger.Backends.Console, format: "$metadata[$level] $message\n"
# Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive.
diff --git a/config/prod.exs b/config/prod.exs
index 968f596e00..2d252bf024 100644
--- a/config/prod.exs
+++ b/config/prod.exs
@@ -20,6 +20,7 @@
config :phoenix, serve_endpoints: true
# Do not print debug messages in production
+config :logger, Logger.Backends.Console, level: :info
config :logger, :console, level: :info
config :logger, :ex_syslogger, level: :info
diff --git a/config/test.exs b/config/test.exs
index 40141a1483..1cf7dd0ed7 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -53,7 +53,8 @@
hostname: System.get_env("DB_HOST") || "localhost",
port: System.get_env("DB_PORT") || "5432",
pool: Ecto.Adapters.SQL.Sandbox,
- pool_size: System.schedulers_online() * 2
+ pool_size: System.schedulers_online() * 2,
+ log: false
config :pleroma, :dangerzone, override_repo_pool_size: true
@@ -189,6 +190,8 @@
streamer_registry: false,
test_http_pools: true
+config :pleroma, Pleroma.Web.Streaming, sync_streaming: true
+
config :pleroma, Pleroma.Uploaders.Uploader, timeout: 1_000
config :pleroma, Pleroma.Emoji.Loader, test_emoji: true
diff --git a/docs/administration/CLI_tasks/database.md b/docs/administration/CLI_tasks/database.md
index c53c499211..c5e51e5552 100644
--- a/docs/administration/CLI_tasks/database.md
+++ b/docs/administration/CLI_tasks/database.md
@@ -21,16 +21,18 @@ Replaces embedded objects with references to them in the `objects` table. Only n
mix pleroma.database remove_embedded_objects [option ...]
```
-
### Options
- `--vacuum` - run `VACUUM FULL` after the embedded objects are replaced with their references
## Prune old remote posts from the database
-This will prune remote posts older than 90 days (configurable with [`config :pleroma, :instance, remote_post_retention_days`](../../configuration/cheatsheet.md#instance)) from the database, they will be refetched from source when accessed.
+This will prune remote posts older than 90 days (configurable with [`config :pleroma, :instance, remote_post_retention_days`](../../configuration/cheatsheet.md#instance)) from the database. Pruned posts may be refetched in some cases.
+
+!!! note
+ The disk space will only be reclaimed after a proper vacuum. By default Postgresql does this for you on a regular basis, but if your instance has been running for a long time and there are many rows deleted, it may be advantageous to use `VACUUM FULL` (e.g. by using the `--vacuum` option).
!!! danger
- The disk space will only be reclaimed after `VACUUM FULL`. You may run out of disk space during the execution of the task or vacuuming if you don't have about 1/3rds of the database size free.
+ You may run out of disk space during the execution of the task or vacuuming if you don't have about 1/3rds of the database size free. Vacuum causes a substantial increase in I/O traffic, and may lead to a degraded experience while it is running.
=== "OTP"
@@ -45,7 +47,11 @@ This will prune remote posts older than 90 days (configurable with [`config :ple
```
### Options
-- `--vacuum` - run `VACUUM FULL` after the objects are pruned
+
+- `--keep-threads` - Don't prune posts when they are part of a thread where at least one post has seen local interaction (e.g. one of the posts is a local post, or is favourited by a local user, or has been repeated by a local user...). It also won't delete posts when at least one of the posts in that thread is kept (e.g. because one of the posts has seen recent activity).
+- `--keep-non-public` - Keep non-public posts like DM's and followers-only, even if they are remote.
+- `--prune-orphaned-activities` - Also prune orphaned activities afterwards. Activities are things like Like, Create, Announce, Flag (aka reports). They can significantly help reduce the database size. Note: this can take a very long time.
+- `--vacuum` - Run `VACUUM FULL` after the objects are pruned. This should not be used on a regular basis, but is useful if your instance has been running for a long time before pruning.
## Create a conversation for all existing DMs
@@ -93,6 +99,9 @@ Can be safely re-run
## Vacuum the database
+!!! note
+ By default Postgresql has an autovacuum deamon running. While the tasks described here can help in some cases, they shouldn't be needed on a regular basis. See [the Postgresql docs on vacuuming](https://www.postgresql.org/docs/current/sql-vacuum.html) for more information on this.
+
### Analyze
Running an `analyze` vacuum job can improve performance by updating statistics used by the query planner. **It is safe to cancel this.**
diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md
index 88f45b5c46..107562017c 100644
--- a/docs/configuration/cheatsheet.md
+++ b/docs/configuration/cheatsheet.md
@@ -853,7 +853,7 @@ config :logger,
backends: [{ExSyslogger, :ex_syslogger}]
config :logger, :ex_syslogger,
- level: :warn
+ level: :warning
```
Another example, keeping console output and adding the pid to syslog output:
@@ -862,7 +862,7 @@ config :logger,
backends: [:console, {ExSyslogger, :ex_syslogger}]
config :logger, :ex_syslogger,
- level: :warn,
+ level: :warning,
option: [:pid, :ndelay]
```
diff --git a/docs/installation/generic_dependencies.include b/docs/installation/generic_dependencies.include
index 666f49fbbf..bdb7f94d3a 100644
--- a/docs/installation/generic_dependencies.include
+++ b/docs/installation/generic_dependencies.include
@@ -1,7 +1,7 @@
## Required dependencies
* PostgreSQL >=11.0
-* Elixir >=1.13.0 <1.15
+* Elixir >=1.13.0 <1.17
* Erlang OTP >=22.2.0 (supported: <27)
* git
* file / libmagic
diff --git a/docs/installation/netbsd_en.md b/docs/installation/netbsd_en.md
index 2ade7df985..7c003700cb 100644
--- a/docs/installation/netbsd_en.md
+++ b/docs/installation/netbsd_en.md
@@ -2,14 +2,41 @@
{! backend/installation/generic_dependencies.include !}
-## Installing software used in this guide
+# Installation options
+
+Currently there are two options available for NetBSD: manual installation (from source) or using experimental package from [pkgsrc-wip](https://github.com/NetBSD/pkgsrc-wip/tree/master/pleroma).
+
+WIP package can be installed via pkgsrc and can be crosscompiled for easier binary distribution. Source installation most probably will be restricted to a single machine.
+
+## pkgsrc installation
+
+WIP package creates Mix.Release (similar to how Docker images are built) but doesn't bundle Erlang runtime, listing it as a dependency instead. This allows for easier and more modular installations, especially on weaker machines. Currently this method also does not support all features of `pleroma_ctl` command (like changing installation type or managing frontends) as NetBSD is not yet a supported binary flavour of Pleroma's CI.
+
+In any case, you can install it the same way as any other `pkgsrc-wip` package:
+
+```
+cd /usr/pkgsrc
+git clone --depth 1 git://wip.pkgsrc.org/pkgsrc-wip.git wip
+cp -rf wip/pleroma www
+cp -rf wip/libvips graphics
+cd /usr/pkgsrc/www/pleroma
+bmake && bmake install
+```
+
+Use `bmake package` to create a binary package. This can come especially handy if you're targeting embedded or low-power systems and are crosscompiling on a more powerful machine.
+
+> Note: Elixir has [endianness bug](https://github.com/elixir-lang/elixir/issues/2785) which requires it to be compiled on a machine with the same endianness. In other words, package crosscompiled on amd64 (little endian) won't work on powerpc or sparc machines (big endian). While _in theory™_ nothing catastrophic should happen, one can see that for example regexes won't work properly. Some distributions just strip this warning away, so it doesn't bother the users... anyway, you've been warned.
+
+## Source installation
pkgin should have been installed by the NetBSD installer if you selected
-the right options. If it isn't installed, install it using pkg_add.
+the right options. If it isn't installed, install it using `pkg_add`.
Note that `postgresql11-contrib` is needed for the Postgres extensions
Pleroma uses.
+> Note: you can use modern versions of PostgreSQL. In this case, just use `postgresql16-contrib` and so on.
+
The `mksh` shell is needed to run the Elixir `mix` script.
`# pkgin install acmesh elixir git-base git-docs mksh nginx postgresql11-server postgresql11-client postgresql11-contrib sudo ffmpeg4 ImageMagick`
@@ -29,29 +56,6 @@ shells/mksh
www/nginx
```
-Copy the rc.d scripts to the right directory:
-
-```
-# cp /usr/pkg/share/examples/rc.d/nginx /usr/pkg/share/examples/rc.d/pgsql /etc/rc.d
-```
-
-Add nginx and Postgres to `/etc/rc.conf`:
-
-```
-nginx=YES
-pgsql=YES
-```
-
-## Configuring postgres
-
-First, run `# /etc/rc.d/pgsql start`. Then, `$ sudo -Hu pgsql -g pgsql createdb`.
-
-### Install media / graphics packages (optional, see [`docs/installation/optional/media_graphics_packages.md`](../installation/optional/media_graphics_packages.md))
-
-`# pkgin install ImageMagick ffmpeg4 p5-Image-ExifTool`
-
-## Configuring Pleroma
-
Create a user for Pleroma:
```
@@ -68,41 +72,98 @@ $ cd /home/pleroma
$ git clone -b stable https://git.pleroma.social/pleroma/pleroma.git
```
-Configure Pleroma. Note that you need a domain name at this point:
+Get deps and compile:
```
$ cd /home/pleroma/pleroma
+$ export MIX_ENV=prod
$ mix deps.get
-$ MIX_ENV=prod mix pleroma.instance gen # You will be asked a few questions here.
+$ mix compile
```
-Since Postgres is configured, we can now initialize the database. There should
-now be a file in `config/setup_db.psql` that makes this easier. Edit it, and
-*change the password* to a password of your choice. Make sure it is secure, since
+## Install media / graphics packages (optional, see [`docs/installation/optional/media_graphics_packages.md`](../installation/optional/media_graphics_packages.md))
+
+`# pkgin install ImageMagick ffmpeg4 p5-Image-ExifTool`
+
+or via pkgsrc:
+
+```
+graphics/p5-Image-ExifTool
+graphics/ImageMagick
+multimedia/ffmpeg4
+```
+
+# Configuration
+
+## Understanding $PREFIX
+
+From now on, you may encounter `$PREFIX` variable in the paths. This variable indicates your current local pkgsrc prefix. Usually it's `/usr/pkg` unless you configured it otherwise. Translating to pkgsrc's lingo, it's called `LOCALBASE`, which essentially means the same this. You may want to set it up for your local shell session (this uses `mksh` which should already be installed as one of the required dependencies):
+
+```
+$ export PREFIX=$(pkg_info -Q LOCALBASE mksh)
+$ echo $PREFIX
+/usr/pkg
+```
+
+## Setting up your instance
+
+Now, you need to configure your instance. During this initial configuration, you will be asked some questions about your server. You will need a domain name at this point; it doesn't have to be deployed, but changing it later will be very cumbersome.
+
+If you've installed via pkgsrc, `pleroma_ctl` should already be in your `PATH`; if you've installed from source, it's located at `/home/pleroma/pleroma/release/bin/pleroma_ctl`.
+
+```
+$ su -l pleroma
+$ pleroma_ctl instance gen --output $PREFIX/etc/pleroma/config.exs --output-psql /tmp/setup_db.psql
+```
+
+During installation, you will be asked about static and upload directories. Don't forget to create them and update permissions:
+
+```
+mkdir -p /var/lib/pleroma/uploads
+chown -R pleroma:pleroma /var/lib/pleroma
+```
+
+## Setting up the database
+
+First, run `# /etc/rc.d/pgsql start`. Then, `$ sudo -Hu pgsql -g pgsql createdb`.
+
+We can now initialize the database. You'll need to edit generated SQL file from the previous step. It's located at `/tmp/setup_db.psql`.
+
+Edit this file, and *change the password* to a password of your choice. Make sure it is secure, since
it'll be protecting your database. Now initialize the database:
```
-$ sudo -Hu pgsql -g pgsql psql -f config/setup_db.psql
+$ sudo -Hu pgsql -g pgsql psql -f /tmp/setup_db.psql
```
Postgres allows connections from all users without a password by default. To
-fix this, edit `/usr/pkg/pgsql/data/pg_hba.conf`. Change every `trust` to
+fix this, edit `$PREFIX/pgsql/data/pg_hba.conf`. Change every `trust` to
`password`.
Once this is done, restart Postgres with `# /etc/rc.d/pgsql restart`.
Run the database migrations.
+
+### pkgsrc installation
+
+```
+pleroma_ctl migrate
+```
+
+### Source installation
+
You will need to do this whenever you update with `git pull`:
```
+$ cd /home/pleroma/pleroma
$ MIX_ENV=prod mix ecto.migrate
```
## Configuring nginx
Install the example configuration file
-`/home/pleroma/pleroma/installation/pleroma.nginx` to
-`/usr/pkg/etc/nginx.conf`.
+(`$PREFIX/share/examples/pleroma/pleroma.nginx` or `/home/pleroma/pleroma/installation/pleroma.nginx`) to
+`$PREFIX/etc/nginx.conf`.
Note that it will need to be wrapped in a `http {}` block. You should add
settings for the nginx daemon outside of the http block, for example:
@@ -176,27 +237,45 @@ Let's add auto-renewal to `/etc/daily.local`
--stateless
```
-## Creating a startup script for Pleroma
+## Autostart
-Copy the startup script to the correct location and make sure it's executable:
+For properly functioning instance, you will need pleroma (backend service), nginx (reverse proxy) and postgresql (database) services running. There's no requirement for them to reside on the same machine, but you have to provide autostart for each of them.
+### nginx
+```
+# cp $PREFIX/share/examples/rc.d/nginx /etc/rc.d
+# echo "nginx=YES" >> /etc/rc.conf
+```
+
+### postgresql
+
+```
+# cp $PREFIX/share/examples/rc.d/pgsql /etc/rc.d
+# echo "pgsql=YES" >> /etc/rc.conf
+```
+
+### pleroma
+
+First, copy the script (pkgsrc variant)
+```
+# cp $PREFIX/share/examples/pleroma/pleroma.rc /etc/rc.d/pleroma
+```
+
+or source variant
```
# cp /home/pleroma/pleroma/installation/netbsd/rc.d/pleroma /etc/rc.d/pleroma
# chmod +x /etc/rc.d/pleroma
```
-Add the following to `/etc/rc.conf`:
+Then, add the following to `/etc/rc.conf`:
```
pleroma=YES
-pleroma_home="/home/pleroma"
-pleroma_user="pleroma"
```
-Run `# /etc/rc.d/pleroma start` to start Pleroma.
-
## Conclusion
+Run `# /etc/rc.d/pleroma start` to start Pleroma.
Restart nginx with `# /etc/rc.d/nginx restart` and you should be up and running.
Make sure your time is in sync, or other instances will receive your posts with
diff --git a/installation/netbsd/rc.d/pleroma b/installation/netbsd/rc.d/pleroma
index 1114668eeb..c70112c3b5 100755
--- a/installation/netbsd/rc.d/pleroma
+++ b/installation/netbsd/rc.d/pleroma
@@ -1,11 +1,14 @@
#!/bin/sh
# PROVIDE: pleroma
-# REQUIRE: DAEMON pgsql
+# REQUIRE: DAEMON pgsql nginx
if [ -f /etc/rc.subr ]; then
. /etc/rc.subr
fi
+pleroma_home="/home/pleroma"
+pleroma_user="pleroma"
+
name="pleroma"
rcvar=${name}
command="/usr/pkg/bin/elixir"
@@ -19,10 +22,10 @@ pleroma_env="HOME=${pleroma_home} MIX_ENV=prod"
check_pidfile()
{
pid=$(pgrep -U "${pleroma_user}" /bin/beam.smp$)
- echo -n "${pid}"
+ printf '%s' "${pid}"
}
-if [ -f /etc/rc.subr -a -d /etc/rc.d -a -f /etc/rc.d/DAEMON ]; then
+if [ -f /etc/rc.subr ] && [ -d /etc/rc.d ] && [ -f /etc/rc.d/DAEMON ]; then
# newer NetBSD
load_rc_config ${name}
run_rc_command "$1"
@@ -39,7 +42,7 @@ else
stop)
echo "Stopping ${name}."
check_pidfile
- ! [ -n ${pid} ] && kill ${pid}
+ ! [ -n "${pid}" ] && kill "${pid}"
;;
restart)
diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex
index 2976085ba3..c01cf054d9 100644
--- a/lib/mix/pleroma.ex
+++ b/lib/mix/pleroma.ex
@@ -14,7 +14,8 @@ defmodule Mix.Pleroma do
:swoosh,
:timex,
:fast_html,
- :oban
+ :oban,
+ :logger_backends
]
@cachex_children ["object", "user", "scrubber", "web_resp"]
@doc "Common functions to be reused in mix tasks"
diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex
index 93ee57dc33..b82d1f079d 100644
--- a/lib/mix/tasks/pleroma/database.ex
+++ b/lib/mix/tasks/pleroma/database.ex
@@ -67,43 +67,168 @@ def run(["prune_objects" | args]) do
OptionParser.parse(
args,
strict: [
- vacuum: :boolean
+ vacuum: :boolean,
+ keep_threads: :boolean,
+ keep_non_public: :boolean,
+ prune_orphaned_activities: :boolean
]
)
start_pleroma()
deadline = Pleroma.Config.get([:instance, :remote_post_retention_days])
+ time_deadline = NaiveDateTime.utc_now() |> NaiveDateTime.add(-(deadline * 86_400))
- Logger.info("Pruning objects older than #{deadline} days")
+ log_message = "Pruning objects older than #{deadline} days"
- time_deadline =
- NaiveDateTime.utc_now()
- |> NaiveDateTime.add(-(deadline * 86_400))
+ log_message =
+ if Keyword.get(options, :keep_non_public) do
+ log_message <> ", keeping non public posts"
+ else
+ log_message
+ end
- from(o in Object,
- where:
- fragment(
- "?->'to' \\? ? OR ?->'cc' \\? ?",
- o.data,
- ^Pleroma.Constants.as_public(),
- o.data,
- ^Pleroma.Constants.as_public()
- ),
- where: o.inserted_at < ^time_deadline,
- where:
+ log_message =
+ if Keyword.get(options, :keep_threads) do
+ log_message <> ", keeping threads intact"
+ else
+ log_message
+ end
+
+ log_message =
+ if Keyword.get(options, :prune_orphaned_activities) do
+ log_message <> ", pruning orphaned activities"
+ else
+ log_message
+ end
+
+ log_message =
+ if Keyword.get(options, :vacuum) do
+ log_message <>
+ ", doing a full vacuum (you shouldn't do this as a recurring maintanance task)"
+ else
+ log_message
+ end
+
+ Logger.info(log_message)
+
+ if Keyword.get(options, :keep_threads) do
+ # We want to delete objects from threads where
+ # 1. the newest post is still old
+ # 2. none of the activities is local
+ # 3. none of the activities is bookmarked
+ # 4. optionally none of the posts is non-public
+ deletable_context =
+ if Keyword.get(options, :keep_non_public) do
+ Pleroma.Activity
+ |> join(:left, [a], b in Pleroma.Bookmark, on: a.id == b.activity_id)
+ |> group_by([a], fragment("? ->> 'context'::text", a.data))
+ |> having(
+ [a],
+ not fragment(
+ # Posts (checked on Create Activity) is non-public
+ "bool_or((not(?->'to' \\? ? OR ?->'cc' \\? ?)) and ? ->> 'type' = 'Create')",
+ a.data,
+ ^Pleroma.Constants.as_public(),
+ a.data,
+ ^Pleroma.Constants.as_public(),
+ a.data
+ )
+ )
+ else
+ Pleroma.Activity
+ |> join(:left, [a], b in Pleroma.Bookmark, on: a.id == b.activity_id)
+ |> group_by([a], fragment("? ->> 'context'::text", a.data))
+ end
+ |> having([a], max(a.updated_at) < ^time_deadline)
+ |> having([a], not fragment("bool_or(?)", a.local))
+ |> having([_, b], fragment("max(?::text) is null", b.id))
+ |> select([a], fragment("? ->> 'context'::text", a.data))
+
+ Pleroma.Object
+ |> where([o], fragment("? ->> 'context'::text", o.data) in subquery(deletable_context))
+ else
+ if Keyword.get(options, :keep_non_public) do
+ Pleroma.Object
+ |> where(
+ [o],
+ fragment(
+ "?->'to' \\? ? OR ?->'cc' \\? ?",
+ o.data,
+ ^Pleroma.Constants.as_public(),
+ o.data,
+ ^Pleroma.Constants.as_public()
+ )
+ )
+ else
+ Pleroma.Object
+ end
+ |> where([o], o.updated_at < ^time_deadline)
+ |> where(
+ [o],
fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host())
- )
+ )
+ end
|> Repo.delete_all(timeout: :infinity)
- prune_hashtags_query = """
+ if !Keyword.get(options, :keep_threads) do
+ # Without the --keep-threads option, it's possible that bookmarked
+ # objects have been deleted. We remove the corresponding bookmarks.
+ """
+ delete from public.bookmarks
+ where id in (
+ select b.id from public.bookmarks b
+ left join public.activities a on b.activity_id = a.id
+ left join public.objects o on a."data" ->> 'object' = o.data ->> 'id'
+ where o.id is null
+ )
+ """
+ |> Repo.query([], timeout: :infinity)
+ end
+
+ if Keyword.get(options, :prune_orphaned_activities) do
+ # Prune activities who link to a single object
+ """
+ delete from public.activities
+ where id in (
+ select a.id from public.activities a
+ left join public.objects o on a.data ->> 'object' = o.data ->> 'id'
+ left join public.activities a2 on a.data ->> 'object' = a2.data ->> 'id'
+ left join public.users u on a.data ->> 'object' = u.ap_id
+ where not a.local
+ and jsonb_typeof(a."data" -> 'object') = 'string'
+ and o.id is null
+ and a2.id is null
+ and u.id is null
+ )
+ """
+ |> Repo.query([], timeout: :infinity)
+
+ # Prune activities who link to an array of objects
+ """
+ delete from public.activities
+ where id in (
+ select a.id from public.activities a
+ join json_array_elements_text((a."data" -> 'object')::json) as j on jsonb_typeof(a."data" -> 'object') = 'array'
+ left join public.objects o on j.value = o.data ->> 'id'
+ left join public.activities a2 on j.value = a2.data ->> 'id'
+ left join public.users u on j.value = u.ap_id
+ group by a.id
+ having max(o.data ->> 'id') is null
+ and max(a2.data ->> 'id') is null
+ and max(u.ap_id) is null
+ )
+ """
+ |> Repo.query([], timeout: :infinity)
+ end
+
+ """
DELETE FROM hashtags AS ht
WHERE NOT EXISTS (
SELECT 1 FROM hashtags_objects hto
WHERE ht.id = hto.hashtag_id)
"""
-
- Repo.query(prune_hashtags_query)
+ |> Repo.query()
if Keyword.get(options, :vacuum) do
Maintenance.vacuum("full")
@@ -226,7 +351,7 @@ def run(["set_text_search_config", tsconfig]) do
)
end
- shell_info('Done.')
+ shell_info(~c"Done.")
end
end
diff --git a/lib/mix/tasks/pleroma/search/indexer.ex b/lib/mix/tasks/pleroma/search/indexer.ex
index 81a9fced63..2a52472f9b 100644
--- a/lib/mix/tasks/pleroma/search/indexer.ex
+++ b/lib/mix/tasks/pleroma/search/indexer.ex
@@ -33,15 +33,18 @@ def run(["index" | options]) do
OptionParser.parse(
options,
strict: [
- limit: :integer
+ chunk: :integer,
+ limit: :integer,
+ step: :integer
]
)
start_pleroma()
+ chunk_size = Keyword.get(options, :chunk, 100)
limit = Keyword.get(options, :limit, 100_000)
+ per_step = Keyword.get(options, :step, 1000)
- per_step = 1000
chunks = max(div(limit, per_step), 1)
1..chunks
@@ -65,7 +68,7 @@ def run(["index" | options]) do
IO.puts("Got #{length(ids)} activities, adding to indexer")
ids
- |> Enum.chunk_every(100)
+ |> Enum.chunk_every(chunk_size)
|> Enum.each(fn chunk ->
IO.puts("Adding #{length(chunk)} activities to indexing queue")
diff --git a/lib/mix/tasks/pleroma/test_runner.ex b/lib/mix/tasks/pleroma/test_runner.ex
new file mode 100644
index 0000000000..69fefb0014
--- /dev/null
+++ b/lib/mix/tasks/pleroma/test_runner.ex
@@ -0,0 +1,25 @@
+defmodule Mix.Tasks.Pleroma.TestRunner do
+ @shortdoc "Retries tests once if they fail"
+
+ use Mix.Task
+
+ def run(args \\ []) do
+ case System.cmd("mix", ["test"] ++ args, into: IO.stream(:stdio, :line)) do
+ {_, 0} ->
+ :ok
+
+ _ ->
+ retry(args)
+ end
+ end
+
+ def retry(args) do
+ case System.cmd("mix", ["test", "--failed"] ++ args, into: IO.stream(:stdio, :line)) do
+ {_, 0} ->
+ :ok
+
+ _ ->
+ exit(1)
+ end
+ end
+end
diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex
index 760fddaa8c..222edb32f0 100644
--- a/lib/pleroma/config/transfer_task.ex
+++ b/lib/pleroma/config/transfer_task.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
+# Copyright © 2017-2023 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Config.TransferTask do
@@ -43,14 +43,9 @@ def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do
with {_, true} <- {:configurable, Config.get(:configurable_from_database)} do
# We need to restart applications for loaded settings take effect
- {logger, other} =
+ settings =
(Repo.all(ConfigDB) ++ deleted_settings)
|> Enum.map(&merge_with_default/1)
- |> Enum.split_with(fn {group, _, _, _} -> group in [:logger] end)
-
- logger
- |> Enum.sort()
- |> Enum.each(&configure/1)
started_applications = Application.started_applications()
@@ -63,7 +58,7 @@ def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do
[:pleroma | reject]
end
- other
+ settings
|> Enum.map(&update/1)
|> Enum.uniq()
|> Enum.reject(&(&1 in reject))
@@ -101,38 +96,6 @@ defp merge_with_default(%{group: group, key: key, value: value} = setting) do
{group, key, value, merged}
end
- # change logger configuration in runtime, without restart
- defp configure({_, :backends, _, merged}) do
- # removing current backends
- Enum.each(Application.get_env(:logger, :backends), &Logger.remove_backend/1)
-
- Enum.each(merged, &Logger.add_backend/1)
-
- :ok = update_env(:logger, :backends, merged)
- end
-
- defp configure({_, key, _, merged}) when key in [:console, :ex_syslogger] do
- merged =
- if key == :console do
- put_in(merged[:format], merged[:format] <> "\n")
- else
- merged
- end
-
- backend =
- if key == :ex_syslogger,
- do: {ExSyslogger, :ex_syslogger},
- else: key
-
- Logger.configure_backend(backend, merged)
- :ok = update_env(:logger, key, merged)
- end
-
- defp configure({_, key, _, merged}) do
- Logger.configure([{key, merged}])
- :ok = update_env(:logger, key, merged)
- end
-
defp update({group, key, value, merged}) do
try do
:ok = update_env(group, key, merged)
diff --git a/lib/pleroma/config_db.ex b/lib/pleroma/config_db.ex
index 4e7f594e11..588846154a 100644
--- a/lib/pleroma/config_db.ex
+++ b/lib/pleroma/config_db.ex
@@ -165,8 +165,7 @@ defp only_full_update?(%ConfigDB{group: group, key: key}) do
{:pleroma, :ecto_repos},
{:mime, :types},
{:cors_plug, [:max_age, :methods, :expose, :headers]},
- {:swarm, :node_blacklist},
- {:logger, :backends}
+ {:swarm, :node_blacklist}
]
Enum.any?(full_key_update, fn
@@ -385,7 +384,12 @@ defp find_valid_delimiter([delimiter | others], pattern, regex_delimiter) do
@spec module_name?(String.t()) :: boolean()
def module_name?(string) do
- Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Ueberauth|Swoosh)\./, string) or
- string in ["Oban", "Ueberauth", "ExSyslogger", "ConcurrentLimiter"]
+ if String.contains?(string, ".") do
+ [name | _] = String.split(string, ".", parts: 2)
+
+ name in ~w[Pleroma Phoenix Tesla Ueberauth Swoosh Logger LoggerBackends]
+ else
+ string in ~w[Oban Ueberauth ExSyslogger ConcurrentLimiter]
+ end
end
end
diff --git a/lib/pleroma/emoji/pack.ex b/lib/pleroma/emoji/pack.ex
index 36e1553c69..c6cb9231d2 100644
--- a/lib/pleroma/emoji/pack.ex
+++ b/lib/pleroma/emoji/pack.ex
@@ -418,10 +418,10 @@ defp downloadable?(pack) do
end
defp create_archive_and_cache(pack, hash) do
- files = ['pack.json' | Enum.map(pack.files, fn {_, file} -> to_charlist(file) end)]
+ files = [~c"pack.json" | Enum.map(pack.files, fn {_, file} -> to_charlist(file) end)]
{:ok, {_, result}} =
- :zip.zip('#{pack.name}.zip', files, [:memory, cwd: to_charlist(pack.path)])
+ :zip.zip(~c"#{pack.name}.zip", files, [:memory, cwd: to_charlist(pack.path)])
ttl_per_file = Pleroma.Config.get!([:emoji, :shared_pack_cache_seconds_per_file])
overall_ttl = :timer.seconds(ttl_per_file * Enum.count(files))
@@ -591,7 +591,7 @@ defp unzip(archive, pack_info, remote_pack, local_pack) do
with :ok <- File.mkdir_p!(local_pack.path) do
files = Enum.map(remote_pack["files"], fn {_, path} -> to_charlist(path) end)
# Fallback cannot contain a pack.json file
- files = if pack_info[:fallback], do: files, else: ['pack.json' | files]
+ files = if pack_info[:fallback], do: files, else: [~c"pack.json" | files]
:zip.unzip(archive, cwd: to_charlist(local_pack.path), file_list: files)
end
diff --git a/lib/pleroma/gun/connection_pool/reclaimer.ex b/lib/pleroma/gun/connection_pool/reclaimer.ex
index 35e7f4b2ee..3580d38f54 100644
--- a/lib/pleroma/gun/connection_pool/reclaimer.ex
+++ b/lib/pleroma/gun/connection_pool/reclaimer.ex
@@ -9,7 +9,7 @@ defp registry, do: Pleroma.Gun.ConnectionPool
def start_monitor do
pid =
- case GenServer.start_link(__MODULE__, [], name: {:via, Registry, {registry(), "reclaimer"}}) do
+ case GenServer.start(__MODULE__, [], name: {:via, Registry, {registry(), "reclaimer"}}) do
{:ok, pid} ->
pid
diff --git a/lib/pleroma/gun/connection_pool/worker_supervisor.ex b/lib/pleroma/gun/connection_pool/worker_supervisor.ex
index eb83962d8e..b9dedf61e1 100644
--- a/lib/pleroma/gun/connection_pool/worker_supervisor.ex
+++ b/lib/pleroma/gun/connection_pool/worker_supervisor.ex
@@ -5,6 +5,9 @@
defmodule Pleroma.Gun.ConnectionPool.WorkerSupervisor do
@moduledoc "Supervisor for pool workers. Does not do anything except enforce max connection limit"
+ alias Pleroma.Config
+ alias Pleroma.Gun.ConnectionPool.Worker
+
use DynamicSupervisor
def start_link(opts) do
@@ -14,21 +17,28 @@ def start_link(opts) do
def init(_opts) do
DynamicSupervisor.init(
strategy: :one_for_one,
- max_children: Pleroma.Config.get([:connections_pool, :max_connections])
+ max_children: Config.get([:connections_pool, :max_connections])
)
end
- def start_worker(opts, last_attempt \\ false) do
- case DynamicSupervisor.start_child(__MODULE__, {Pleroma.Gun.ConnectionPool.Worker, opts}) do
- {:error, :max_children} ->
- funs = [fn -> last_attempt end, fn -> match?(:error, free_pool()) end]
+ def start_worker(opts, last_attempt \\ false)
- if Enum.any?(funs, fn fun -> fun.() end) do
- :telemetry.execute([:pleroma, :connection_pool, :provision_failure], %{opts: opts})
- {:error, :pool_full}
- else
- start_worker(opts, true)
- end
+ def start_worker(opts, true) do
+ case DynamicSupervisor.start_child(__MODULE__, {Worker, opts}) do
+ {:error, :max_children} ->
+ :telemetry.execute([:pleroma, :connection_pool, :provision_failure], %{opts: opts})
+ {:error, :pool_full}
+
+ res ->
+ res
+ end
+ end
+
+ def start_worker(opts, false) do
+ case DynamicSupervisor.start_child(__MODULE__, {Worker, opts}) do
+ {:error, :max_children} ->
+ free_pool()
+ start_worker(opts, true)
res ->
res
diff --git a/lib/pleroma/helpers/media_helper.ex b/lib/pleroma/helpers/media_helper.ex
index e44114d9da..8566ab3ea2 100644
--- a/lib/pleroma/helpers/media_helper.ex
+++ b/lib/pleroma/helpers/media_helper.ex
@@ -25,7 +25,7 @@ def missing_dependencies do
end
def image_resize(url, options) do
- with {:ok, env} <- HTTP.get(url, [], pool: :media),
+ with {:ok, env} <- HTTP.get(url, [], http_client_opts()),
{:ok, resized} <-
Operation.thumbnail_buffer(env.body, options.max_width,
height: options.max_height,
@@ -45,8 +45,8 @@ def image_resize(url, options) do
@spec video_framegrab(String.t()) :: {:ok, binary()} | {:error, any()}
def video_framegrab(url) do
with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
- false <- @cachex.exists?(:failed_media_helper_cache, url),
- {:ok, env} <- HTTP.get(url, [], pool: :media),
+ {:ok, false} <- @cachex.exists?(:failed_media_helper_cache, url),
+ {:ok, env} <- HTTP.get(url, [], http_client_opts()),
{:ok, pid} <- StringIO.open(env.body) do
body_stream = IO.binstream(pid, 1)
@@ -71,17 +71,19 @@ def video_framegrab(url) do
end)
case Task.yield(task, 5_000) do
- nil ->
+ {:ok, result} ->
+ {:ok, result}
+
+ _ ->
Task.shutdown(task)
@cachex.put(:failed_media_helper_cache, url, nil)
{:error, {:ffmpeg, :timeout}}
-
- result ->
- {:ok, result}
end
else
nil -> {:error, {:ffmpeg, :command_not_found}}
{:error, _} = error -> error
end
end
+
+ defp http_client_opts, do: Pleroma.Config.get([:media_proxy, :proxy_opts, :http], pool: :media)
end
diff --git a/lib/pleroma/http.ex b/lib/pleroma/http.ex
index eec61cf141..ec837e5092 100644
--- a/lib/pleroma/http.ex
+++ b/lib/pleroma/http.ex
@@ -37,7 +37,7 @@ def head(url, headers \\ [], options \\ []), do: request(:head, url, "", headers
See `Pleroma.HTTP.request/5`
"""
- @spec post(Request.url(), String.t(), Request.headers(), keyword()) ::
+ @spec post(Request.url(), Tesla.Env.body(), Request.headers(), keyword()) ::
{:ok, Env.t()} | {:error, any()}
def post(url, body, headers \\ [], options \\ []),
do: request(:post, url, body, headers, options)
@@ -56,7 +56,7 @@ def post(url, body, headers \\ [], options \\ []),
`{:ok, %Tesla.Env{}}` or `{:error, error}`
"""
- @spec request(method(), Request.url(), String.t(), Request.headers(), keyword()) ::
+ @spec request(method(), Request.url(), Tesla.Env.body(), Request.headers(), keyword()) ::
{:ok, Env.t()} | {:error, any()}
def request(method, url, body, headers, options) when is_binary(url) do
uri = URI.parse(url)
diff --git a/lib/pleroma/http/adapter_helper/gun.ex b/lib/pleroma/http/adapter_helper/gun.ex
index 74ab9851ec..1fe8dd4b26 100644
--- a/lib/pleroma/http/adapter_helper/gun.ex
+++ b/lib/pleroma/http/adapter_helper/gun.ex
@@ -15,7 +15,7 @@ defmodule Pleroma.HTTP.AdapterHelper.Gun do
retry_timeout: 1_000
]
- @type pool() :: :federation | :upload | :media | :default
+ @type pool() :: :federation | :upload | :media | :rich_media | :default
@spec options(keyword(), URI.t()) :: keyword()
def options(incoming_opts \\ [], %URI{} = uri) do
diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
index b7c45f886b..ce9d25093a 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -548,7 +548,7 @@ def create_event_notifications(%Activity{} = activity) do
NOTE: might be called for FAKE Activities, see ActivityPub.Utils.get_notified_from_object/1
"""
- @spec get_notified_from_activity(Activity.t(), boolean()) :: {list(User.t()), list(User.t())}
+ @spec get_notified_from_activity(Activity.t(), boolean()) :: list(User.t())
def get_notified_from_activity(activity, local_only \\ true)
def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, local_only)
@@ -865,8 +865,9 @@ def mark_context_as_read(%User{id: id}, context) do
|> Repo.update_all(set: [seen: true])
end
- @spec send(list(Notification.t())) :: :ok
- def send(notifications) do
+ @doc "Streams a list of notifications over websockets and web push"
+ @spec stream(list(Notification.t())) :: :ok
+ def stream(notifications) do
Enum.each(notifications, fn notification ->
Streamer.stream(["user", "user:notification"], notification)
Push.send(notification)
diff --git a/lib/pleroma/object/updater.ex b/lib/pleroma/object/updater.ex
index 39fe789448..8fd7da0a42 100644
--- a/lib/pleroma/object/updater.ex
+++ b/lib/pleroma/object/updater.ex
@@ -135,7 +135,10 @@ def make_update_object_data(original_data, new_data, date) do
else
%{updated_object: updated_data} =
updated_data
- |> maybe_update_history(original_data, updated: updated, use_history_in_new_object?: false)
+ |> maybe_update_history(original_data,
+ updated: updated,
+ use_history_in_new_object?: false
+ )
updated_data
|> Map.put("updated", date)
diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex
index 4d13e51fcc..8aec4ae588 100644
--- a/lib/pleroma/reverse_proxy.ex
+++ b/lib/pleroma/reverse_proxy.ex
@@ -8,7 +8,7 @@ defmodule Pleroma.ReverseProxy do
~w(if-unmodified-since if-none-match) ++ @range_headers
@resp_cache_headers ~w(etag date last-modified)
@keep_resp_headers @resp_cache_headers ++
- ~w(content-type content-disposition content-encoding) ++
+ ~w(content-length content-type content-disposition content-encoding) ++
~w(content-range accept-ranges vary)
@default_cache_control_header "public, max-age=1209600"
@valid_resp_codes [200, 206, 304]
@@ -180,6 +180,7 @@ defp response(conn, client, url, status, headers, opts) do
result =
conn
|> put_resp_headers(build_resp_headers(headers, opts))
+ |> streaming_compat
|> send_chunked(status)
|> chunk_reply(client, opts)
@@ -417,4 +418,17 @@ defp track_failed_url(url, error, opts) do
@cachex.put(:failed_proxy_url_cache, url, true, ttl: ttl)
end
+
+ # When Cowboy handles a chunked response with a content-length header it streams
+ # over HTTP 1.1 instead of chunking. Bandit cannot stream over HTTP 1.1 so the header
+ # must be stripped or it breaks RFC compliance for Transfer Encoding: Chunked. RFC9112§6.2
+ #
+ # HTTP2 is always streamed for all adapters.
+ defp streaming_compat(conn) do
+ with Phoenix.Endpoint.Cowboy2Adapter <- Pleroma.Web.Endpoint.config(:adapter) do
+ conn
+ else
+ _ -> delete_resp_header(conn, "content-length")
+ end
+ end
end
diff --git a/lib/pleroma/search/database_search.ex b/lib/pleroma/search/database_search.ex
index c6fe8a9bd8..aef5d1e741 100644
--- a/lib/pleroma/search/database_search.ex
+++ b/lib/pleroma/search/database_search.ex
@@ -28,7 +28,7 @@ def search(user, search_query, options \\ []) do
|> Activity.with_preloaded_object()
|> Activity.restrict_deactivated_users()
|> restrict_public(user)
- |> query_with(index_type, search_query, :websearch)
+ |> query_with(index_type, search_query)
|> maybe_restrict_local(user)
|> maybe_restrict_author(author)
|> maybe_restrict_blocked(user)
@@ -88,25 +88,7 @@ defp restrict_public(q, _user) do
)
end
- defp query_with(q, :gin, search_query, :plain) do
- %{rows: [[tsc]]} =
- Ecto.Adapters.SQL.query!(
- Pleroma.Repo,
- "select current_setting('default_text_search_config')::regconfig::oid;"
- )
-
- from([a, o] in q,
- where:
- fragment(
- "to_tsvector(?::oid::regconfig, ?->>'content') @@ plainto_tsquery(?)",
- ^tsc,
- o.data,
- ^search_query
- )
- )
- end
-
- defp query_with(q, :gin, search_query, :websearch) do
+ defp query_with(q, :gin, search_query) do
%{rows: [[tsc]]} =
Ecto.Adapters.SQL.query!(
Pleroma.Repo,
@@ -124,19 +106,7 @@ defp query_with(q, :gin, search_query, :websearch) do
)
end
- defp query_with(q, :rum, search_query, :plain) do
- from([a, o] in q,
- where:
- fragment(
- "? @@ plainto_tsquery(?)",
- o.fts_content,
- ^search_query
- ),
- order_by: [fragment("? <=> now()::date", o.inserted_at)]
- )
- end
-
- defp query_with(q, :rum, search_query, :websearch) do
+ defp query_with(q, :rum, search_query) do
from([a, o] in q,
where:
fragment(
diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex
index 87290c6c21..3756968180 100644
--- a/lib/pleroma/upload.ex
+++ b/lib/pleroma/upload.ex
@@ -277,14 +277,16 @@ defp url_from_spec(%__MODULE__{name: name}, base_url, {:file, path}) do
defp url_from_spec(_upload, _base_url, {:url, url}), do: url
+ @spec base_url() :: binary
def base_url do
uploader = @config_impl.get([Pleroma.Upload, :uploader])
- upload_base_url = @config_impl.get([Pleroma.Upload, :base_url])
+ upload_fallback_url = Pleroma.Web.Endpoint.url() <> "/media/"
+ upload_base_url = @config_impl.get([Pleroma.Upload, :base_url]) || upload_fallback_url
public_endpoint = @config_impl.get([uploader, :public_endpoint])
case uploader do
Pleroma.Uploaders.Local ->
- upload_base_url || Pleroma.Web.Endpoint.url() <> "/media/"
+ upload_base_url
Pleroma.Uploaders.S3 ->
bucket = @config_impl.get([Pleroma.Uploaders.S3, :bucket])
@@ -296,11 +298,14 @@ def base_url do
!is_nil(truncated_namespace) ->
truncated_namespace
- !is_nil(namespace) ->
+ !is_nil(namespace) and !is_nil(bucket) ->
namespace <> ":" <> bucket
- true ->
+ !is_nil(bucket) ->
bucket
+
+ true ->
+ ""
end
if public_endpoint do
@@ -313,7 +318,7 @@ def base_url do
@config_impl.get([Pleroma.Uploaders.IPFS, :get_gateway_url])
_ ->
- public_endpoint || upload_base_url || Pleroma.Web.Endpoint.url() <> "/media/"
+ public_endpoint || upload_base_url
end
end
end
diff --git a/lib/pleroma/upload/filter/exiftool/strip_location.ex b/lib/pleroma/upload/filter/exiftool/strip_location.ex
index f2bcc4622b..8becee712f 100644
--- a/lib/pleroma/upload/filter/exiftool/strip_location.ex
+++ b/lib/pleroma/upload/filter/exiftool/strip_location.ex
@@ -9,8 +9,6 @@ defmodule Pleroma.Upload.Filter.Exiftool.StripLocation do
"""
@behaviour Pleroma.Upload.Filter
- @spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()}
-
# Formats not compatible with exiftool at this time
def filter(%Pleroma.Upload{content_type: "image/heic"}), do: {:ok, :noop}
def filter(%Pleroma.Upload{content_type: "image/webp"}), do: {:ok, :noop}
diff --git a/lib/pleroma/upload/filter/mogrifun.ex b/lib/pleroma/upload/filter/mogrifun.ex
index a0f247b704..9716580a84 100644
--- a/lib/pleroma/upload/filter/mogrifun.ex
+++ b/lib/pleroma/upload/filter/mogrifun.ex
@@ -38,7 +38,6 @@ defmodule Pleroma.Upload.Filter.Mogrifun do
[{"fill", "yellow"}, {"tint", "40"}]
]
- @spec filter(Pleroma.Upload.t()) :: {:ok, atom()} | {:error, String.t()}
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
try do
Filter.Mogrify.do_filter(file, [Enum.random(@filters)])
diff --git a/lib/pleroma/upload/filter/mogrify.ex b/lib/pleroma/upload/filter/mogrify.ex
index 06efbf3212..d1e166022b 100644
--- a/lib/pleroma/upload/filter/mogrify.ex
+++ b/lib/pleroma/upload/filter/mogrify.ex
@@ -8,7 +8,6 @@ defmodule Pleroma.Upload.Filter.Mogrify do
@type conversion :: action :: String.t() | {action :: String.t(), opts :: String.t()}
@type conversions :: conversion() | [conversion()]
- @spec filter(Pleroma.Upload.t()) :: {:ok, :atom} | {:error, String.t()}
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
try do
do_filter(file, Pleroma.Config.get!([__MODULE__, :args]))
diff --git a/lib/pleroma/uploaders/ipfs.ex b/lib/pleroma/uploaders/ipfs.ex
index d171e46525..5930a129e2 100644
--- a/lib/pleroma/uploaders/ipfs.ex
+++ b/lib/pleroma/uploaders/ipfs.ex
@@ -8,23 +8,10 @@ defmodule Pleroma.Uploaders.IPFS do
alias Tesla.Multipart
+ @api_add "/api/v0/add"
+ @api_delete "/api/v0/files/rm"
@config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
- defp get_final_url(method) do
- config = @config_impl.get([__MODULE__])
- post_base_url = Keyword.get(config, :post_gateway_url)
-
- Path.join([post_base_url, method])
- end
-
- def put_file_endpoint do
- get_final_url("/api/v0/add")
- end
-
- def delete_file_endpoint do
- get_final_url("/api/v0/files/rm")
- end
-
@placeholder "{CID}"
def placeholder, do: @placeholder
@@ -40,26 +27,26 @@ def get_file(file) do
end
@impl true
- def put_file(%Pleroma.Upload{} = upload) do
+ def put_file(%Pleroma.Upload{tempfile: tempfile}) do
mp =
Multipart.new()
|> Multipart.add_content_type_param("charset=utf-8")
- |> Multipart.add_file(upload.tempfile)
+ |> Multipart.add_file(tempfile)
- case Pleroma.HTTP.post(put_file_endpoint(), mp, [], params: ["cid-version": "1"]) do
- {:ok, ret} ->
- case Jason.decode(ret.body) do
- {:ok, ret} ->
- if Map.has_key?(ret, "Hash") do
- {:ok, {:file, ret["Hash"]}}
- else
- {:error, "JSON doesn't contain Hash key"}
- end
+ endpoint = ipfs_endpoint(@api_add)
- error ->
- Logger.error("#{__MODULE__}: #{inspect(error)}")
- {:error, "JSON decode failed"}
- end
+ with {:ok, %{body: body}} when is_binary(body) <-
+ Pleroma.HTTP.post(endpoint, mp, [], params: ["cid-version": "1"], pool: :upload),
+ {_, {:ok, decoded}} <- {:json, Jason.decode(body)},
+ {_, true} <- {:hash, Map.has_key?(decoded, "Hash")} do
+ {:ok, {:file, decoded["Hash"]}}
+ else
+ {:hash, false} ->
+ {:error, "JSON doesn't contain Hash key"}
+
+ {:json, error} ->
+ Logger.error("#{__MODULE__}: #{inspect(error)}")
+ {:error, "JSON decode failed"}
error ->
Logger.error("#{__MODULE__}: #{inspect(error)}")
@@ -69,9 +56,17 @@ def put_file(%Pleroma.Upload{} = upload) do
@impl true
def delete_file(file) do
- case Pleroma.HTTP.post(delete_file_endpoint(), "", [], params: [arg: file]) do
+ endpoint = ipfs_endpoint(@api_delete)
+
+ case Pleroma.HTTP.post(endpoint, "", [], params: [arg: file]) do
{:ok, %{status: 204}} -> :ok
error -> {:error, inspect(error)}
end
end
+
+ defp ipfs_endpoint(path) do
+ URI.parse(@config_impl.get([__MODULE__, :post_gateway_url]))
+ |> Map.put(:path, path)
+ |> URI.to_string()
+ end
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 8e0cd71ebf..f15dfbed39 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -40,6 +40,7 @@ defmodule Pleroma.User do
alias Pleroma.Web.RelMe
alias Pleroma.Webhook.Notify
alias Pleroma.Workers.BackgroundWorker
+ alias Pleroma.Workers.UserRefreshWorker
require Logger
require Pleroma.Constants
@@ -2108,7 +2109,8 @@ defp verify_field_link(field, profile_urls) do
%{scheme: scheme, userinfo: nil, host: host}
when not_empty_string(host) and scheme in ["http", "https"] <-
URI.parse(value),
- {:not_idn, true} <- {:not_idn, to_string(:idna.encode(host)) == host},
+ {:not_idn, true} <-
+ {:not_idn, match?(^host, to_string(:idna.encode(to_charlist(host))))},
"me" <- Pleroma.Web.RelMe.maybe_put_rel_me(value, profile_urls) do
CommonUtils.to_masto_date(NaiveDateTime.utc_now())
else
@@ -2208,20 +2210,20 @@ def html_filter_policy(_), do: Config.get([:markup, :scrub_policy])
def fetch_by_ap_id(ap_id), do: ActivityPub.make_user_from_ap_id(ap_id)
+ @spec get_or_fetch_by_ap_id(String.t()) :: {:ok, User.t()} | {:error, any()}
def get_or_fetch_by_ap_id(ap_id) do
- cached_user = get_cached_by_ap_id(ap_id)
+ with cached_user = %User{} <- get_cached_by_ap_id(ap_id),
+ _ <- maybe_refresh(cached_user) do
+ {:ok, cached_user}
+ else
+ _ -> fetch_by_ap_id(ap_id)
+ end
+ end
- maybe_fetched_user = needs_update?(cached_user) && fetch_by_ap_id(ap_id)
-
- case {cached_user, maybe_fetched_user} do
- {_, {:ok, %User{} = user}} ->
- {:ok, user}
-
- {%User{} = user, _} ->
- {:ok, user}
-
- _ ->
- {:error, :not_found}
+ defp maybe_refresh(user) do
+ if needs_update?(user) do
+ UserRefreshWorker.new(%{"ap_id" => user.ap_id})
+ |> Oban.insert()
end
end
@@ -2782,7 +2784,7 @@ defp add_to_block(%User{} = user, %User{} = blocked) do
end
end
- @spec add_to_block(User.t(), User.t()) ::
+ @spec remove_from_block(User.t(), User.t()) ::
{:ok, UserRelationship.t()} | {:ok, nil} | {:error, Ecto.Changeset.t()}
defp remove_from_block(%User{} = user, %User{} = blocked) do
with {:ok, relationship} <- UserRelationship.delete_block(user, blocked) do
diff --git a/lib/pleroma/user/backup.ex b/lib/pleroma/user/backup.ex
index 9f4688ff2f..7db415a458 100644
--- a/lib/pleroma/user/backup.ex
+++ b/lib/pleroma/user/backup.ex
@@ -198,14 +198,14 @@ defp wait_backup(backup, current_processed, task) do
end
@files [
- 'actor.json',
- 'outbox.json',
- 'likes.json',
- 'bookmarks.json',
- 'followers.json',
- 'following.json',
- 'chats.json',
- 'chat_messages.json'
+ ~c"actor.json",
+ ~c"outbox.json",
+ ~c"likes.json",
+ ~c"bookmarks.json",
+ ~c"followers.json",
+ ~c"following.json",
+ ~c"chats.json",
+ ~c"chat_messages.json"
]
@spec export(Pleroma.User.Backup.t(), pid()) :: {:ok, String.t()} | :error
def export(%__MODULE__{} = backup, caller_pid) do
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 558f3a181a..3e647a677f 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -1937,24 +1937,25 @@ def fetch_and_prepare_featured_from_ap_id(ap_id) do
end
end
- def pinned_fetch_task(nil), do: nil
-
- def pinned_fetch_task(%{pinned_objects: pins}) do
- if Enum.all?(pins, fn {ap_id, _} ->
- Object.get_cached_by_ap_id(ap_id) ||
- match?({:ok, _object}, Fetcher.fetch_object_from_id(ap_id))
- end) do
- :ok
- else
- :error
- end
+ def enqueue_pin_fetches(%{pinned_objects: pins}) do
+ # enqueue a task to fetch all pinned objects
+ Enum.each(pins, fn {ap_id, _} ->
+ if is_nil(Object.get_cached_by_ap_id(ap_id)) do
+ Pleroma.Workers.RemoteFetcherWorker.enqueue("fetch_remote", %{
+ "id" => ap_id,
+ "depth" => 1
+ })
+ end
+ end)
end
+ def enqueue_pin_fetches(_), do: nil
+
def make_user_from_ap_id(ap_id, additional \\ []) do
user = User.get_cached_by_ap_id(ap_id)
with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id, additional) do
- {:ok, _pid} = Task.start(fn -> pinned_fetch_task(data) end)
+ enqueue_pin_fetches(data)
if user do
user
diff --git a/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex b/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex
index 9543cc5453..7c6bb888f1 100644
--- a/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex
@@ -103,7 +103,11 @@ defp check_rbl(%{host: actor_host}, object) do
{:ok, object}
else
Task.start(fn ->
- reason = rblquery(query, :txt) || "undefined"
+ reason =
+ case rblquery(query, :txt) do
+ [[result]] -> result
+ _ -> "undefined"
+ end
Logger.warning(
"DNSRBL Rejected activity from #{actor_host} for reason: #{inspect(reason)}"
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
index c02d4e3692..ff16f0c7a7 100644
--- a/lib/pleroma/web/activity_pub/side_effects.ex
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -694,9 +694,9 @@ defp delete_object(object) do
with {:ok, _} <- Repo.delete(object), do: :ok
end
- defp send_notifications(meta) do
+ defp stream_notifications(meta) do
Keyword.get(meta, :notifications, [])
- |> Notification.send()
+ |> Notification.stream()
meta
end
@@ -727,7 +727,7 @@ defp add_notifications(meta, notifications) do
@impl true
def handle_after_transaction(meta) do
meta
- |> send_notifications()
+ |> stream_notifications()
|> send_streamables()
end
end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index bb8ba6f046..5f57080d2b 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -928,9 +928,11 @@ def add_emoji_tags(%{"emoji" => emoji} = object) do
def add_emoji_tags(object), do: object
- defp build_emoji_tag({name, url}) do
+ def build_emoji_tag({name, url}) do
+ url = URI.encode(url)
+
%{
- "icon" => %{"url" => "#{URI.encode(url)}", "type" => "Image"},
+ "icon" => %{"url" => "#{url}", "type" => "Image"},
"name" => ":" <> name <> ":",
"type" => "Emoji",
"updated" => "1970-01-01T00:00:00Z",
diff --git a/lib/pleroma/web/api_spec/cast_and_validate.ex b/lib/pleroma/web/api_spec/cast_and_validate.ex
index f3e8e093ed..672d1c4a1f 100644
--- a/lib/pleroma/web/api_spec/cast_and_validate.ex
+++ b/lib/pleroma/web/api_spec/cast_and_validate.ex
@@ -18,6 +18,8 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
alias OpenApiSpex.Plug.PutApiSpec
alias Plug.Conn
+ require Logger
+
@impl Plug
def init(opts) do
opts
@@ -51,6 +53,10 @@ def call(conn, %{operation_id: operation_id, render_error: render_error} = opts)
conn
{:error, reason} ->
+ Logger.error(
+ "Strict ApiSpec: request denied to #{conn.request_path} with params #{inspect(conn.params)}"
+ )
+
opts = render_error.init(reason)
conn
diff --git a/lib/pleroma/web/api_spec/operations/notification_operation.ex b/lib/pleroma/web/api_spec/operations/notification_operation.ex
index 993ea08a90..a0dc81635d 100644
--- a/lib/pleroma/web/api_spec/operations/notification_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/notification_operation.ex
@@ -212,7 +212,9 @@ defp notification_type do
"pleroma:participation_accepted",
"pleroma:participation_request",
"pleroma:event_reminder",
- "pleroma:event_update"
+ "pleroma:event_update",
+ "admin.sign_up",
+ "admin.report"
],
description: """
The type of event that resulted in the notification.
@@ -228,11 +230,13 @@ defp notification_type do
- `pleroma:chat_mention` - Someone mentioned you in a chat message
- `pleroma:report` - Someone was reported
- `status` - Someone you are subscribed to created a status
- - `update` - A status you interacted with was updated
+ - `update` - A status you boosted has been edited
- `pleroma:event_reminder` – An event you are participating in or created is taking place soon
- `pleroma:event_update` – An event you are participating in was edited
- `pleroma:participation_request - Someone wants to participate in your event
- `pleroma:participation_accepted - Your event participation request was accepted
+ - `admin.sign_up` - Someone signed up (optionally sent to admins)
+ - `admin.report` - A new report has been filed
"""
}
end
diff --git a/lib/pleroma/web/api_spec/operations/search_operation.ex b/lib/pleroma/web/api_spec/operations/search_operation.ex
index d244fec6ac..174c70f36d 100644
--- a/lib/pleroma/web/api_spec/operations/search_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/search_operation.ex
@@ -79,7 +79,9 @@ def search_operation do
%Schema{type: :string, enum: ["accounts", "hashtags", "statuses"]},
"Search type"
),
- Operation.parameter(:q, :query, %Schema{type: :string}, "The search query", required: true),
+ Operation.parameter(:q, :query, %Schema{type: :string}, "The search query",
+ required: true
+ ),
Operation.parameter(
:resolve,
:query,
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index e8cd4491ca..17ffd820d9 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -110,7 +110,7 @@ defp register_user(connection, base, uid, name) do
}
params =
- case List.keyfind(attributes, 'mail', 0) do
+ case List.keyfind(attributes, ~c"mail", 0) do
{_, [mail]} -> Map.put_new(params, :email, :erlang.list_to_binary(mail))
_ -> params
end
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 7de0741d67..d40042ea74 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -31,7 +31,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
# pagination is restricted to 40 activities at a time
defp fetch_rich_media_for_activities(activities) do
Enum.each(activities, fn activity ->
- spawn(fn -> Card.get_by_activity(activity) end)
+ Card.get_by_activity(activity)
end)
end
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index bb27d806df..730295a4ce 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -104,7 +104,7 @@ def handle_info(:ping, state) do
end
def handle_info(:close, state) do
- {:stop, {:closed, 'connection closed by server'}, state}
+ {:stop, {:closed, ~c"connection closed by server"}, state}
end
def handle_info(msg, state) do
diff --git a/lib/pleroma/web/media_proxy.ex b/lib/pleroma/web/media_proxy.ex
index eab37488a8..d5ed559327 100644
--- a/lib/pleroma/web/media_proxy.ex
+++ b/lib/pleroma/web/media_proxy.ex
@@ -75,8 +75,7 @@ def whitelisted?(url) do
%{host: domain} = URI.parse(url)
mediaproxy_whitelist_domains =
- [:media_proxy, :whitelist]
- |> Config.get()
+ Config.get([:media_proxy, :whitelist], [])
|> Kernel.++(["#{Upload.base_url()}"])
|> Enum.map(&maybe_get_domain_from_url/1)
diff --git a/lib/pleroma/web/o_auth/token.ex b/lib/pleroma/web/o_auth/token.ex
index a5ad2e909f..9b1198b428 100644
--- a/lib/pleroma/web/o_auth/token.ex
+++ b/lib/pleroma/web/o_auth/token.ex
@@ -96,7 +96,7 @@ defp put_valid_until(changeset, attrs) do
|> validate_required([:valid_until])
end
- @spec create(App.t(), User.t(), map()) :: {:ok, Token} | {:error, Ecto.Changeset.t()}
+ @spec create(App.t(), User.t(), map()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()}
def create(%App{} = app, %User{} = user, attrs \\ %{}) do
with {:ok, token} <- do_create(app, user, attrs) do
if Pleroma.Config.get([:oauth2, :clean_expired_tokens]) do
diff --git a/lib/pleroma/web/plugs/o_auth_scopes_plug.ex b/lib/pleroma/web/plugs/o_auth_scopes_plug.ex
index faf0fd8c62..08c2f61eab 100644
--- a/lib/pleroma/web/plugs/o_auth_scopes_plug.ex
+++ b/lib/pleroma/web/plugs/o_auth_scopes_plug.ex
@@ -34,7 +34,9 @@ def perform(%Plug.Conn{assigns: assigns} = conn, %{scopes: scopes} = options) do
permissions = Enum.join(missing_scopes, " #{op} ")
error_message =
- dgettext("errors", "Insufficient permissions: %{permissions}.", permissions: permissions)
+ dgettext("errors", "Insufficient permissions: %{permissions}.",
+ permissions: permissions
+ )
conn
|> put_resp_content_type("application/json")
diff --git a/lib/pleroma/web/push.ex b/lib/pleroma/web/push.ex
index 0d43f402e5..d4693f63e4 100644
--- a/lib/pleroma/web/push.ex
+++ b/lib/pleroma/web/push.ex
@@ -20,17 +20,13 @@ def init do
end
def vapid_config do
- Application.get_env(:web_push_encryption, :vapid_details, [])
+ Application.get_env(:web_push_encryption, :vapid_details, nil)
end
- def enabled do
- case vapid_config() do
- [] -> false
- list when is_list(list) -> true
- _ -> false
- end
- end
+ def enabled, do: match?([subject: _, public_key: _, private_key: _], vapid_config())
+ @spec send(Pleroma.Notification.t()) ::
+ {:ok, Oban.Job.t()} | {:error, Oban.Job.changeset() | term()}
def send(notification) do
WebPusherWorker.enqueue("web_push", %{"notification_id" => notification.id})
end
diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex
index 9e68d827b8..d71e134cb1 100644
--- a/lib/pleroma/web/push/impl.ex
+++ b/lib/pleroma/web/push/impl.ex
@@ -16,62 +16,70 @@ defmodule Pleroma.Web.Push.Impl do
require Logger
import Ecto.Query
+ @body_chars 140
@types ["Create", "Follow", "Announce", "Like", "Move", "EmojiReact", "Update"]
- @doc "Performs sending notifications for user subscriptions"
- @spec perform(Notification.t()) :: list(any) | :error | {:error, :unknown_type}
- def perform(
+ @doc "Builds webpush notification payloads for the subscriptions enabled by the receiving user"
+ @spec build(Notification.t()) ::
+ list(%{content: map(), subscription: Subscription.t()}) | []
+ def build(
%{
activity: %{data: %{"type" => activity_type}} = activity,
- user: %User{id: user_id}
+ user_id: user_id
} = notification
)
when activity_type in @types do
- actor = User.get_cached_by_ap_id(notification.activity.data["actor"])
+ notification_actor = User.get_cached_by_ap_id(notification.activity.data["actor"])
+ avatar_url = User.avatar_url(notification_actor)
- mastodon_type = notification.type
- gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
- avatar_url = User.avatar_url(actor)
object = Object.normalize(activity, fetch: false)
user = User.get_cached_by_id(user_id)
direct_conversation_id = Activity.direct_conversation_id(activity, user)
- for subscription <- fetch_subscriptions(user_id),
- Subscription.enabled?(subscription, mastodon_type) do
- %{
- access_token: subscription.token.token,
- notification_id: notification.id,
- notification_type: mastodon_type,
- icon: avatar_url,
- preferred_locale: "en",
- pleroma: %{
- activity_id: notification.activity.id,
- direct_conversation_id: direct_conversation_id
+ subscriptions = fetch_subscriptions(user_id)
+
+ subscriptions
+ |> Enum.filter(&Subscription.enabled?(&1, notification.type))
+ |> Enum.map(fn subscription ->
+ payload =
+ %{
+ access_token: subscription.token.token,
+ notification_id: notification.id,
+ notification_type: notification.type,
+ icon: avatar_url,
+ preferred_locale: "en",
+ pleroma: %{
+ activity_id: notification.activity.id,
+ direct_conversation_id: direct_conversation_id
+ }
}
- }
- |> Map.merge(build_content(notification, actor, object, mastodon_type))
- |> Jason.encode!()
- |> push_message(build_sub(subscription), gcm_api_key, subscription)
- end
- |> (&{:ok, &1}).()
+ |> Map.merge(build_content(notification, notification_actor, object))
+ |> Jason.encode!()
+
+ %{payload: payload, subscription: subscription}
+ end)
end
- def perform(_) do
- Logger.warning("Unknown notification type")
- {:error, :unknown_type}
+ def build(notif) do
+ Logger.warning("WebPush: unknown activity type: #{inspect(notif)}")
+ []
end
- @doc "Push message to web"
- def push_message(body, sub, api_key, subscription) do
- case WebPushEncryption.send_web_push(body, sub, api_key) do
+ @doc "Deliver push notification to the provided webpush subscription"
+ @spec deliver(%{payload: String.t(), subscription: Subscription.t()}) :: :ok | :error
+ def deliver(%{payload: payload, subscription: subscription}) do
+ gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
+ formatted_subscription = build_sub(subscription)
+
+ case WebPushEncryption.send_web_push(payload, formatted_subscription, gcm_api_key) do
+ {:ok, %{status: code}} when code in 200..299 ->
+ :ok
+
{:ok, %{status: code}} when code in 400..499 ->
Logger.debug("Removing subscription record")
Repo.delete!(subscription)
:ok
- {:ok, %{status: code}} when code in 200..299 ->
- :ok
-
{:ok, %{status: code}} ->
Logger.error("Web Push Notification failed with code: #{code}")
:error
@@ -100,107 +108,106 @@ def build_sub(subscription) do
}
end
- def build_content(notification, actor, object, mastodon_type \\ nil)
-
def build_content(
%{
user: %{notification_settings: %{hide_notification_contents: true}}
} = notification,
- _actor,
- _object,
- mastodon_type
+ _user,
+ _object
) do
- %{body: format_title(notification, mastodon_type)}
+ %{body: format_title(notification)}
end
- def build_content(notification, actor, object, mastodon_type) do
- mastodon_type = mastodon_type || notification.type
-
+ def build_content(notification, user, object) do
%{
- title: format_title(notification, mastodon_type),
- body: format_body(notification, actor, object, mastodon_type)
+ title: format_title(notification),
+ body: format_body(notification, user, object)
}
end
- def format_body(activity, actor, object, mastodon_type \\ nil)
-
- def format_body(_activity, actor, %{data: %{"type" => "ChatMessage"} = data}, _) do
- case data["content"] do
- nil -> "@#{actor.nickname}: (Attachment)"
- content -> "@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
+ @spec format_body(Notification.t(), User.t(), Object.t()) :: String.t()
+ def format_body(_notification, user, %{data: %{"type" => "ChatMessage"} = object}) do
+ case object["content"] do
+ nil -> "@#{user.nickname}: (Attachment)"
+ content -> "@#{user.nickname}: #{Utils.scrub_html_and_truncate(content, @body_chars)}"
end
end
def format_body(
- %{activity: %{data: %{"type" => "Create"}}},
- actor,
- %{data: %{"content" => content}},
- _mastodon_type
+ %{type: "poll"} = _notification,
+ _user,
+ %{data: %{"content" => content} = data} = _object
) do
- "@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
+ options = Map.get(data, "anyOf") || Map.get(data, "oneOf")
+
+ content_text = content <> "\n"
+
+ options_text = Enum.map_join(options, "\n", fn x -> "○ #{x["name"]}" end)
+
+ [content_text, options_text]
+ |> Enum.join("\n")
+ |> Utils.scrub_html_and_truncate(@body_chars)
+ end
+
+ def format_body(
+ %{activity: %{data: %{"type" => "Create"}}},
+ user,
+ %{data: %{"content" => content}}
+ ) do
+ "@#{user.nickname}: #{Utils.scrub_html_and_truncate(content, @body_chars)}"
end
def format_body(
%{activity: %{data: %{"type" => "Announce"}}},
- actor,
- %{data: %{"content" => content}},
- _mastodon_type
+ user,
+ %{data: %{"content" => content}}
) do
- "@#{actor.nickname} repeated: #{Utils.scrub_html_and_truncate(content, 80)}"
+ "@#{user.nickname} repeated: #{Utils.scrub_html_and_truncate(content, @body_chars)}"
end
def format_body(
%{activity: %{data: %{"type" => "EmojiReact", "content" => content}}},
- actor,
- _object,
- _mastodon_type
+ user,
+ _object
) do
- "@#{actor.nickname} reacted with #{content}"
+ "@#{user.nickname} reacted with #{content}"
end
def format_body(
%{activity: %{data: %{"type" => type}}} = notification,
- actor,
- _object,
- mastodon_type
+ user,
+ _object
)
when type in ["Follow", "Like"] do
- mastodon_type = mastodon_type || notification.type
-
- case mastodon_type do
- "follow" -> "@#{actor.nickname} has followed you"
- "follow_request" -> "@#{actor.nickname} has requested to follow you"
- "favourite" -> "@#{actor.nickname} has favorited your post"
+ case notification.type do
+ "follow" -> "@#{user.nickname} has followed you"
+ "follow_request" -> "@#{user.nickname} has requested to follow you"
+ "favourite" -> "@#{user.nickname} has favorited your post"
end
end
def format_body(
%{activity: %{data: %{"type" => "Update"}}},
- actor,
- _object,
- _mastodon_type
+ user,
+ _object
) do
- "@#{actor.nickname} edited a status"
+ "@#{user.nickname} edited a status"
end
- def format_title(activity, mastodon_type \\ nil)
-
- def format_title(%{activity: %{data: %{"directMessage" => true}}}, _mastodon_type) do
+ @spec format_title(Notification.t()) :: String.t()
+ def format_title(%{activity: %{data: %{"directMessage" => true}}}) do
"New Direct Message"
end
- def format_title(%{type: type}, mastodon_type) do
- case mastodon_type || type do
- "mention" -> "New Mention"
- "status" -> "New Status"
- "follow" -> "New Follower"
- "follow_request" -> "New Follow Request"
- "reblog" -> "New Repeat"
- "favourite" -> "New Favorite"
- "update" -> "New Update"
- "pleroma:chat_mention" -> "New Chat Message"
- "pleroma:emoji_reaction" -> "New Reaction"
- type -> "New #{String.capitalize(type || "event")}"
- end
- end
+ def format_title(%{type: "mention"}), do: "New Mention"
+ def format_title(%{type: "status"}), do: "New Status"
+ def format_title(%{type: "follow"}), do: "New Follower"
+ def format_title(%{type: "follow_request"}), do: "New Follow Request"
+ def format_title(%{type: "reblog"}), do: "New Repeat"
+ def format_title(%{type: "favourite"}), do: "New Favorite"
+ def format_title(%{type: "update"}), do: "New Update"
+ def format_title(%{type: "pleroma:chat_mention"}), do: "New Chat Message"
+ def format_title(%{type: "pleroma:emoji_reaction"}), do: "New Reaction"
+ def format_title(%{type: "poll"}), do: "Poll Results"
+ def format_title(%{type: type}), do: "New #{String.capitalize(type || "event")}"
end
diff --git a/lib/pleroma/web/rich_media/backfill.ex b/lib/pleroma/web/rich_media/backfill.ex
index 4ec50e1329..1d8cc87d45 100644
--- a/lib/pleroma/web/rich_media/backfill.ex
+++ b/lib/pleroma/web/rich_media/backfill.ex
@@ -6,35 +6,25 @@ defmodule Pleroma.Web.RichMedia.Backfill do
alias Pleroma.Web.RichMedia.Card
alias Pleroma.Web.RichMedia.Parser
alias Pleroma.Web.RichMedia.Parser.TTL
- alias Pleroma.Workers.RichMediaExpirationWorker
+ alias Pleroma.Workers.RichMediaWorker
require Logger
- @backfiller Pleroma.Config.get([__MODULE__, :provider], Pleroma.Web.RichMedia.Backfill.Task)
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
- @max_attempts 3
- @retry 5_000
- def start(%{url: url} = args) when is_binary(url) do
+ @spec run(map()) ::
+ :ok | {:error, {:invalid_metadata, any()} | :body_too_large | {:content, any()} | any()}
+ def run(%{"url" => url} = args) do
url_hash = Card.url_to_hash(url)
- args =
- args
- |> Map.put(:attempt, 1)
- |> Map.put(:url_hash, url_hash)
-
- @backfiller.run(args)
- end
-
- def run(%{url: url, url_hash: url_hash, attempt: attempt} = args)
- when attempt <= @max_attempts do
case Parser.parse(url) do
{:ok, fields} ->
{:ok, card} = Card.create(url, fields)
maybe_schedule_expiration(url, fields)
- if Map.has_key?(args, :activity_id) do
+ with %{"activity_id" => activity_id} <- args,
+ false <- is_nil(activity_id) do
stream_update(args)
end
@@ -54,25 +44,16 @@ def run(%{url: url, url_hash: url_hash, attempt: attempt} = args)
e ->
Logger.debug("Rich media error for #{url}: #{inspect(e)}")
-
- :timer.sleep(@retry * attempt)
-
- run(%{args | attempt: attempt + 1})
+ {:error, e}
end
end
- def run(%{url: url, url_hash: url_hash}) do
- Logger.debug("Rich media failure for #{url}")
-
- negative_cache(url_hash, :timer.minutes(15))
- end
-
defp maybe_schedule_expiration(url, fields) do
case TTL.process(fields, url) do
{:ok, ttl} when is_number(ttl) ->
timestamp = DateTime.from_unix!(ttl)
- RichMediaExpirationWorker.new(%{"url" => url}, scheduled_at: timestamp)
+ RichMediaWorker.new(%{"op" => "expire", "url" => url}, scheduled_at: timestamp)
|> Oban.insert()
_ ->
@@ -80,22 +61,14 @@ defp maybe_schedule_expiration(url, fields) do
end
end
- defp stream_update(%{activity_id: activity_id}) do
+ defp stream_update(%{"activity_id" => activity_id}) do
Pleroma.Activity.get_by_id(activity_id)
|> Pleroma.Activity.normalize()
|> Pleroma.Web.ActivityPub.ActivityPub.stream_out()
end
defp warm_cache(key, val), do: @cachex.put(:rich_media_cache, key, val)
- defp negative_cache(key, ttl \\ nil), do: @cachex.put(:rich_media_cache, key, nil, ttl: ttl)
-end
-defmodule Pleroma.Web.RichMedia.Backfill.Task do
- alias Pleroma.Web.RichMedia.Backfill
-
- def run(args) do
- Task.Supervisor.start_child(Pleroma.TaskSupervisor, Backfill, :run, [args],
- name: {:global, {:rich_media, args.url_hash}}
- )
- end
+ defp negative_cache(key, ttl \\ :timer.minutes(15)),
+ do: @cachex.put(:rich_media_cache, key, nil, ttl: ttl)
end
diff --git a/lib/pleroma/web/rich_media/card.ex b/lib/pleroma/web/rich_media/card.ex
index 36a1ae44ae..72ff5e791e 100644
--- a/lib/pleroma/web/rich_media/card.ex
+++ b/lib/pleroma/web/rich_media/card.ex
@@ -7,8 +7,8 @@ defmodule Pleroma.Web.RichMedia.Card do
alias Pleroma.HTML
alias Pleroma.Object
alias Pleroma.Repo
- alias Pleroma.Web.RichMedia.Backfill
alias Pleroma.Web.RichMedia.Parser
+ alias Pleroma.Workers.RichMediaWorker
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
@config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
@@ -75,21 +75,26 @@ def get_by_url(url) when is_binary(url) do
def get_by_url(nil), do: nil
- @spec get_or_backfill_by_url(String.t(), map()) :: t() | nil
- def get_or_backfill_by_url(url, backfill_opts \\ %{}) do
- case get_by_url(url) do
- %__MODULE__{} = card ->
- card
+ @spec get_or_backfill_by_url(String.t(), keyword()) :: t() | nil
+ def get_or_backfill_by_url(url, opts \\ []) do
+ if @config_impl.get([:rich_media, :enabled]) do
+ case get_by_url(url) do
+ %__MODULE__{} = card ->
+ card
- nil ->
- backfill_opts = Map.put(backfill_opts, :url, url)
+ nil ->
+ activity_id = Keyword.get(opts, :activity, nil)
- Backfill.start(backfill_opts)
+ RichMediaWorker.new(%{"op" => "backfill", "url" => url, "activity_id" => activity_id})
+ |> Oban.insert()
- nil
+ nil
- :error ->
- nil
+ :error ->
+ nil
+ end
+ else
+ nil
end
end
@@ -104,7 +109,8 @@ def get_by_object(object) do
@spec get_by_activity(Activity.t()) :: t() | nil | :error
# Fake/Draft activity
def get_by_activity(%Activity{id: "pleroma:fakeid"} = activity) do
- with %Object{} = object <- Object.normalize(activity, fetch: false),
+ with {_, true} <- {:config, @config_impl.get([:rich_media, :enabled])},
+ %Object{} = object <- Object.normalize(activity, fetch: false),
url when not is_nil(url) <- HTML.extract_first_external_url_from_object(object) do
case get_by_url(url) do
# Cache hit
@@ -132,7 +138,7 @@ def get_by_activity(activity) do
nil
else
{:cached, url} ->
- get_or_backfill_by_url(url, %{activity_id: activity.id})
+ get_or_backfill_by_url(url, activity_id: activity.id)
_ ->
:error
diff --git a/lib/pleroma/web/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex
index 37cf29029b..7f6b5d388a 100644
--- a/lib/pleroma/web/rich_media/parser.ex
+++ b/lib/pleroma/web/rich_media/parser.ex
@@ -15,10 +15,14 @@ def parse(nil), do: nil
@spec parse(String.t()) :: {:ok, map()} | {:error, any()}
def parse(url) do
- with :ok <- validate_page_url(url),
+ with {_, true} <- {:config, @config_impl.get([:rich_media, :enabled])},
+ :ok <- validate_page_url(url),
{:ok, data} <- parse_url(url) do
data = Map.put(data, "url", url)
{:ok, data}
+ else
+ {:config, _} -> {:error, :rich_media_disabled}
+ e -> e
end
end
diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
index e9dfb2f054..81aac3d47a 100644
--- a/lib/pleroma/web/streamer.ex
+++ b/lib/pleroma/web/streamer.ex
@@ -173,7 +173,13 @@ def remove_socket(topic) do
def stream(topics, items) do
if should_env_send?() do
for topic <- List.wrap(topics), item <- List.wrap(items) do
- spawn(fn -> do_stream(topic, item) end)
+ fun = fn -> do_stream(topic, item) end
+
+ if Config.get([__MODULE__, :sync_streaming], false) do
+ fun.()
+ else
+ spawn(fun)
+ end
end
end
end
diff --git a/lib/pleroma/web/xml.ex b/lib/pleroma/web/xml.ex
index ccbab601a6..6e1d31934f 100644
--- a/lib/pleroma/web/xml.ex
+++ b/lib/pleroma/web/xml.ex
@@ -9,7 +9,7 @@ def string_from_xpath(_, :error), do: nil
def string_from_xpath(xpath, doc) do
try do
- {:xmlObj, :string, res} = :xmerl_xpath.string('string(#{xpath})', doc)
+ {:xmlObj, :string, res} = :xmerl_xpath.string(~c"string(#{xpath})", doc)
res =
res
diff --git a/lib/pleroma/workers/notification_worker.ex b/lib/pleroma/workers/notification_worker.ex
index 92ac7a033e..7c77dd2651 100644
--- a/lib/pleroma/workers/notification_worker.ex
+++ b/lib/pleroma/workers/notification_worker.ex
@@ -16,7 +16,7 @@ defmodule Pleroma.Workers.NotificationWorker do
def perform(%Job{args: %{"op" => "create", "activity_id" => activity_id}}) do
with %Activity{} = activity <- find_activity(activity_id),
{:ok, notifications} <- Notification.create_notifications(activity) do
- Notification.send(notifications)
+ Notification.stream(notifications)
end
end
diff --git a/lib/pleroma/workers/poll_worker.ex b/lib/pleroma/workers/poll_worker.ex
index 70df541931..3fcac9bc3d 100644
--- a/lib/pleroma/workers/poll_worker.ex
+++ b/lib/pleroma/workers/poll_worker.ex
@@ -14,8 +14,9 @@ defmodule Pleroma.Workers.PollWorker do
@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)
+ with %Activity{} = activity <- find_poll_activity(activity_id),
+ {:ok, notifications} <- Notification.create_poll_notifications(activity) do
+ Notification.stream(notifications)
end
end
diff --git a/lib/pleroma/workers/rich_media_expiration_worker.ex b/lib/pleroma/workers/rich_media_expiration_worker.ex
deleted file mode 100644
index 0b74687cfd..0000000000
--- a/lib/pleroma/workers/rich_media_expiration_worker.ex
+++ /dev/null
@@ -1,15 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Workers.RichMediaExpirationWorker do
- alias Pleroma.Web.RichMedia.Card
-
- use Oban.Worker,
- queue: :background
-
- @impl Oban.Worker
- def perform(%Job{args: %{"url" => url} = _args}) do
- Card.delete(url)
- end
-end
diff --git a/lib/pleroma/workers/rich_media_worker.ex b/lib/pleroma/workers/rich_media_worker.ex
new file mode 100644
index 0000000000..f18ac658ad
--- /dev/null
+++ b/lib/pleroma/workers/rich_media_worker.ex
@@ -0,0 +1,19 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.RichMediaWorker do
+ alias Pleroma.Web.RichMedia.Backfill
+ alias Pleroma.Web.RichMedia.Card
+
+ use Oban.Worker, queue: :background, max_attempts: 3, unique: [period: 300]
+
+ @impl Oban.Worker
+ def perform(%Job{args: %{"op" => "expire", "url" => url} = _args}) do
+ Card.delete(url)
+ end
+
+ def perform(%Job{args: %{"op" => "backfill", "url" => _url} = args}) do
+ Backfill.run(args)
+ end
+end
diff --git a/lib/pleroma/workers/user_refresh_worker.ex b/lib/pleroma/workers/user_refresh_worker.ex
new file mode 100644
index 0000000000..5842143f8b
--- /dev/null
+++ b/lib/pleroma/workers/user_refresh_worker.ex
@@ -0,0 +1,14 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.UserRefreshWorker do
+ use Pleroma.Workers.WorkerHelper, queue: "background", max_attempts: 1, unique: [period: 300]
+
+ alias Pleroma.User
+
+ @impl Oban.Worker
+ def perform(%Job{args: %{"ap_id" => ap_id}}) do
+ User.fetch_by_ap_id(ap_id)
+ end
+end
diff --git a/lib/pleroma/workers/web_pusher_worker.ex b/lib/pleroma/workers/web_pusher_worker.ex
index 67e84b0c9d..c549d3cd65 100644
--- a/lib/pleroma/workers/web_pusher_worker.ex
+++ b/lib/pleroma/workers/web_pusher_worker.ex
@@ -5,6 +5,7 @@
defmodule Pleroma.Workers.WebPusherWorker do
alias Pleroma.Notification
alias Pleroma.Repo
+ alias Pleroma.Web.Push.Impl
use Pleroma.Workers.WorkerHelper, queue: "web_push"
@@ -15,7 +16,8 @@ def perform(%Job{args: %{"op" => "web_push", "notification_id" => notification_i
|> Repo.get(notification_id)
|> Repo.preload([:activity, :user])
- Pleroma.Web.Push.Impl.perform(notification)
+ Impl.build(notification)
+ |> Enum.each(&Impl.deliver(&1))
end
@impl Oban.Worker
diff --git a/mix.exs b/mix.exs
index 295bdbb402..fe95315fe7 100644
--- a/mix.exs
+++ b/mix.exs
@@ -12,7 +12,7 @@ def project do
elixir: "~> 1.13",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: Mix.compilers(),
- elixirc_options: [warnings_as_errors: warnings_as_errors()],
+ elixirc_options: [warnings_as_errors: warnings_as_errors(), prune_code_paths: false],
xref: [exclude: [:eldap]],
dialyzer: [plt_add_apps: [:mix, :eldap]],
start_permanent: Mix.env() == :prod,
@@ -75,14 +75,15 @@ def copy_nginx_config(%{path: target_path} = release) do
def application do
[
mod: {Pleroma.Application, []},
- extra_applications: [
- :logger,
- :runtime_tools,
- :comeonin,
- :fast_sanitize,
- :os_mon,
- :ssl
- ],
+ extra_applications:
+ [
+ :logger,
+ :runtime_tools,
+ :comeonin,
+ :fast_sanitize,
+ :os_mon,
+ :ssl
+ ] ++ logger_application(),
included_applications: [:ex_syslogger]
]
end
@@ -111,6 +112,22 @@ defp oauth_deps do
for s <- oauth_strategy_packages, do: {String.to_atom(s), ">= 0.0.0"}
end
+ defp logger_application do
+ if Version.match?(System.version(), "<1.15.0-rc.0") do
+ []
+ else
+ [:logger_backends]
+ end
+ end
+
+ defp logger_deps do
+ if Version.match?(System.version(), "<1.15.0-rc.0") do
+ []
+ else
+ [{:logger_backends, "~> 1.0"}]
+ end
+ end
+
# Specifies your project dependencies.
#
# Type `mix help deps` for examples and options.
@@ -123,15 +140,13 @@ defp deps do
{:ecto_enum, "~> 1.4"},
{:postgrex, ">= 0.15.5"},
{:phoenix_html, "~> 3.3"},
- {:phoenix_live_reload, "~> 1.3.3", only: :dev},
{:phoenix_live_view, "~> 0.19.0"},
{:phoenix_live_dashboard, "~> 0.8.0"},
{:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"},
{:tzdata, "~> 1.0.3"},
- {:plug_cowboy, "~> 2.6.1"},
- # oban 2.14 requires Elixir 1.12+
- {:oban, "~> 2.13.4"},
+ {:plug_cowboy, "~> 2.5"},
+ {:oban, "~> 2.17.9"},
{:gettext, "~> 0.20"},
{:bcrypt_elixir, "~> 2.2"},
{:fast_sanitize, "~> 0.2.0"},
@@ -150,13 +165,11 @@ defp deps do
{:ex_aws, "~> 2.1.6"},
{:ex_aws_s3, "~> 2.0"},
{:sweet_xml, "~> 0.7.2"},
- # earmark 1.4.23 requires Elixir 1.12+
- {:earmark, "1.4.22"},
+ {:earmark, "1.4.46"},
{:bbcode_pleroma, "~> 0.2.0"},
{:cors_plug, "~> 2.0"},
{:web_push_encryption, "~> 0.3.1"},
- # swoosh 1.11.2+ requires Elixir 1.12+
- {:swoosh, "~> 1.10.0"},
+ {:swoosh, "~> 1.16.9"},
{:phoenix_swoosh, "~> 1.1"},
{:gen_smtp, "~> 0.13"},
{:ex_syslogger, "~> 1.4"},
@@ -188,14 +201,14 @@ defp deps do
{:vix, "~> 0.26.0"},
{:elixir_make, "~> 0.7.7", override: true},
{:blurhash, "~> 0.1.0", hex: :rinpatch_blurhash},
- {:exile,
- git: "https://github.com/akash-akya/exile.git",
- ref: "be87c33b02a7c3c5d22d2ece01fbd462355b28ef"},
- {:bandit, "~> 1.2"},
+ {:exile, "~> 0.10.0"},
+ {:bandit, "~> 1.5.2"},
+ {:websock_adapter, "~> 0.5.6"},
{:icalendar, "~> 1.1"},
{:geospatial, "~> 0.3.0"},
## dev & test
+ {:phoenix_live_reload, "~> 1.3.3", only: :dev},
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
{:ex_machina, "~> 2.4", only: :test},
{:credo, "~> 1.6", only: [:dev, :test], runtime: false},
@@ -206,7 +219,7 @@ defp deps do
{:websockex, "~> 0.4.3", only: :test},
{:benchee, "~> 1.0", only: :benchmark},
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}
- ] ++ oauth_deps()
+ ] ++ oauth_deps() ++ logger_deps()
end
# Aliases are shortcuts or tasks specific to the current project.
diff --git a/mix.lock b/mix.lock
index 53a5b26d65..cbef0e73b1 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,6 +1,6 @@
%{
"accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm", "11b18c220bcc2eab63b5470c038ef10eb6783bcb1fcdb11aa4137defa5ac1bb8"},
- "bandit": {:hex, :bandit, "1.2.1", "aa485b4ac175065b8e0fb5864ddd5dd7b50d52336b36f61c82f484c3718b3d15", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "27393e590a407f1b7d51c5fee4737f139fe224a30449ce25061eac70f763896b"},
+ "bandit": {:hex, :bandit, "1.5.2", "ed0a41c43a9e529c670d0fd48371db4027e7b80d43b1942893e17deb8bed0540", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "35ddbdce7e8a2a3c6b5093f7299d70832a43ed2f4a1852885a61d334cab1b4ad"},
"base62": {:hex, :base62, "1.2.2", "85c6627eb609317b70f555294045895ffaaeb1758666ab9ef9ca38865b11e629", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "d41336bda8eaa5be197f1e4592400513ee60518e5b9f4dcf38f4b4dae6f377bb"},
"bbcode_pleroma": {:hex, :bbcode_pleroma, "0.2.0", "d36f5bca6e2f62261c45be30fa9b92725c0655ad45c99025cb1c3e28e25803ef", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "19851074419a5fedb4ef49e1f01b30df504bb5dbb6d6adfc135238063bebd1c3"},
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.1", "5114d780459a04f2b4aeef52307de23de961b69e13a5cd98a911e39fda13f420", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "42182d5f46764def15bf9af83739e3bf4ad22661b1c34fc3e88558efced07279"},
@@ -19,9 +19,9 @@
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cors_plug": {:hex, :cors_plug, "2.0.3", "316f806d10316e6d10f09473f19052d20ba0a0ce2a1d910ddf57d663dac402ae", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ee4ae1418e6ce117fc42c2ba3e6cbdca4e95ecd2fe59a05ec6884ca16d469aea"},
"covertool": {:hex, :covertool, "2.0.6", "4a291b4e3449025b0595d8f44c8d7635d4f48f033be2ce88d22a329f36f94a91", [:rebar3], [], "hexpm", "5db3fcd82180d8ea4ad857d4d1ab21a8d31b5aee0d60d2f6c0f9e25a411d1e21"},
- "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
+ "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
- "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"},
+ "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
"credo": {:hex, :credo, "1.7.3", "05bb11eaf2f2b8db370ecaa6a6bda2ec49b2acd5e0418bc106b73b07128c0436", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "35ea675a094c934c22fb1dca3696f3c31f2728ae6ef5a53b5d648c11180a4535"},
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
"crypt": {:git, "https://github.com/msantos/crypt.git", "f75cd55325e33cbea198fb41fe41871392f8fb76", [ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"]},
@@ -31,13 +31,13 @@
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
- "earmark": {:hex, :earmark, "1.4.22", "ea3e45c6359446dc308be0a64ce82a03260d973de7d0625a762e6d352ff57958", [:mix], [{:earmark_parser, "~> 1.4.23", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "1caf5145665a42fd76d5317286b0c171861fb1c04f86ab103dde76868814fdfb"},
+ "earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"},
"earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
"eblurhash": {:git, "https://github.com/zotonic/eblurhash.git", "bc37ceb426ef021ee9927fb249bb93f7059194ab", [ref: "bc37ceb426ef021ee9927fb249bb93f7059194ab"]},
- "ecto": {:hex, :ecto, "3.11.1", "4b4972b717e7ca83d30121b12998f5fcdc62ba0ed4f20fd390f16f3270d85c3e", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ebd3d3772cd0dfcd8d772659e41ed527c28b2a8bde4b00fe03e0463da0f1983b"},
+ "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.15", "0fc29dbae0e444a29bd6abeee4cf3c4c037e692a272478a234a1cc765077dbb1", [:mix], [{:ecto_sql, "~> 3.7", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1 or ~> 4.0.0", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "b6127f3a5c6fc3d84895e4768cc7c199f22b48b67d6c99b13fbf4a374e73f039"},
- "ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"},
+ "ecto_sql": {:hex, :ecto_sql, "3.11.2", "c7cc7f812af571e50b80294dc2e535821b3b795ce8008d07aa5f336591a185a8", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "73c07f995ac17dbf89d3cfaaf688fcefabcd18b7b004ac63b0dc4ef39499ed6b"},
"eimp": {:hex, :eimp, "1.0.14", "fc297f0c7e2700457a95a60c7010a5f1dcb768a083b6d53f49cd94ab95a28f22", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "501133f3112079b92d9e22da8b88bf4f0e13d4d67ae9c15c42c30bd25ceb83b6"},
"elixir_make": {:hex, :elixir_make, "0.7.8", "505026f266552ee5aabca0b9f9c229cbb496c689537c9f922f3eb5431157efc7", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "7a71945b913d37ea89b06966e1342c85cfe549b15e6d6d081e8081c493062c07"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
@@ -49,7 +49,7 @@
"ex_doc": {:hex, :ex_doc, "0.31.1", "8a2355ac42b1cc7b2379da9e40243f2670143721dd50748bf6c3b1184dae2089", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "3178c3a407c557d8343479e1ff117a96fd31bafe52a039079593fb0524ef61b0"},
"ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
"ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
- "exile": {:git, "https://github.com/akash-akya/exile.git", "be87c33b02a7c3c5d22d2ece01fbd462355b28ef", [ref: "be87c33b02a7c3c5d22d2ece01fbd462355b28ef"]},
+ "exile": {:hex, :exile, "0.10.0", "b69e2d27a9af670b0f0a0898addca0eda78f6f5ba95ccfbc9bc6ccdd04925436", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "c62ee8fee565b5ac4a898d0dcd58d2b04fb5eec1655af1ddcc9eb582c6732c33"},
"expo": {:hex, :expo, "0.5.1", "249e826a897cac48f591deba863b26c16682b43711dd15ee86b92f25eafd96d9", [:mix], [], "hexpm", "68a4233b0658a3d12ee00d27d37d856b1ba48607e7ce20fd376958d0ba6ce92b"},
"fast_html": {:hex, :fast_html, "2.2.0", "6c5ef1be087a4ed613b0379c13f815c4d11742b36b67bb52cee7859847c84520", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "064c4f23b4a6168f9187dac8984b056f2c531bb0787f559fd6a8b34b38aefbae"},
"fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"},
@@ -78,6 +78,7 @@
"jose": {:hex, :jose, "1.11.6", "613fda82552128aa6fb804682e3a616f4bc15565a048dabd05b1ebd5827ed965", [:mix, :rebar3], [], "hexpm", "6275cb75504f9c1e60eeacb771adfeee4905a9e182103aa59b53fed651ff9738"},
"jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},
"linkify": {:git, "https://gitlab.com/mkljczk/linkify", "b854b2f1701a5e13dfea50add729a8525a549f64", [branch: "master"]},
+ "logger_backends": {:hex, :logger_backends, "1.0.0", "09c4fad6202e08cb0fbd37f328282f16539aca380f512523ce9472b28edc6bdf", [:mix], [], "hexpm", "1faceb3e7ec3ef66a8f5746c5afd020e63996df6fd4eb8cdb789e5665ae6c9ce"},
"majic": {:hex, :majic, "1.0.0", "37e50648db5f5c2ff0c9fb46454d034d11596c03683807b9fb3850676ffdaab3", [:make, :mix], [{:elixir_make, "~> 0.6.1", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7905858f76650d49695f14ea55cd9aaaee0c6654fa391671d4cf305c275a0a9e"},
"makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"},
@@ -85,19 +86,19 @@
"meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"},
- "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
- "mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"},
+ "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
+ "mint": {:hex, :mint, "1.6.0", "88a4f91cd690508a04ff1c3e28952f322528934be541844d54e0ceb765f01d5e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "3c5ae85d90a5aca0a49c0d8b67360bbe407f3b54f1030a111047ff988e8fefaa"},
"mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
"mock": {:hex, :mock, "0.3.8", "7046a306b71db2488ef54395eeb74df0a7f335a7caca4a3d3875d1fc81c884dd", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "7fa82364c97617d79bb7d15571193fc0c4fe5afd0c932cef09426b3ee6fe2022"},
"mogrify": {:hex, :mogrify, "0.8.0", "3506f3ca3f7b95a155f3b4ef803b5db176f5a0633723e3fe85e0d6399e3b11c8", [:mix], [], "hexpm", "2278d245f07056ea3b586e98801e933695147066fa4cf563f552c1b4f0ff8ad9"},
"mox": {:hex, :mox, "1.1.0", "0f5e399649ce9ab7602f72e718305c0f9cdc351190f72844599545e4996af73c", [:mix], [], "hexpm", "d44474c50be02d5b72131070281a5d3895c0e7a95c780e90bc0cfe712f633a13"},
- "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"},
+ "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
"nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"},
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
"oauth2": {:hex, :oauth2, "0.9.4", "632e8e8826a45e33ac2ea5ac66dcc019ba6bb5a0d2ba77e342d33e3b7b252c6e", [:mix], [{:hackney, "~> 1.7", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "407c6b9f60aa0d01b915e2347dc6be78adca706a37f0c530808942da3b62e7af"},
"oauther": {:hex, :oauther, "1.3.0", "82b399607f0ca9d01c640438b34d74ebd9e4acd716508f868e864537ecdb1f76", [:mix], [], "hexpm", "78eb888ea875c72ca27b0864a6f550bc6ee84f2eeca37b093d3d833fbcaec04e"},
- "oban": {:hex, :oban, "2.13.6", "a0cb1bce3bd393770512231fb5a3695fa19fd3af10d7575bf73f837aee7abf43", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c1c5eb16f377b3cbbf2ea14be24d20e3d91285af9d1ac86260b7c2af5464887"},
+ "oban": {:hex, :oban, "2.17.10", "c3e5bd739b5c3fdc38eba1d43ab270a8c6ca4463bb779b7705c69400b0d87678", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4afd027b8e2bc3c399b54318b4f46ee8c40251fb55a285cb4e38b5363f0ee7c4"},
"octo_fetch": {:hex, :octo_fetch, "0.4.0", "074b5ecbc08be10b05b27e9db08bc20a3060142769436242702931c418695b19", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "cf8be6f40cd519d7000bb4e84adcf661c32e59369ca2827c4e20042eda7a7fc6"},
"open_api_spex": {:hex, :open_api_spex, "3.18.2", "8c855e83bfe8bf81603d919d6e892541eafece3720f34d1700b58024dadde247", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "aa3e6dcfc0ad6a02596b2172662da21c9dd848dac145ea9e603f54e3d81b8d2b"},
"parallel_stream": {:hex, :parallel_stream, "1.0.6", "b967be2b23f0f6787fab7ed681b4c45a215a81481fb62b01a5b750fa8f30f76c", [:mix], [], "hexpm", "639b2e8749e11b87b9eb42f2ad325d161c170b39b288ac8d04c4f31f8f0823eb"},
@@ -113,13 +114,13 @@
"phoenix_swoosh": {:hex, :phoenix_swoosh, "1.2.1", "b74ccaa8046fbc388a62134360ee7d9742d5a8ae74063f34eb050279de7a99e1", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "4000eeba3f9d7d1a6bf56d2bd56733d5cadf41a7f0d8ffe5bb67e7d667e204a2"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
"phoenix_view": {:hex, :phoenix_view, "2.0.3", "4d32c4817fce933693741deeb99ef1392619f942633dde834a5163124813aad3", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "cd34049af41be2c627df99cd4eaa71fc52a328c0c3d8e7d4aa28f880c30e7f64"},
- "plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"},
+ "plug": {:hex, :plug, "1.16.0", "1d07d50cb9bb05097fdf187b31cf087c7297aafc3fed8299aac79c128a707e47", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cbf53aa1f5c4d758a7559c0bd6d59e286c2be0c6a1fac8cc3eee2f638243b93e"},
"plug_cowboy": {:hex, :plug_cowboy, "2.6.2", "753611b23b29231fb916b0cdd96028084b12aff57bfd7b71781bd04b1dbeb5c9", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "951ed2433df22f4c97b85fdb145d4cee561f36b74854d64c06d896d7cd2921a7"},
- "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
+ "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
"plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"},
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
- "postgrex": {:hex, :postgrex, "0.17.4", "5777781f80f53b7c431a001c8dad83ee167bcebcf3a793e3906efff680ab62b3", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "6458f7d5b70652bc81c3ea759f91736c16a31be000f306d3c64bcdfe9a18b3cc"},
+ "postgrex": {:hex, :postgrex, "0.17.5", "0483d054938a8dc069b21bdd636bf56c487404c241ce6c319c1f43588246b281", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "50b8b11afbb2c4095a3ba675b4f055c416d0f3d7de6633a595fc131a828a67eb"},
"pot": {:hex, :pot, "1.0.2", "13abb849139fdc04ab8154986abbcb63bdee5de6ed2ba7e1713527e33df923dd", [:rebar3], [], "hexpm", "78fe127f5a4f5f919d6ea5a2a671827bd53eb9d37e5b4128c0ad3df99856c2e0"},
"prom_ex": {:hex, :prom_ex, "1.9.0", "63e6dda6c05cdeec1f26c48443dcc38ffd2118b3665ae8d2bd0e5b79f2aea03e", [:mix], [{:absinthe, ">= 1.6.0", [hex: :absinthe, repo: "hexpm", optional: true]}, {:broadway, ">= 1.0.2", [hex: :broadway, repo: "hexpm", optional: true]}, {:ecto, ">= 3.5.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:finch, "~> 0.15", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:oban, ">= 2.4.0", [hex: :oban, repo: "hexpm", optional: true]}, {:octo_fetch, "~> 0.3", [hex: :octo_fetch, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.5.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, ">= 0.14.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, ">= 1.12.1", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, "~> 2.5 or ~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry, ">= 1.0.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.0", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: false]}, {:telemetry_poller, "~> 1.0", [hex: :telemetry_poller, repo: "hexpm", optional: false]}], "hexpm", "01f3d4f69ec93068219e686cc65e58a29c42bea5429a8ff4e2121f19db178ee6"},
"prometheus": {:hex, :prometheus, "4.10.0", "792adbf0130ff61b5fa8826f013772af24b6e57b984445c8d602c8a0355704a1", [:mix, :rebar3], [{:quantile_estimator, "~> 0.2.1", [hex: :quantile_estimator, repo: "hexpm", optional: false]}], "hexpm", "2a99bb6dce85e238c7236fde6b0064f9834dc420ddbd962aac4ea2a3c3d59384"},
@@ -137,7 +138,7 @@
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
"sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"},
- "swoosh": {:hex, :swoosh, "1.10.3", "32f1531ee3fe4e82da8175c597bf3692938f8152eb981e0cbf57107b6c5924c1", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8b7167d93047bac6e1a1c367bf7d899cf2e4fea0592ee04a70673548ef6091b9"},
+ "swoosh": {:hex, :swoosh, "1.16.9", "20c6a32ea49136a4c19f538e27739bb5070558c0fa76b8a95f4d5d5ca7d319a1", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.0", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "878b1a7a6c10ebbf725a3349363f48f79c5e3d792eb621643b0d276a38acc0a6"},
"syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
"table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"},
"telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"},
@@ -145,7 +146,7 @@
"telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.2.0", "b583c3f18508f5c5561b674d16cf5d9afd2ea3c04505b7d92baaeac93c1b8260", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "9cba950e1c4733468efbe3f821841f34ac05d28e7af7798622f88ecdbbe63ea3"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
"tesla": {:hex, :tesla, "1.8.0", "d511a4f5c5e42538d97eef7c40ec4f3e44effdc5068206f42ed859e09e51d1fd", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "10501f360cd926a309501287470372af1a6e1cbed0f43949203a4c13300bc79f"},
- "thousand_island": {:hex, :thousand_island, "1.3.2", "bc27f9afba6e1a676dd36507d42e429935a142cf5ee69b8e3f90bff1383943cd", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0e085b93012cd1057b378fce40cbfbf381ff6d957a382bfdd5eca1a98eec2535"},
+ "thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
"timex": {:hex, :timex, "3.7.7", "3ed093cae596a410759104d878ad7b38e78b7c2151c6190340835515d4a46b8a", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "0ec4b09f25fe311321f9fc04144a7e3affe48eb29481d7a5583849b6c4dfa0a7"},
"toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"},
"tz_world": {:hex, :tz_world, "1.3.2", "15d331ad1ff22735dfcc8c98bfc7b2a9fdc17f1f071e31e21cdafe2d9318a300", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:geo, "~> 1.0 or ~> 2.0 or ~> 3.3", [hex: :geo, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d1a345e07b3378c4c902ad54fbd5d54c8c3dd55dba883b7407fe57bcec45ff2a"},
@@ -164,6 +165,6 @@
"vix": {:hex, :vix, "0.26.0", "027f10b6969b759318be84bd0bd8c88af877445e4e41cf96a0460392cea5399c", [:make, :mix], [{:castore, "~> 1.0 or ~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:cc_precompiler, "~> 0.2 or ~> 0.1.4", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.8 or ~> 0.7.3", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}], "hexpm", "71b0a79ae7f199cacfc8e679b0e4ba25ee47dc02e182c5b9097efb29fbe14efd"},
"web_push_encryption": {:hex, :web_push_encryption, "0.3.1", "76d0e7375142dfee67391e7690e89f92578889cbcf2879377900b5620ee4708d", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.1", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "4f82b2e57622fb9337559058e8797cb0df7e7c9790793bdc4e40bc895f70e2a2"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
- "websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"},
+ "websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"},
"websockex": {:hex, :websockex, "0.4.3", "92b7905769c79c6480c02daacaca2ddd49de936d912976a4d3c923723b647bf0", [:mix], [], "hexpm", "95f2e7072b85a3a4cc385602d42115b73ce0b74a9121d0d6dbbf557645ac53e4"},
}
diff --git a/priv/repo/migrations/20180516154905_create_user_trigram_index.exs b/priv/repo/migrations/20180516154905_create_user_trigram_index.exs
index 68878e1e2e..049b101756 100644
--- a/priv/repo/migrations/20180516154905_create_user_trigram_index.exs
+++ b/priv/repo/migrations/20180516154905_create_user_trigram_index.exs
@@ -7,7 +7,10 @@ defmodule Pleroma.Repo.Migrations.CreateUserTrigramIndex do
def change do
create_if_not_exists(
- index(:users, ["(nickname || name) gist_trgm_ops"], name: :users_trigram_index, using: :gist)
+ index(:users, ["(nickname || name) gist_trgm_ops"],
+ name: :users_trigram_index,
+ using: :gist
+ )
)
end
end
diff --git a/priv/repo/migrations/20190118074940_fix_user_trigram_index.exs b/priv/repo/migrations/20190118074940_fix_user_trigram_index.exs
index b0f5238a05..3958ea262c 100644
--- a/priv/repo/migrations/20190118074940_fix_user_trigram_index.exs
+++ b/priv/repo/migrations/20190118074940_fix_user_trigram_index.exs
@@ -20,7 +20,10 @@ def down do
drop_if_exists(index(:users, [], name: :users_trigram_index))
create_if_not_exists(
- index(:users, ["(nickname || name) gist_trgm_ops"], name: :users_trigram_index, using: :gist)
+ index(:users, ["(nickname || name) gist_trgm_ops"],
+ name: :users_trigram_index,
+ using: :gist
+ )
)
end
end
diff --git a/priv/repo/migrations/20190603173419_add_tag_index_to_objects.exs b/priv/repo/migrations/20190603173419_add_tag_index_to_objects.exs
index 00c71e95f8..a3cb17f3b4 100644
--- a/priv/repo/migrations/20190603173419_add_tag_index_to_objects.exs
+++ b/priv/repo/migrations/20190603173419_add_tag_index_to_objects.exs
@@ -7,7 +7,10 @@ defmodule Pleroma.Repo.Migrations.AddTagIndexToObjects do
def change do
drop_if_exists(
- index(:activities, ["(data #> '{\"object\",\"tag\"}')"], using: :gin, name: :activities_tags)
+ index(:activities, ["(data #> '{\"object\",\"tag\"}')"],
+ using: :gin,
+ name: :activities_tags
+ )
)
create_if_not_exists(index(:objects, ["(data->'tag')"], using: :gin, name: :objects_tags))
diff --git a/priv/repo/migrations/20200919182636_remoteip_plug_rename.exs b/priv/repo/migrations/20200919182636_remoteip_plug_rename.exs
index b9a8fd0e16..69627d3d82 100644
--- a/priv/repo/migrations/20200919182636_remoteip_plug_rename.exs
+++ b/priv/repo/migrations/20200919182636_remoteip_plug_rename.exs
@@ -9,7 +9,9 @@ defmodule Pleroma.Repo.Migrations.RemoteipPlugRename do
def up do
config =
- from(c in Pleroma.ConfigDB, where: c.group == ^:pleroma and c.key == ^Pleroma.Plugs.RemoteIp)
+ from(c in Pleroma.ConfigDB,
+ where: c.group == ^:pleroma and c.key == ^Pleroma.Plugs.RemoteIp
+ )
|> Pleroma.Repo.one()
if config do
diff --git a/priv/repo/migrations/20220225164000_add_activity_assigned_account_index.exs b/priv/repo/migrations/20220225164000_add_activity_assigned_account_index.exs
index 565bb3e251..b54daf43db 100644
--- a/priv/repo/migrations/20220225164000_add_activity_assigned_account_index.exs
+++ b/priv/repo/migrations/20220225164000_add_activity_assigned_account_index.exs
@@ -3,7 +3,9 @@ defmodule Pleroma.Repo.Migrations.AddActivityAssignedAccountIndex do
def change do
create_if_not_exists(
- index(:activities, ["(data->>'assigned_account')"], name: :activities_assigned_account_index)
+ index(:activities, ["(data->>'assigned_account')"],
+ name: :activities_assigned_account_index
+ )
)
end
end
diff --git a/priv/repo/migrations/20240530011739_add_missing_foreign_keys.exs b/priv/repo/migrations/20240530011739_add_missing_foreign_keys.exs
new file mode 100644
index 0000000000..158f9701b3
--- /dev/null
+++ b/priv/repo/migrations/20240530011739_add_missing_foreign_keys.exs
@@ -0,0 +1,20 @@
+defmodule Pleroma.Repo.Migrations.AddMissingForeignKeys do
+ use Ecto.Migration
+
+ def change do
+ create_if_not_exists(index(:announcement_read_relationships, :announcement_id))
+ create_if_not_exists(index(:bookmarks, :activity_id))
+ create_if_not_exists(index(:bookmarks, :folder_id))
+ create_if_not_exists(index(:chats, :recipient))
+ create_if_not_exists(index(:mfa_tokens, :authorization_id))
+ create_if_not_exists(index(:mfa_tokens, :user_id))
+ create_if_not_exists(index(:notifications, :activity_id))
+ create_if_not_exists(index(:oauth_authorizations, :app_id))
+ create_if_not_exists(index(:oauth_authorizations, :user_id))
+ create_if_not_exists(index(:password_reset_tokens, :user_id))
+ create_if_not_exists(index(:push_subscriptions, :token_id))
+ create_if_not_exists(index(:report_notes, :activity_id))
+ create_if_not_exists(index(:report_notes, :user_id))
+ create_if_not_exists(index(:user_notes, :target_id))
+ end
+end
diff --git a/priv/repo/migrations/20240608003957_upgrade_oban_jobs_to_v12.exs b/priv/repo/migrations/20240608003957_upgrade_oban_jobs_to_v12.exs
new file mode 100644
index 0000000000..ed5bf4ebb9
--- /dev/null
+++ b/priv/repo/migrations/20240608003957_upgrade_oban_jobs_to_v12.exs
@@ -0,0 +1,7 @@
+defmodule Pleroma.Repo.Migrations.UpgradeObanJobsToV12 do
+ use Ecto.Migration
+
+ def up, do: Oban.Migrations.up(version: 12)
+
+ def down, do: Oban.Migrations.down(version: 12)
+end
diff --git a/priv/repo/migrations/20240619141319_deprecate_config_db_logger.exs b/priv/repo/migrations/20240619141319_deprecate_config_db_logger.exs
new file mode 100644
index 0000000000..19ef0a2bb1
--- /dev/null
+++ b/priv/repo/migrations/20240619141319_deprecate_config_db_logger.exs
@@ -0,0 +1,7 @@
+defmodule Pleroma.Repo.Migrations.DeprecateConfigDBLogger do
+ use Ecto.Migration
+
+ def change do
+ execute("DELETE FROM config WHERE config.group = ':logger'")
+ end
+end
diff --git a/priv/static/adminfe/app.147d87e8.css b/priv/static/adminfe/app.a10ad7b9.css
similarity index 80%
rename from priv/static/adminfe/app.147d87e8.css
rename to priv/static/adminfe/app.a10ad7b9.css
index 2d2ae4f328..9c223973e0 100644
Binary files a/priv/static/adminfe/app.147d87e8.css and b/priv/static/adminfe/app.a10ad7b9.css differ
diff --git a/priv/static/adminfe/chunk-42d5.9ade3c1d.css b/priv/static/adminfe/chunk-0631.387bfc09.css
similarity index 94%
rename from priv/static/adminfe/chunk-42d5.9ade3c1d.css
rename to priv/static/adminfe/chunk-0631.387bfc09.css
index 8dfdc0dcf3..a92c99f776 100644
Binary files a/priv/static/adminfe/chunk-42d5.9ade3c1d.css and b/priv/static/adminfe/chunk-0631.387bfc09.css differ
diff --git a/priv/static/adminfe/chunk-091e.07f692aa.css b/priv/static/adminfe/chunk-091e.07f692aa.css
new file mode 100644
index 0000000000..3fe9fb5e02
Binary files /dev/null and b/priv/static/adminfe/chunk-091e.07f692aa.css differ
diff --git a/priv/static/adminfe/chunk-0c3d.79348811.css b/priv/static/adminfe/chunk-0c3d.79348811.css
deleted file mode 100644
index faf49a8ad9..0000000000
Binary files a/priv/static/adminfe/chunk-0c3d.79348811.css and /dev/null differ
diff --git a/priv/static/adminfe/chunk-0c60.ee394b7b.css b/priv/static/adminfe/chunk-0c60.ee394b7b.css
deleted file mode 100644
index 5182009320..0000000000
Binary files a/priv/static/adminfe/chunk-0c60.ee394b7b.css and /dev/null differ
diff --git a/priv/static/adminfe/chunk-0fa6.d224ff3a.css b/priv/static/adminfe/chunk-0fa6.d224ff3a.css
deleted file mode 100644
index 863f6f4f42..0000000000
Binary files a/priv/static/adminfe/chunk-0fa6.d224ff3a.css and /dev/null differ
diff --git a/priv/static/adminfe/chunk-59e6.07d1d2f0.css b/priv/static/adminfe/chunk-1b9d.9a3b3be3.css
similarity index 53%
rename from priv/static/adminfe/chunk-59e6.07d1d2f0.css
rename to priv/static/adminfe/chunk-1b9d.9a3b3be3.css
index bafdf19ac7..a439edf25d 100644
Binary files a/priv/static/adminfe/chunk-59e6.07d1d2f0.css and b/priv/static/adminfe/chunk-1b9d.9a3b3be3.css differ
diff --git a/priv/static/adminfe/chunk-31b9.abc32430.css b/priv/static/adminfe/chunk-31b9.abc32430.css
deleted file mode 100644
index be4b767649..0000000000
Binary files a/priv/static/adminfe/chunk-31b9.abc32430.css and /dev/null differ
diff --git a/priv/static/adminfe/chunk-33c9.3c0c7538.css b/priv/static/adminfe/chunk-33c9.3c0c7538.css
deleted file mode 100644
index 6b35200b26..0000000000
Binary files a/priv/static/adminfe/chunk-33c9.3c0c7538.css and /dev/null differ
diff --git a/priv/static/adminfe/chunk-3779.8ac501a6.css b/priv/static/adminfe/chunk-3779.8ac501a6.css
new file mode 100644
index 0000000000..bb6a81d114
Binary files /dev/null and b/priv/static/adminfe/chunk-3779.8ac501a6.css differ
diff --git a/priv/static/adminfe/chunk-45ed.fc62bc5c.css b/priv/static/adminfe/chunk-45ed.fc62bc5c.css
deleted file mode 100644
index 2393a696a6..0000000000
Binary files a/priv/static/adminfe/chunk-45ed.fc62bc5c.css and /dev/null differ
diff --git a/priv/static/adminfe/chunk-2be3.846d0d5a.css b/priv/static/adminfe/chunk-4ef6.d70a1827.css
similarity index 94%
rename from priv/static/adminfe/chunk-2be3.846d0d5a.css
rename to priv/static/adminfe/chunk-4ef6.d70a1827.css
index 348f82660a..c08849a649 100644
Binary files a/priv/static/adminfe/chunk-2be3.846d0d5a.css and b/priv/static/adminfe/chunk-4ef6.d70a1827.css differ
diff --git a/priv/static/adminfe/chunk-5290.9a003297.css b/priv/static/adminfe/chunk-5290.9a003297.css
new file mode 100644
index 0000000000..55eaf052fb
Binary files /dev/null and b/priv/static/adminfe/chunk-5290.9a003297.css differ
diff --git a/priv/static/adminfe/chunk-5669.9e91529b.css b/priv/static/adminfe/chunk-5bab.584959de.css
similarity index 100%
rename from priv/static/adminfe/chunk-5669.9e91529b.css
rename to priv/static/adminfe/chunk-5bab.584959de.css
diff --git a/priv/static/adminfe/chunk-68b6.d7a7a7ea.css b/priv/static/adminfe/chunk-60b8.edf55553.css
similarity index 100%
rename from priv/static/adminfe/chunk-68b6.d7a7a7ea.css
rename to priv/static/adminfe/chunk-60b8.edf55553.css
diff --git a/priv/static/adminfe/chunk-2cfa.c090392a.css b/priv/static/adminfe/chunk-6182.b819e481.css
similarity index 89%
rename from priv/static/adminfe/chunk-2cfa.c090392a.css
rename to priv/static/adminfe/chunk-6182.b819e481.css
index a4ab52d510..28fa2dd387 100644
Binary files a/priv/static/adminfe/chunk-2cfa.c090392a.css and b/priv/static/adminfe/chunk-6182.b819e481.css differ
diff --git a/priv/static/adminfe/chunk-7c11.5c2bbb9c.css b/priv/static/adminfe/chunk-6252.3c3f1bdf.css
similarity index 94%
rename from priv/static/adminfe/chunk-7c11.5c2bbb9c.css
rename to priv/static/adminfe/chunk-6252.3c3f1bdf.css
index 5c87df7e13..a59ac3dd53 100644
Binary files a/priv/static/adminfe/chunk-7c11.5c2bbb9c.css and b/priv/static/adminfe/chunk-6252.3c3f1bdf.css differ
diff --git a/priv/static/adminfe/chunk-6816.60ad31eb.css b/priv/static/adminfe/chunk-6816.60ad31eb.css
new file mode 100644
index 0000000000..83e2f0b0e9
Binary files /dev/null and b/priv/static/adminfe/chunk-6816.60ad31eb.css differ
diff --git a/priv/static/adminfe/chunk-4995.ba9a98d5.css b/priv/static/adminfe/chunk-75c1.ca2242fe.css
similarity index 55%
rename from priv/static/adminfe/chunk-4995.ba9a98d5.css
rename to priv/static/adminfe/chunk-75c1.ca2242fe.css
index 6d49f2b5a5..90e4589c13 100644
Binary files a/priv/static/adminfe/chunk-4995.ba9a98d5.css and b/priv/static/adminfe/chunk-75c1.ca2242fe.css differ
diff --git a/priv/static/adminfe/chunk-9bb9.ca31fc42.css b/priv/static/adminfe/chunk-9bb9.ca31fc42.css
new file mode 100644
index 0000000000..a208fcf7a6
Binary files /dev/null and b/priv/static/adminfe/chunk-9bb9.ca31fc42.css differ
diff --git a/priv/static/adminfe/chunk-5cf2.5bf52c8f.css b/priv/static/adminfe/chunk-a296.c175a1b5.css
similarity index 100%
rename from priv/static/adminfe/chunk-5cf2.5bf52c8f.css
rename to priv/static/adminfe/chunk-a296.c175a1b5.css
diff --git a/priv/static/adminfe/chunk-da78.ba246a04.css b/priv/static/adminfe/chunk-da78.ba246a04.css
new file mode 100644
index 0000000000..eb07d612d3
Binary files /dev/null and b/priv/static/adminfe/chunk-da78.ba246a04.css differ
diff --git a/priv/static/adminfe/chunk-1a25.098b6a73.css b/priv/static/adminfe/chunk-e1ce.68ac1ba1.css
similarity index 100%
rename from priv/static/adminfe/chunk-1a25.098b6a73.css
rename to priv/static/adminfe/chunk-e1ce.68ac1ba1.css
diff --git a/priv/static/adminfe/chunk-elementUI.852ab1db.css b/priv/static/adminfe/chunk-elementUI.852ab1db.css
deleted file mode 100644
index cd28ac433b..0000000000
Binary files a/priv/static/adminfe/chunk-elementUI.852ab1db.css and /dev/null differ
diff --git a/priv/static/adminfe/chunk-elementUI.9644454c.css b/priv/static/adminfe/chunk-elementUI.9644454c.css
new file mode 100644
index 0000000000..2bc1b7e54c
Binary files /dev/null and b/priv/static/adminfe/chunk-elementUI.9644454c.css differ
diff --git a/priv/static/adminfe/chunk-305b.64cc20ab.css b/priv/static/adminfe/chunk-f631.16bbd040.css
similarity index 100%
rename from priv/static/adminfe/chunk-305b.64cc20ab.css
rename to priv/static/adminfe/chunk-f631.16bbd040.css
diff --git a/priv/static/adminfe/chunk-libs.0b4a26df.css b/priv/static/adminfe/chunk-libs.3c625040.css
similarity index 100%
rename from priv/static/adminfe/chunk-libs.0b4a26df.css
rename to priv/static/adminfe/chunk-libs.3c625040.css
diff --git a/priv/static/adminfe/index.html b/priv/static/adminfe/index.html
index 4731b1c371..d1ab1fea97 100644
--- a/priv/static/adminfe/index.html
+++ b/priv/static/adminfe/index.html
@@ -1 +1 @@
-
Admin FE
\ No newline at end of file
+Admin FE
\ No newline at end of file
diff --git a/priv/static/adminfe/static/js/7zzA.e1ae1c94.js b/priv/static/adminfe/static/js/7zzA.e1ae1c94.js
deleted file mode 100644
index 526e228f59..0000000000
Binary files a/priv/static/adminfe/static/js/7zzA.e1ae1c94.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/7zzA.e1ae1c94.js.map b/priv/static/adminfe/static/js/7zzA.e1ae1c94.js.map
deleted file mode 100644
index feddfaeeea..0000000000
Binary files a/priv/static/adminfe/static/js/7zzA.e1ae1c94.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/7zzA.ff5424db.js b/priv/static/adminfe/static/js/7zzA.ff5424db.js
new file mode 100644
index 0000000000..87a7c59333
Binary files /dev/null and b/priv/static/adminfe/static/js/7zzA.ff5424db.js differ
diff --git a/priv/static/adminfe/static/js/7zzA.ff5424db.js.map b/priv/static/adminfe/static/js/7zzA.ff5424db.js.map
new file mode 100644
index 0000000000..1fbf118f17
Binary files /dev/null and b/priv/static/adminfe/static/js/7zzA.ff5424db.js.map differ
diff --git a/priv/static/adminfe/static/js/ExVU.af3ef662.js b/priv/static/adminfe/static/js/ExVU.af3ef662.js
new file mode 100644
index 0000000000..d1392a49cd
Binary files /dev/null and b/priv/static/adminfe/static/js/ExVU.af3ef662.js differ
diff --git a/priv/static/adminfe/static/js/ExVU.af3ef662.js.map b/priv/static/adminfe/static/js/ExVU.af3ef662.js.map
new file mode 100644
index 0000000000..1442ea1c16
Binary files /dev/null and b/priv/static/adminfe/static/js/ExVU.af3ef662.js.map differ
diff --git a/priv/static/adminfe/static/js/JEtC.f9ba4594.js b/priv/static/adminfe/static/js/JEtC.1f75b169.js
similarity index 74%
rename from priv/static/adminfe/static/js/JEtC.f9ba4594.js
rename to priv/static/adminfe/static/js/JEtC.1f75b169.js
index 4d7adff7f7..1297bb16ee 100644
Binary files a/priv/static/adminfe/static/js/JEtC.f9ba4594.js and b/priv/static/adminfe/static/js/JEtC.1f75b169.js differ
diff --git a/priv/static/adminfe/static/js/JEtC.1f75b169.js.map b/priv/static/adminfe/static/js/JEtC.1f75b169.js.map
new file mode 100644
index 0000000000..8d3d0e2857
Binary files /dev/null and b/priv/static/adminfe/static/js/JEtC.1f75b169.js.map differ
diff --git a/priv/static/adminfe/static/js/JEtC.f9ba4594.js.map b/priv/static/adminfe/static/js/JEtC.f9ba4594.js.map
deleted file mode 100644
index 9969563567..0000000000
Binary files a/priv/static/adminfe/static/js/JEtC.f9ba4594.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/app.85d71fab.js b/priv/static/adminfe/static/js/app.85d71fab.js
new file mode 100644
index 0000000000..acd3963ac7
Binary files /dev/null and b/priv/static/adminfe/static/js/app.85d71fab.js differ
diff --git a/priv/static/adminfe/static/js/app.85d71fab.js.map b/priv/static/adminfe/static/js/app.85d71fab.js.map
new file mode 100644
index 0000000000..8984da9858
Binary files /dev/null and b/priv/static/adminfe/static/js/app.85d71fab.js.map differ
diff --git a/priv/static/adminfe/static/js/app.c3e187df.js b/priv/static/adminfe/static/js/app.c3e187df.js
deleted file mode 100644
index f9b525594c..0000000000
Binary files a/priv/static/adminfe/static/js/app.c3e187df.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/app.c3e187df.js.map b/priv/static/adminfe/static/js/app.c3e187df.js.map
deleted file mode 100644
index 2c7f69c3b7..0000000000
Binary files a/priv/static/adminfe/static/js/app.c3e187df.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-0631.411af962.js b/priv/static/adminfe/static/js/chunk-0631.411af962.js
new file mode 100644
index 0000000000..a25e62daea
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-0631.411af962.js differ
diff --git a/priv/static/adminfe/static/js/chunk-0631.411af962.js.map b/priv/static/adminfe/static/js/chunk-0631.411af962.js.map
new file mode 100644
index 0000000000..4b5b6e2586
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-0631.411af962.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-091e.555ed3c2.js b/priv/static/adminfe/static/js/chunk-091e.555ed3c2.js
new file mode 100644
index 0000000000..186e652ad8
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-091e.555ed3c2.js differ
diff --git a/priv/static/adminfe/static/js/chunk-091e.555ed3c2.js.map b/priv/static/adminfe/static/js/chunk-091e.555ed3c2.js.map
new file mode 100644
index 0000000000..0cf9388718
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-091e.555ed3c2.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-0ae4.98250589.js b/priv/static/adminfe/static/js/chunk-0ae4.98250589.js
new file mode 100644
index 0000000000..edf7d46340
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-0ae4.98250589.js differ
diff --git a/priv/static/adminfe/static/js/chunk-0ae4.98250589.js.map b/priv/static/adminfe/static/js/chunk-0ae4.98250589.js.map
new file mode 100644
index 0000000000..001f8ed66f
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-0ae4.98250589.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-0c3d.00a00ec3.js b/priv/static/adminfe/static/js/chunk-0c3d.00a00ec3.js
deleted file mode 100644
index 62b001352d..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-0c3d.00a00ec3.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-0c3d.00a00ec3.js.map b/priv/static/adminfe/static/js/chunk-0c3d.00a00ec3.js.map
deleted file mode 100644
index 56069f60fa..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-0c3d.00a00ec3.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-0c60.e0f08810.js b/priv/static/adminfe/static/js/chunk-0c60.e0f08810.js
deleted file mode 100644
index e637ca50a1..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-0c60.e0f08810.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-0c60.e0f08810.js.map b/priv/static/adminfe/static/js/chunk-0c60.e0f08810.js.map
deleted file mode 100644
index 6bcbd1396c..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-0c60.e0f08810.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-0e2d.04760e2c.js b/priv/static/adminfe/static/js/chunk-0e2d.04760e2c.js
deleted file mode 100644
index 713bc62753..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-0e2d.04760e2c.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-0e2d.04760e2c.js.map b/priv/static/adminfe/static/js/chunk-0e2d.04760e2c.js.map
deleted file mode 100644
index 5942e7a757..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-0e2d.04760e2c.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-0fa6.ddd4199e.js b/priv/static/adminfe/static/js/chunk-0fa6.ddd4199e.js
deleted file mode 100644
index beef953845..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-0fa6.ddd4199e.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-0fa6.ddd4199e.js.map b/priv/static/adminfe/static/js/chunk-0fa6.ddd4199e.js.map
deleted file mode 100644
index 6784cdc170..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-0fa6.ddd4199e.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-16d0.7d343bb9.js b/priv/static/adminfe/static/js/chunk-16d0.0db6c24f.js
similarity index 83%
rename from priv/static/adminfe/static/js/chunk-16d0.7d343bb9.js
rename to priv/static/adminfe/static/js/chunk-16d0.0db6c24f.js
index 6e1dac38ad..66f60b565b 100644
Binary files a/priv/static/adminfe/static/js/chunk-16d0.7d343bb9.js and b/priv/static/adminfe/static/js/chunk-16d0.0db6c24f.js differ
diff --git a/priv/static/adminfe/static/js/chunk-16d0.0db6c24f.js.map b/priv/static/adminfe/static/js/chunk-16d0.0db6c24f.js.map
new file mode 100644
index 0000000000..a6053bc42d
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-16d0.0db6c24f.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-16d0.7d343bb9.js.map b/priv/static/adminfe/static/js/chunk-16d0.7d343bb9.js.map
deleted file mode 100644
index 2ec231550a..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-16d0.7d343bb9.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-1a25.107c34e7.js b/priv/static/adminfe/static/js/chunk-1a25.107c34e7.js
deleted file mode 100644
index 1109d36b66..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-1a25.107c34e7.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-1a25.107c34e7.js.map b/priv/static/adminfe/static/js/chunk-1a25.107c34e7.js.map
deleted file mode 100644
index e39649604a..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-1a25.107c34e7.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-1b9d.822ff94d.js b/priv/static/adminfe/static/js/chunk-1b9d.822ff94d.js
new file mode 100644
index 0000000000..9a9254d4b9
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-1b9d.822ff94d.js differ
diff --git a/priv/static/adminfe/static/js/chunk-1b9d.822ff94d.js.map b/priv/static/adminfe/static/js/chunk-1b9d.822ff94d.js.map
new file mode 100644
index 0000000000..8150e399a6
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-1b9d.822ff94d.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-2be3.7b7c045e.js b/priv/static/adminfe/static/js/chunk-2be3.7b7c045e.js
deleted file mode 100644
index 4670071d04..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-2be3.7b7c045e.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-2be3.7b7c045e.js.map b/priv/static/adminfe/static/js/chunk-2be3.7b7c045e.js.map
deleted file mode 100644
index 76cbef240f..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-2be3.7b7c045e.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-2cfa.608c3714.js b/priv/static/adminfe/static/js/chunk-2cfa.608c3714.js
deleted file mode 100644
index e5d39dfae0..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-2cfa.608c3714.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-2cfa.608c3714.js.map b/priv/static/adminfe/static/js/chunk-2cfa.608c3714.js.map
deleted file mode 100644
index b9ffc2f0c4..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-2cfa.608c3714.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-305b.3a7fb27b.js b/priv/static/adminfe/static/js/chunk-305b.3a7fb27b.js
deleted file mode 100644
index 3801c2ad48..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-305b.3a7fb27b.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-305b.3a7fb27b.js.map b/priv/static/adminfe/static/js/chunk-305b.3a7fb27b.js.map
deleted file mode 100644
index e935d010e1..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-305b.3a7fb27b.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-319f.8919d1e7.js b/priv/static/adminfe/static/js/chunk-319f.8919d1e7.js
deleted file mode 100644
index 67c4f0dadf..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-319f.8919d1e7.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-319f.8919d1e7.js.map b/priv/static/adminfe/static/js/chunk-319f.8919d1e7.js.map
deleted file mode 100644
index 92d070e4e4..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-319f.8919d1e7.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-31b9.7b89f7b5.js b/priv/static/adminfe/static/js/chunk-31b9.7b89f7b5.js
deleted file mode 100644
index 6dd253a19d..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-31b9.7b89f7b5.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-31b9.7b89f7b5.js.map b/priv/static/adminfe/static/js/chunk-31b9.7b89f7b5.js.map
deleted file mode 100644
index 92c1fee31d..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-31b9.7b89f7b5.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-33c9.cf3bdd1b.js b/priv/static/adminfe/static/js/chunk-33c9.cf3bdd1b.js
deleted file mode 100644
index e0aa86696e..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-33c9.cf3bdd1b.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-33c9.cf3bdd1b.js.map b/priv/static/adminfe/static/js/chunk-33c9.cf3bdd1b.js.map
deleted file mode 100644
index f6829f3404..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-33c9.cf3bdd1b.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-3779.335bbe02.js b/priv/static/adminfe/static/js/chunk-3779.335bbe02.js
new file mode 100644
index 0000000000..1b644d7b66
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-3779.335bbe02.js differ
diff --git a/priv/static/adminfe/static/js/chunk-3779.335bbe02.js.map b/priv/static/adminfe/static/js/chunk-3779.335bbe02.js.map
new file mode 100644
index 0000000000..0f4251a2f9
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-3779.335bbe02.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-42d5.f83ab775.js b/priv/static/adminfe/static/js/chunk-42d5.f83ab775.js
deleted file mode 100644
index fad2f0b441..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-42d5.f83ab775.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-42d5.f83ab775.js.map b/priv/static/adminfe/static/js/chunk-42d5.f83ab775.js.map
deleted file mode 100644
index b6d1a5db95..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-42d5.f83ab775.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-45ed.10b6b7a7.js b/priv/static/adminfe/static/js/chunk-45ed.10b6b7a7.js
deleted file mode 100644
index ef49eaf11c..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-45ed.10b6b7a7.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-45ed.10b6b7a7.js.map b/priv/static/adminfe/static/js/chunk-45ed.10b6b7a7.js.map
deleted file mode 100644
index 6ed12956cb..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-45ed.10b6b7a7.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-4995.94e052fc.js b/priv/static/adminfe/static/js/chunk-4995.94e052fc.js
deleted file mode 100644
index db3eeb54cc..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-4995.94e052fc.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-4995.94e052fc.js.map b/priv/static/adminfe/static/js/chunk-4995.94e052fc.js.map
deleted file mode 100644
index 3048cc4c54..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-4995.94e052fc.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-4ef6.28755c4f.js b/priv/static/adminfe/static/js/chunk-4ef6.28755c4f.js
new file mode 100644
index 0000000000..7450148833
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-4ef6.28755c4f.js differ
diff --git a/priv/static/adminfe/static/js/chunk-4ef6.28755c4f.js.map b/priv/static/adminfe/static/js/chunk-4ef6.28755c4f.js.map
new file mode 100644
index 0000000000..14d17d1b00
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-4ef6.28755c4f.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-5290.3d44be05.js b/priv/static/adminfe/static/js/chunk-5290.3d44be05.js
new file mode 100644
index 0000000000..a83ef7df81
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-5290.3d44be05.js differ
diff --git a/priv/static/adminfe/static/js/chunk-5290.3d44be05.js.map b/priv/static/adminfe/static/js/chunk-5290.3d44be05.js.map
new file mode 100644
index 0000000000..24cc29eb30
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-5290.3d44be05.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-5669.88725eaa.js b/priv/static/adminfe/static/js/chunk-5669.88725eaa.js
deleted file mode 100644
index 41d9c2adf0..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-5669.88725eaa.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-5669.88725eaa.js.map b/priv/static/adminfe/static/js/chunk-5669.88725eaa.js.map
deleted file mode 100644
index a6aa3d1a3c..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-5669.88725eaa.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-59e6.01e205d8.js b/priv/static/adminfe/static/js/chunk-59e6.01e205d8.js
deleted file mode 100644
index 1262532f35..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-59e6.01e205d8.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-59e6.01e205d8.js.map b/priv/static/adminfe/static/js/chunk-59e6.01e205d8.js.map
deleted file mode 100644
index 417e29f0b5..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-59e6.01e205d8.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-5bab.25c32827.js b/priv/static/adminfe/static/js/chunk-5bab.25c32827.js
new file mode 100644
index 0000000000..d833050caf
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-5bab.25c32827.js differ
diff --git a/priv/static/adminfe/static/js/chunk-5bab.25c32827.js.map b/priv/static/adminfe/static/js/chunk-5bab.25c32827.js.map
new file mode 100644
index 0000000000..4ca4400ebe
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-5bab.25c32827.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-5cf2.a8562f1f.js b/priv/static/adminfe/static/js/chunk-5cf2.a8562f1f.js
deleted file mode 100644
index c639e62160..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-5cf2.a8562f1f.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-5cf2.a8562f1f.js.map b/priv/static/adminfe/static/js/chunk-5cf2.a8562f1f.js.map
deleted file mode 100644
index 1e92102a67..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-5cf2.a8562f1f.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-60b8.1c968f67.js b/priv/static/adminfe/static/js/chunk-60b8.1c968f67.js
new file mode 100644
index 0000000000..5ff902dacc
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-60b8.1c968f67.js differ
diff --git a/priv/static/adminfe/static/js/chunk-60b8.1c968f67.js.map b/priv/static/adminfe/static/js/chunk-60b8.1c968f67.js.map
new file mode 100644
index 0000000000..33000c45eb
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-60b8.1c968f67.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-6182.5c558ab1.js b/priv/static/adminfe/static/js/chunk-6182.5c558ab1.js
new file mode 100644
index 0000000000..23a04680dc
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-6182.5c558ab1.js differ
diff --git a/priv/static/adminfe/static/js/chunk-6182.5c558ab1.js.map b/priv/static/adminfe/static/js/chunk-6182.5c558ab1.js.map
new file mode 100644
index 0000000000..5858f7376d
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-6182.5c558ab1.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-6252.7cd5f91a.js b/priv/static/adminfe/static/js/chunk-6252.7cd5f91a.js
new file mode 100644
index 0000000000..3907f4a4b9
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-6252.7cd5f91a.js differ
diff --git a/priv/static/adminfe/static/js/chunk-6252.7cd5f91a.js.map b/priv/static/adminfe/static/js/chunk-6252.7cd5f91a.js.map
new file mode 100644
index 0000000000..5739bc0228
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-6252.7cd5f91a.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-6816.32dc5cb7.js b/priv/static/adminfe/static/js/chunk-6816.32dc5cb7.js
new file mode 100644
index 0000000000..97c3c9f1e1
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-6816.32dc5cb7.js differ
diff --git a/priv/static/adminfe/static/js/chunk-6816.32dc5cb7.js.map b/priv/static/adminfe/static/js/chunk-6816.32dc5cb7.js.map
new file mode 100644
index 0000000000..fec386ac58
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-6816.32dc5cb7.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-68b6.4347fd87.js b/priv/static/adminfe/static/js/chunk-68b6.4347fd87.js
deleted file mode 100644
index 895f8ce90c..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-68b6.4347fd87.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-68b6.4347fd87.js.map b/priv/static/adminfe/static/js/chunk-68b6.4347fd87.js.map
deleted file mode 100644
index b3441a3989..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-68b6.4347fd87.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-75c1.35b2205f.js b/priv/static/adminfe/static/js/chunk-75c1.35b2205f.js
new file mode 100644
index 0000000000..a7369f3188
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-75c1.35b2205f.js differ
diff --git a/priv/static/adminfe/static/js/chunk-75c1.35b2205f.js.map b/priv/static/adminfe/static/js/chunk-75c1.35b2205f.js.map
new file mode 100644
index 0000000000..efa6cd8947
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-75c1.35b2205f.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-7c11.b858969e.js b/priv/static/adminfe/static/js/chunk-7c11.b858969e.js
deleted file mode 100644
index 01d4eed027..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-7c11.b858969e.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-7c11.b858969e.js.map b/priv/static/adminfe/static/js/chunk-7c11.b858969e.js.map
deleted file mode 100644
index d5609102cb..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-7c11.b858969e.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-9bb9.a09acfdd.js b/priv/static/adminfe/static/js/chunk-9bb9.a09acfdd.js
new file mode 100644
index 0000000000..a509ff7199
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-9bb9.a09acfdd.js differ
diff --git a/priv/static/adminfe/static/js/chunk-9bb9.a09acfdd.js.map b/priv/static/adminfe/static/js/chunk-9bb9.a09acfdd.js.map
new file mode 100644
index 0000000000..1de9dd89b2
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-9bb9.a09acfdd.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-a296.53fd9783.js b/priv/static/adminfe/static/js/chunk-a296.53fd9783.js
new file mode 100644
index 0000000000..16212f99e4
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-a296.53fd9783.js differ
diff --git a/priv/static/adminfe/static/js/chunk-a296.53fd9783.js.map b/priv/static/adminfe/static/js/chunk-a296.53fd9783.js.map
new file mode 100644
index 0000000000..72a5480add
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-a296.53fd9783.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-da78.7530bb4c.js b/priv/static/adminfe/static/js/chunk-da78.7530bb4c.js
new file mode 100644
index 0000000000..3e356771e2
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-da78.7530bb4c.js differ
diff --git a/priv/static/adminfe/static/js/chunk-da78.7530bb4c.js.map b/priv/static/adminfe/static/js/chunk-da78.7530bb4c.js.map
new file mode 100644
index 0000000000..e5f57e843b
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-da78.7530bb4c.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-e1ce.0a535b9b.js b/priv/static/adminfe/static/js/chunk-e1ce.0a535b9b.js
new file mode 100644
index 0000000000..4b62a334f1
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-e1ce.0a535b9b.js differ
diff --git a/priv/static/adminfe/static/js/chunk-e1ce.0a535b9b.js.map b/priv/static/adminfe/static/js/chunk-e1ce.0a535b9b.js.map
new file mode 100644
index 0000000000..799243e28a
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-e1ce.0a535b9b.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-elementUI.bec6fa77.js b/priv/static/adminfe/static/js/chunk-elementUI.bec6fa77.js
deleted file mode 100644
index 155839b11b..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-elementUI.bec6fa77.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-elementUI.bec6fa77.js.map b/priv/static/adminfe/static/js/chunk-elementUI.bec6fa77.js.map
deleted file mode 100644
index 02dca73f45..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-elementUI.bec6fa77.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-elementUI.d02c484d.js b/priv/static/adminfe/static/js/chunk-elementUI.d02c484d.js
new file mode 100644
index 0000000000..6de816bb14
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-elementUI.d02c484d.js differ
diff --git a/priv/static/adminfe/static/js/chunk-elementUI.d02c484d.js.map b/priv/static/adminfe/static/js/chunk-elementUI.d02c484d.js.map
new file mode 100644
index 0000000000..885059d016
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-elementUI.d02c484d.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-f631.50351e52.js b/priv/static/adminfe/static/js/chunk-f631.50351e52.js
new file mode 100644
index 0000000000..e2755eefbd
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-f631.50351e52.js differ
diff --git a/priv/static/adminfe/static/js/chunk-f631.50351e52.js.map b/priv/static/adminfe/static/js/chunk-f631.50351e52.js.map
new file mode 100644
index 0000000000..1cd37e5620
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-f631.50351e52.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-libs.c8fc8a3a.js b/priv/static/adminfe/static/js/chunk-libs.c8fc8a3a.js
new file mode 100644
index 0000000000..b5794d57c6
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-libs.c8fc8a3a.js differ
diff --git a/priv/static/adminfe/static/js/chunk-libs.c8fc8a3a.js.map b/priv/static/adminfe/static/js/chunk-libs.c8fc8a3a.js.map
new file mode 100644
index 0000000000..6082498e3f
Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-libs.c8fc8a3a.js.map differ
diff --git a/priv/static/adminfe/static/js/chunk-libs.eb232bda.js b/priv/static/adminfe/static/js/chunk-libs.eb232bda.js
deleted file mode 100644
index 895a057029..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-libs.eb232bda.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/chunk-libs.eb232bda.js.map b/priv/static/adminfe/static/js/chunk-libs.eb232bda.js.map
deleted file mode 100644
index a3ed4c6887..0000000000
Binary files a/priv/static/adminfe/static/js/chunk-libs.eb232bda.js.map and /dev/null differ
diff --git a/priv/static/adminfe/static/js/oAJy.25bb7cc7.js b/priv/static/adminfe/static/js/oAJy.68007501.js
similarity index 99%
rename from priv/static/adminfe/static/js/oAJy.25bb7cc7.js
rename to priv/static/adminfe/static/js/oAJy.68007501.js
index 1c98c2800e..4a5045832d 100644
Binary files a/priv/static/adminfe/static/js/oAJy.25bb7cc7.js and b/priv/static/adminfe/static/js/oAJy.68007501.js differ
diff --git a/priv/static/adminfe/static/js/oAJy.25bb7cc7.js.map b/priv/static/adminfe/static/js/oAJy.68007501.js.map
similarity index 99%
rename from priv/static/adminfe/static/js/oAJy.25bb7cc7.js.map
rename to priv/static/adminfe/static/js/oAJy.68007501.js.map
index 8ed70c098b..ec80d5796b 100644
Binary files a/priv/static/adminfe/static/js/oAJy.25bb7cc7.js.map and b/priv/static/adminfe/static/js/oAJy.68007501.js.map differ
diff --git a/priv/static/adminfe/static/js/runtime.26323110.js b/priv/static/adminfe/static/js/runtime.26323110.js
new file mode 100644
index 0000000000..2a72f5ae5c
Binary files /dev/null and b/priv/static/adminfe/static/js/runtime.26323110.js differ
diff --git a/priv/static/adminfe/static/js/runtime.26323110.js.map b/priv/static/adminfe/static/js/runtime.26323110.js.map
new file mode 100644
index 0000000000..ab28254619
Binary files /dev/null and b/priv/static/adminfe/static/js/runtime.26323110.js.map differ
diff --git a/priv/static/adminfe/static/js/runtime.f1a41c33.js b/priv/static/adminfe/static/js/runtime.f1a41c33.js
deleted file mode 100644
index f97fa72c89..0000000000
Binary files a/priv/static/adminfe/static/js/runtime.f1a41c33.js and /dev/null differ
diff --git a/priv/static/adminfe/static/js/runtime.f1a41c33.js.map b/priv/static/adminfe/static/js/runtime.f1a41c33.js.map
deleted file mode 100644
index 587794937e..0000000000
Binary files a/priv/static/adminfe/static/js/runtime.f1a41c33.js.map and /dev/null differ
diff --git a/test/fixtures/unindexed_fk.sql b/test/fixtures/unindexed_fk.sql
new file mode 100644
index 0000000000..3b71679cfa
--- /dev/null
+++ b/test/fixtures/unindexed_fk.sql
@@ -0,0 +1,27 @@
+-- Unindexed FK -- Missing indexes - For CI
+
+WITH y AS (
+SELECT
+pg_catalog.format('%I', c1.relname) AS referencing_tbl,
+pg_catalog.quote_ident(a1.attname) AS referencing_column,
+(SELECT pg_get_expr(indpred, indrelid) FROM pg_catalog.pg_index WHERE indrelid = t.conrelid AND indkey[0] = t.conkey[1] AND indpred IS NOT NULL LIMIT 1) partial_statement
+FROM pg_catalog.pg_constraint t
+JOIN pg_catalog.pg_attribute a1 ON a1.attrelid = t.conrelid AND a1.attnum = t.conkey[1]
+JOIN pg_catalog.pg_class c1 ON c1.oid = t.conrelid
+JOIN pg_catalog.pg_namespace n1 ON n1.oid = c1.relnamespace
+JOIN pg_catalog.pg_class c2 ON c2.oid = t.confrelid
+JOIN pg_catalog.pg_namespace n2 ON n2.oid = c2.relnamespace
+JOIN pg_catalog.pg_attribute a2 ON a2.attrelid = t.confrelid AND a2.attnum = t.confkey[1]
+WHERE t.contype = 'f'
+AND NOT EXISTS (
+SELECT 1
+FROM pg_catalog.pg_index i
+WHERE i.indrelid = t.conrelid
+AND i.indkey[0] = t.conkey[1]
+AND indpred IS NULL
+)
+)
+SELECT referencing_tbl || '.' || referencing_column as "column"
+FROM y
+WHERE (partial_statement IS NULL OR partial_statement <> ('(' || referencing_column || ' IS NOT NULL)'))
+ORDER BY 1;
\ No newline at end of file
diff --git a/test/mix/tasks/pleroma/config_test.exs b/test/mix/tasks/pleroma/config_test.exs
index 7b21341290..942cfa83d4 100644
--- a/test/mix/tasks/pleroma/config_test.exs
+++ b/test/mix/tasks/pleroma/config_test.exs
@@ -51,7 +51,6 @@ test "error if file with custom settings doesn't exist" do
clear_config(:configurable_from_database, true)
end
- @tag capture_log: true
test "config migration refused when deprecated settings are found" do
clear_config([:media_proxy, :whitelist], ["domain_without_scheme.com"])
assert config_records() == []
diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs
index fbc9391712..d773038cb6 100644
--- a/test/mix/tasks/pleroma/database_test.exs
+++ b/test/mix/tasks/pleroma/database_test.exs
@@ -7,6 +7,7 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do
use Oban.Testing, repo: Pleroma.Repo
alias Pleroma.Activity
+ alias Pleroma.Bookmark
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
@@ -45,28 +46,509 @@ test "it replaces objects with references" do
end
describe "prune_objects" do
- test "it prunes old objects from the database" do
- insert(:note)
+ setup do
deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1
- date =
+ old_insert_date =
Timex.now()
|> Timex.shift(days: -deadline)
|> Timex.to_naive_datetime()
|> NaiveDateTime.truncate(:second)
- %{id: id} =
+ %{old_insert_date: old_insert_date}
+ end
+
+ test "it prunes old objects from the database", %{old_insert_date: old_insert_date} do
+ insert(:note)
+
+ %{id: note_remote_public_id} =
:note
|> insert()
- |> Ecto.Changeset.change(%{inserted_at: date})
+ |> Ecto.Changeset.change(%{updated_at: old_insert_date})
|> Repo.update!()
- assert length(Repo.all(Object)) == 2
+ note_remote_non_public =
+ %{id: note_remote_non_public_id, data: note_remote_non_public_data} =
+ :note
+ |> insert()
+
+ note_remote_non_public
+ |> Ecto.Changeset.change(%{
+ updated_at: old_insert_date,
+ data: note_remote_non_public_data |> update_in(["to"], fn _ -> [] end)
+ })
+ |> Repo.update!()
+
+ assert length(Repo.all(Object)) == 3
Mix.Tasks.Pleroma.Database.run(["prune_objects"])
assert length(Repo.all(Object)) == 1
- refute Object.get_by_id(id)
+ refute Object.get_by_id(note_remote_public_id)
+ refute Object.get_by_id(note_remote_non_public_id)
+ end
+
+ test "it cleans up bookmarks", %{old_insert_date: old_insert_date} do
+ user = insert(:user)
+ {:ok, old_object_activity} = CommonAPI.post(user, %{status: "yadayada"})
+
+ Repo.one(Object)
+ |> Ecto.Changeset.change(%{updated_at: old_insert_date})
+ |> Repo.update!()
+
+ {:ok, new_object_activity} = CommonAPI.post(user, %{status: "yadayada"})
+
+ {:ok, _} = Bookmark.create(user.id, old_object_activity.id)
+ {:ok, _} = Bookmark.create(user.id, new_object_activity.id)
+
+ assert length(Repo.all(Object)) == 2
+ assert length(Repo.all(Bookmark)) == 2
+
+ Mix.Tasks.Pleroma.Database.run(["prune_objects"])
+
+ assert length(Repo.all(Object)) == 1
+ assert length(Repo.all(Bookmark)) == 1
+ refute Bookmark.get(user.id, old_object_activity.id)
+ end
+
+ test "with the --keep-non-public option it still keeps non-public posts even if they are not local",
+ %{old_insert_date: old_insert_date} do
+ insert(:note)
+
+ %{id: note_remote_id} =
+ :note
+ |> insert()
+ |> Ecto.Changeset.change(%{updated_at: old_insert_date})
+ |> Repo.update!()
+
+ note_remote_non_public =
+ %{data: note_remote_non_public_data} =
+ :note
+ |> insert()
+
+ note_remote_non_public
+ |> Ecto.Changeset.change(%{
+ updated_at: old_insert_date,
+ data: note_remote_non_public_data |> update_in(["to"], fn _ -> [] end)
+ })
+ |> Repo.update!()
+
+ assert length(Repo.all(Object)) == 3
+
+ Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-non-public"])
+
+ assert length(Repo.all(Object)) == 2
+ refute Object.get_by_id(note_remote_id)
+ end
+
+ test "with the --keep-threads and --keep-non-public option it keeps old threads with non-public replies even if the interaction is not local",
+ %{old_insert_date: old_insert_date} do
+ # For non-public we only check Create Activities because only these are relevant for threads
+ # Flags are always non-public, Announces from relays can be non-public...
+
+ remote_user1 = insert(:user, local: false)
+ remote_user2 = insert(:user, local: false)
+
+ # Old remote non-public reply (should be kept)
+ {:ok, old_remote_post1_activity} =
+ CommonAPI.post(remote_user1, %{status: "some thing", local: false})
+
+ old_remote_post1_activity
+ |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ {:ok, old_remote_non_public_reply_activity} =
+ CommonAPI.post(remote_user2, %{
+ status: "some reply",
+ in_reply_to_status_id: old_remote_post1_activity.id
+ })
+
+ old_remote_non_public_reply_activity
+ |> Ecto.Changeset.change(%{
+ local: false,
+ updated_at: old_insert_date,
+ data: old_remote_non_public_reply_activity.data |> update_in(["to"], fn _ -> [] end)
+ })
+ |> Repo.update!()
+
+ # Old remote non-public Announce (should be removed)
+ {:ok, old_remote_post2_activity = %{data: %{"object" => old_remote_post2_id}}} =
+ CommonAPI.post(remote_user1, %{status: "some thing", local: false})
+
+ old_remote_post2_activity
+ |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ {:ok, old_remote_non_public_repeat_activity} =
+ CommonAPI.repeat(old_remote_post2_activity.id, remote_user2)
+
+ old_remote_non_public_repeat_activity
+ |> Ecto.Changeset.change(%{
+ local: false,
+ updated_at: old_insert_date,
+ data: old_remote_non_public_repeat_activity.data |> update_in(["to"], fn _ -> [] end)
+ })
+ |> Repo.update!()
+
+ assert length(Repo.all(Object)) == 3
+
+ Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-threads", "--keep-non-public"])
+
+ Repo.all(Pleroma.Activity)
+ assert length(Repo.all(Object)) == 2
+ refute Object.get_by_ap_id(old_remote_post2_id)
+ end
+
+ test "with the --keep-threads option it still keeps non-old threads even with no local interactions" do
+ remote_user = insert(:user, local: false)
+ remote_user2 = insert(:user, local: false)
+
+ {:ok, remote_post_activity} =
+ CommonAPI.post(remote_user, %{status: "some thing", local: false})
+
+ {:ok, remote_post_reply_activity} =
+ CommonAPI.post(remote_user2, %{
+ status: "some reply",
+ in_reply_to_status_id: remote_post_activity.id
+ })
+
+ remote_post_activity
+ |> Ecto.Changeset.change(%{local: false})
+ |> Repo.update!()
+
+ remote_post_reply_activity
+ |> Ecto.Changeset.change(%{local: false})
+ |> Repo.update!()
+
+ assert length(Repo.all(Object)) == 2
+
+ Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-threads"])
+
+ assert length(Repo.all(Object)) == 2
+ end
+
+ test "with the --keep-threads option it deletes old threads with no local interaction", %{
+ old_insert_date: old_insert_date
+ } do
+ remote_user = insert(:user, local: false)
+ remote_user2 = insert(:user, local: false)
+
+ {:ok, old_remote_post_activity} =
+ CommonAPI.post(remote_user, %{status: "some thing", local: false})
+
+ old_remote_post_activity
+ |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ {:ok, old_remote_post_reply_activity} =
+ CommonAPI.post(remote_user2, %{
+ status: "some reply",
+ in_reply_to_status_id: old_remote_post_activity.id
+ })
+
+ old_remote_post_reply_activity
+ |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ {:ok, old_favourite_activity} =
+ CommonAPI.favorite(remote_user2, old_remote_post_activity.id)
+
+ old_favourite_activity
+ |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ {:ok, old_repeat_activity} = CommonAPI.repeat(old_remote_post_activity.id, remote_user2)
+
+ old_repeat_activity
+ |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ assert length(Repo.all(Object)) == 2
+
+ Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-threads"])
+
+ assert length(Repo.all(Object)) == 0
+ end
+
+ test "with the --keep-threads option it keeps old threads with local interaction", %{
+ old_insert_date: old_insert_date
+ } do
+ remote_user = insert(:user, local: false)
+ local_user = insert(:user, local: true)
+
+ # local reply
+ {:ok, old_remote_post1_activity} =
+ CommonAPI.post(remote_user, %{status: "some thing", local: false})
+
+ old_remote_post1_activity
+ |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ {:ok, old_local_post2_reply_activity} =
+ CommonAPI.post(local_user, %{
+ status: "some reply",
+ in_reply_to_status_id: old_remote_post1_activity.id
+ })
+
+ old_local_post2_reply_activity
+ |> Ecto.Changeset.change(%{local: true, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ # local Like
+ {:ok, old_remote_post3_activity} =
+ CommonAPI.post(remote_user, %{status: "some thing", local: false})
+
+ old_remote_post3_activity
+ |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ {:ok, old_favourite_activity} = CommonAPI.favorite(local_user, old_remote_post3_activity.id)
+
+ old_favourite_activity
+ |> Ecto.Changeset.change(%{local: true, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ # local Announce
+ {:ok, old_remote_post4_activity} =
+ CommonAPI.post(remote_user, %{status: "some thing", local: false})
+
+ old_remote_post4_activity
+ |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ {:ok, old_repeat_activity} = CommonAPI.repeat(old_remote_post4_activity.id, local_user)
+
+ old_repeat_activity
+ |> Ecto.Changeset.change(%{local: true, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ assert length(Repo.all(Object)) == 4
+
+ Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-threads"])
+
+ assert length(Repo.all(Object)) == 4
+ end
+
+ test "with the --keep-threads option it keeps old threads with bookmarked posts", %{
+ old_insert_date: old_insert_date
+ } do
+ remote_user = insert(:user, local: false)
+ local_user = insert(:user, local: true)
+
+ {:ok, old_remote_post_activity} =
+ CommonAPI.post(remote_user, %{status: "some thing", local: false})
+
+ old_remote_post_activity
+ |> Ecto.Changeset.change(%{local: false, updated_at: old_insert_date})
+ |> Repo.update!()
+
+ Pleroma.Bookmark.create(local_user.id, old_remote_post_activity.id)
+
+ assert length(Repo.all(Object)) == 1
+
+ Mix.Tasks.Pleroma.Database.run(["prune_objects", "--keep-threads"])
+
+ assert length(Repo.all(Object)) == 1
+ end
+
+ test "We don't have unexpected tables which may contain objects that are referenced by activities" do
+ # We can delete orphaned activities. For that we look for the objects
+ # they reference in the 'objects', 'activities', and 'users' table.
+ # If someone adds another table with objects (idk, maybe with separate
+ # relations, or collections or w/e), then we need to make sure we
+ # add logic for that in the 'prune_objects' task so that we don't
+ # wrongly delete their corresponding activities.
+ # So when someone adds (or removes) a table, this test will fail.
+ # Either the table contains objects which can be referenced from the
+ # activities table
+ # => in that case the prune_objects job should be adapted so we don't
+ # delete activities who still have the referenced object.
+ # Or it doesn't contain objects which can be referenced from the activities table
+ # => in that case you can add/remove the table to/from this (sorted) list.
+
+ assert Repo.query!(
+ "SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE';"
+ ).rows
+ |> Enum.sort() == [
+ ["activities"],
+ ["announcement_read_relationships"],
+ ["announcements"],
+ ["apps"],
+ ["backups"],
+ ["bookmark_folders"],
+ ["bookmarks"],
+ ["chat_message_references"],
+ ["chats"],
+ ["config"],
+ ["conversation_participation_recipient_ships"],
+ ["conversation_participations"],
+ ["conversations"],
+ ["counter_cache"],
+ ["data_migration_failed_ids"],
+ ["data_migrations"],
+ ["deliveries"],
+ ["filters"],
+ ["following_relationships"],
+ ["hashtags"],
+ ["hashtags_objects"],
+ ["instances"],
+ ["lists"],
+ ["markers"],
+ ["mfa_tokens"],
+ ["moderation_log"],
+ ["notifications"],
+ ["oauth_authorizations"],
+ ["oauth_tokens"],
+ ["oban_jobs"],
+ ["oban_peers"],
+ ["objects"],
+ ["password_reset_tokens"],
+ ["push_subscriptions"],
+ ["registrations"],
+ ["report_notes"],
+ ["rich_media_card"],
+ ["rules"],
+ ["scheduled_activities"],
+ ["schema_migrations"],
+ ["thread_mutes"],
+ # ["user_follows_hashtag"], # not in pleroma
+ # ["user_frontend_setting_profiles"], # not in pleroma
+ ["user_invite_tokens"],
+ ["user_notes"],
+ ["user_relationships"],
+ ["users"]
+ ]
+ end
+
+ test "it prunes orphaned activities with the --prune-orphaned-activities" do
+ # Add a remote activity which references an Object
+ %Object{} |> Map.merge(%{data: %{"id" => "object_for_activity"}}) |> Repo.insert()
+
+ %Activity{}
+ |> Map.merge(%{
+ local: false,
+ data: %{"id" => "remote_activity_with_object", "object" => "object_for_activity"}
+ })
+ |> Repo.insert()
+
+ # Add a remote activity which references an activity
+ %Activity{}
+ |> Map.merge(%{
+ local: false,
+ data: %{
+ "id" => "remote_activity_with_activity",
+ "object" => "remote_activity_with_object"
+ }
+ })
+ |> Repo.insert()
+
+ # Add a remote activity which references an Actor
+ %User{} |> Map.merge(%{ap_id: "actor"}) |> Repo.insert()
+
+ %Activity{}
+ |> Map.merge(%{
+ local: false,
+ data: %{"id" => "remote_activity_with_actor", "object" => "actor"}
+ })
+ |> Repo.insert()
+
+ # Add a remote activity without existing referenced object, activity or actor
+ %Activity{}
+ |> Map.merge(%{
+ local: false,
+ data: %{
+ "id" => "remote_activity_without_existing_referenced_object",
+ "object" => "non_existing"
+ }
+ })
+ |> Repo.insert()
+
+ # Add a local activity without existing referenced object, activity or actor
+ %Activity{}
+ |> Map.merge(%{
+ local: true,
+ data: %{"id" => "local_activity_with_actor", "object" => "non_existing"}
+ })
+ |> Repo.insert()
+
+ # The remote activities without existing reference,
+ # and only the remote activities without existing reference, are deleted
+ # if, and only if, we provide the --prune-orphaned-activities option
+ assert length(Repo.all(Activity)) == 5
+ Mix.Tasks.Pleroma.Database.run(["prune_objects"])
+ assert length(Repo.all(Activity)) == 5
+ Mix.Tasks.Pleroma.Database.run(["prune_objects", "--prune-orphaned-activities"])
+ activities = Repo.all(Activity)
+
+ assert "remote_activity_without_existing_referenced_object" not in Enum.map(
+ activities,
+ fn a -> a.data["id"] end
+ )
+
+ assert length(activities) == 4
+ end
+
+ test "it prunes orphaned activities with the --prune-orphaned-activities when the objects are referenced from an array" do
+ %Object{} |> Map.merge(%{data: %{"id" => "existing_object"}}) |> Repo.insert()
+ %User{} |> Map.merge(%{ap_id: "existing_actor"}) |> Repo.insert()
+
+ # Multiple objects, one object exists (keep)
+ %Activity{}
+ |> Map.merge(%{
+ local: false,
+ data: %{
+ "id" => "remote_activity_existing_object",
+ "object" => ["non_ existing_object", "existing_object"]
+ }
+ })
+ |> Repo.insert()
+
+ # Multiple objects, one actor exists (keep)
+ %Activity{}
+ |> Map.merge(%{
+ local: false,
+ data: %{
+ "id" => "remote_activity_existing_actor",
+ "object" => ["non_ existing_object", "existing_actor"]
+ }
+ })
+ |> Repo.insert()
+
+ # Multiple objects, one activity exists (keep)
+ %Activity{}
+ |> Map.merge(%{
+ local: false,
+ data: %{
+ "id" => "remote_activity_existing_activity",
+ "object" => ["non_ existing_object", "remote_activity_existing_actor"]
+ }
+ })
+ |> Repo.insert()
+
+ # Multiple objects none exist (prune)
+ %Activity{}
+ |> Map.merge(%{
+ local: false,
+ data: %{
+ "id" => "remote_activity_without_existing_referenced_object",
+ "object" => ["owo", "whats_this"]
+ }
+ })
+ |> Repo.insert()
+
+ assert length(Repo.all(Activity)) == 4
+ Mix.Tasks.Pleroma.Database.run(["prune_objects"])
+ assert length(Repo.all(Activity)) == 4
+ Mix.Tasks.Pleroma.Database.run(["prune_objects", "--prune-orphaned-activities"])
+ activities = Repo.all(Activity)
+ assert length(activities) == 3
+
+ assert "remote_activity_without_existing_referenced_object" not in Enum.map(
+ activities,
+ fn a -> a.data["id"] end
+ )
+
+ assert length(activities) == 3
end
end
diff --git a/test/pleroma/config_db_test.exs b/test/pleroma/config_db_test.exs
index e20da15748..d68e4e6fa1 100644
--- a/test/pleroma/config_db_test.exs
+++ b/test/pleroma/config_db_test.exs
@@ -312,7 +312,7 @@ test "proxy tuple with localhost" do
test "proxy tuple with domain" do
assert ConfigDB.to_elixir_types(%{
"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]
- }) == {:proxy_url, {:socks5, 'domain.com', 1234}}
+ }) == {:proxy_url, {:socks5, ~c"domain.com", 1234}}
end
test "proxy tuple with ip" do
diff --git a/test/pleroma/gun/connection_pool_test.exs b/test/pleroma/gun/connection_pool_test.exs
index e0c9e99040..f3670760da 100644
--- a/test/pleroma/gun/connection_pool_test.exs
+++ b/test/pleroma/gun/connection_pool_test.exs
@@ -46,7 +46,6 @@ test "gives the same connection to 2 concurrent requests" do
end
end
- @tag :erratic
test "connection limit is respected with concurrent requests" do
clear_config([:connections_pool, :max_connections]) do
clear_config([:connections_pool, :max_connections], 1)
diff --git a/test/pleroma/http/adapter_helper/gun_test.exs b/test/pleroma/http/adapter_helper/gun_test.exs
index d567bc844b..568fd6fb39 100644
--- a/test/pleroma/http/adapter_helper/gun_test.exs
+++ b/test/pleroma/http/adapter_helper/gun_test.exs
@@ -55,23 +55,23 @@ test "parses string proxy host & port" do
uri = URI.parse("https://some-domain.com")
opts = Gun.options([receive_conn: false], uri)
- assert opts[:proxy] == {'localhost', 8123}
+ assert opts[:proxy] == {~c"localhost", 8123}
end
test "parses tuple proxy scheme host and port" do
- clear_config([:http, :proxy_url], {:socks, 'localhost', 1234})
+ clear_config([:http, :proxy_url], {:socks, ~c"localhost", 1234})
uri = URI.parse("https://some-domain.com")
opts = Gun.options([receive_conn: false], uri)
- assert opts[:proxy] == {:socks, 'localhost', 1234}
+ assert opts[:proxy] == {:socks, ~c"localhost", 1234}
end
test "passed opts have more weight than defaults" do
- clear_config([:http, :proxy_url], {:socks5, 'localhost', 1234})
+ clear_config([:http, :proxy_url], {:socks5, ~c"localhost", 1234})
uri = URI.parse("https://some-domain.com")
- opts = Gun.options([receive_conn: false, proxy: {'example.com', 4321}], uri)
+ opts = Gun.options([receive_conn: false, proxy: {~c"example.com", 4321}], uri)
- assert opts[:proxy] == {'example.com', 4321}
+ assert opts[:proxy] == {~c"example.com", 4321}
end
end
end
diff --git a/test/pleroma/http/adapter_helper_test.exs b/test/pleroma/http/adapter_helper_test.exs
index e3c78f3176..cc0e24167f 100644
--- a/test/pleroma/http/adapter_helper_test.exs
+++ b/test/pleroma/http/adapter_helper_test.exs
@@ -17,12 +17,12 @@ test "with string" do
end
test "localhost with port" do
- assert AdapterHelper.format_proxy("localhost:8123") == {'localhost', 8123}
+ assert AdapterHelper.format_proxy("localhost:8123") == {~c"localhost", 8123}
end
test "tuple" do
assert AdapterHelper.format_proxy({:socks4, :localhost, 9050}) ==
- {:socks4, 'localhost', 9050}
+ {:socks4, ~c"localhost", 9050}
end
end
end
diff --git a/test/pleroma/job_queue_monitor_test.exs b/test/pleroma/job_queue_monitor_test.exs
index f2056990f9..e2250d7e22 100644
--- a/test/pleroma/job_queue_monitor_test.exs
+++ b/test/pleroma/job_queue_monitor_test.exs
@@ -28,13 +28,13 @@ defmodule Pleroma.JobQueueMonitorTest do
queue: "background",
stack: [
{Pleroma.Workers.BackgroundWorker, :perform, 2,
- [file: 'lib/pleroma/workers/background_worker.ex', line: 31]},
+ [file: ~c"lib/pleroma/workers/background_worker.ex", line: 31]},
{Oban.Queue.Executor, :safe_call, 1,
- [file: 'lib/oban/queue/executor.ex', line: 42]},
- {:timer, :tc, 3, [file: 'timer.erl', line: 197]},
- {Oban.Queue.Executor, :call, 2, [file: 'lib/oban/queue/executor.ex', line: 23]},
- {Task.Supervised, :invoke_mfa, 2, [file: 'lib/task/supervised.ex', line: 90]},
- {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 249]}
+ [file: ~c"lib/oban/queue/executor.ex", line: 42]},
+ {:timer, :tc, 3, [file: ~c"timer.erl", line: 197]},
+ {Oban.Queue.Executor, :call, 2, [file: ~c"lib/oban/queue/executor.ex", line: 23]},
+ {Task.Supervised, :invoke_mfa, 2, [file: ~c"lib/task/supervised.ex", line: 90]},
+ {:proc_lib, :init_p_do_apply, 3, [file: ~c"proc_lib.erl", line: 249]}
],
worker: "Pleroma.Workers.BackgroundWorker"
}}
diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs
index 287ef686c3..898d109fbb 100644
--- a/test/pleroma/notification_test.exs
+++ b/test/pleroma/notification_test.exs
@@ -468,7 +468,10 @@ test "it creates `follow_request` notification for pending Follow activity" do
|> Repo.preload(:activity)
assert %{type: "follow"} =
- NotificationView.render("show.json", notification: notification, for: followed_user)
+ NotificationView.render("show.json",
+ notification: notification,
+ for: followed_user
+ )
end
test "it doesn't create a notification for follow-unfollow-follow chains" do
diff --git a/test/pleroma/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs
index 6f21452a7d..6704c18db9 100644
--- a/test/pleroma/object/fetcher_test.exs
+++ b/test/pleroma/object/fetcher_test.exs
@@ -84,7 +84,6 @@ defmodule Pleroma.Object.FetcherTest do
:ok
end
- @tag capture_log: true
test "it works when fetching the OP actor errors out" do
# Here we simulate a case where the author of the OP can't be read
assert {:ok, _} =
diff --git a/test/pleroma/schema_test.exs b/test/pleroma/schema_test.exs
new file mode 100644
index 0000000000..9bddd2031d
--- /dev/null
+++ b/test/pleroma/schema_test.exs
@@ -0,0 +1,17 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.SchemaTest do
+ use Pleroma.DataCase, async: true
+
+ alias Pleroma.Repo
+
+ test "No unindexed foreign keys" do
+ query = File.read!("test/fixtures/unindexed_fk.sql")
+
+ {:ok, result} = Repo.query(query)
+
+ assert Enum.empty?(result.rows)
+ end
+end
diff --git a/test/pleroma/uploaders/ipfs_test.exs b/test/pleroma/uploaders/ipfs_test.exs
index cf325b54f2..bdf2933ac5 100644
--- a/test/pleroma/uploaders/ipfs_test.exs
+++ b/test/pleroma/uploaders/ipfs_test.exs
@@ -14,25 +14,6 @@ defmodule Pleroma.Uploaders.IPFSTest do
alias Pleroma.UnstubbedConfigMock, as: Config
- describe "get_final_url" do
- setup do
- Config
- |> expect(:get, fn [Pleroma.Uploaders.IPFS] ->
- [post_gateway_url: "http://localhost:5001"]
- end)
-
- :ok
- end
-
- test "it returns the final url for put_file" do
- assert IPFS.put_file_endpoint() == "http://localhost:5001/api/v0/add"
- end
-
- test "it returns the final url for delete_file" do
- assert IPFS.delete_file_endpoint() == "http://localhost:5001/api/v0/files/rm"
- end
- end
-
describe "get_file/1" do
setup do
Config
@@ -71,8 +52,8 @@ test "it returns path to ipfs file with cid as path" do
describe "put_file/1" do
setup do
Config
- |> expect(:get, fn [Pleroma.Uploaders.IPFS] ->
- [post_gateway_url: "http://localhost:5001"]
+ |> expect(:get, fn [Pleroma.Uploaders.IPFS, :post_gateway_url] ->
+ "http://localhost:5001"
end)
file_upload = %Pleroma.Upload{
@@ -92,7 +73,11 @@ test "it returns path to ipfs file with cid as path" do
test "save file", %{file_upload: file_upload} do
with_mock Pleroma.HTTP,
- post: fn "http://localhost:5001/api/v0/add", _mp, [], params: ["cid-version": "1"] ->
+ post: fn "http://localhost:5001/api/v0/add",
+ _mp,
+ [],
+ params: ["cid-version": "1"],
+ pool: :upload ->
{:ok,
%Tesla.Env{
status: 200,
@@ -107,7 +92,11 @@ test "save file", %{file_upload: file_upload} do
test "returns error", %{file_upload: file_upload} do
with_mock Pleroma.HTTP,
- post: fn "http://localhost:5001/api/v0/add", _mp, [], params: ["cid-version": "1"] ->
+ post: fn "http://localhost:5001/api/v0/add",
+ _mp,
+ [],
+ params: ["cid-version": "1"],
+ pool: :upload ->
{:error, "IPFS Gateway upload failed"}
end do
assert capture_log(fn ->
@@ -118,7 +107,11 @@ test "returns error", %{file_upload: file_upload} do
test "returns error if JSON decode fails", %{file_upload: file_upload} do
with_mock Pleroma.HTTP, [],
- post: fn "http://localhost:5001/api/v0/add", _mp, [], params: ["cid-version": "1"] ->
+ post: fn "http://localhost:5001/api/v0/add",
+ _mp,
+ [],
+ params: ["cid-version": "1"],
+ pool: :upload ->
{:ok, %Tesla.Env{status: 200, body: "invalid"}}
end do
assert capture_log(fn ->
@@ -130,7 +123,11 @@ test "returns error if JSON decode fails", %{file_upload: file_upload} do
test "returns error if JSON body doesn't contain Hash key", %{file_upload: file_upload} do
with_mock Pleroma.HTTP, [],
- post: fn "http://localhost:5001/api/v0/add", _mp, [], params: ["cid-version": "1"] ->
+ post: fn "http://localhost:5001/api/v0/add",
+ _mp,
+ [],
+ params: ["cid-version": "1"],
+ pool: :upload ->
{:ok, %Tesla.Env{status: 200, body: "{\"key\": \"value\"}"}}
end do
assert IPFS.put_file(file_upload) == {:error, "JSON doesn't contain Hash key"}
@@ -141,8 +138,8 @@ test "returns error if JSON body doesn't contain Hash key", %{file_upload: file_
describe "delete_file/1" do
setup do
Config
- |> expect(:get, fn [Pleroma.Uploaders.IPFS] ->
- [post_gateway_url: "http://localhost:5001"]
+ |> expect(:get, fn [Pleroma.Uploaders.IPFS, :post_gateway_url] ->
+ "http://localhost:5001"
end)
:ok
diff --git a/test/pleroma/user/backup_async_test.exs b/test/pleroma/user/backup_async_test.exs
index 76716d6847..b0e9413bed 100644
--- a/test/pleroma/user/backup_async_test.exs
+++ b/test/pleroma/user/backup_async_test.exs
@@ -19,7 +19,6 @@ defmodule Pleroma.User.BackupAsyncTest do
%{backup: backup}
end
- @tag capture_log: true
test "it handles unrecoverable exceptions", %{backup: backup} do
ProcessorMock
|> expect(:do_process, fn _, _ ->
@@ -34,7 +33,6 @@ test "it handles unrecoverable exceptions", %{backup: backup} do
assert backup.state == :failed
end
- @tag capture_log: true
test "it handles timeouts", %{backup: backup} do
ProcessorMock
|> expect(:do_process, fn _, _ ->
diff --git a/test/pleroma/user/backup_test.exs b/test/pleroma/user/backup_test.exs
index 1b6a47f88d..5f7b95f145 100644
--- a/test/pleroma/user/backup_test.exs
+++ b/test/pleroma/user/backup_test.exs
@@ -197,7 +197,7 @@ test "it creates a zip archive with user data" do
assert {:ok, backup} = user |> Backup.new() |> Repo.insert()
assert {:ok, path} = Backup.export(backup, self())
assert {:ok, zipfile} = :zip.zip_open(String.to_charlist(path), [:memory])
- assert {:ok, {'actor.json', json}} = :zip.zip_get('actor.json', zipfile)
+ assert {:ok, {~c"actor.json", json}} = :zip.zip_get(~c"actor.json", zipfile)
assert %{
"@context" => [
@@ -222,7 +222,7 @@ test "it creates a zip archive with user data" do
"url" => "http://cofe.io/users/cofe"
} = Jason.decode!(json)
- assert {:ok, {'outbox.json', json}} = :zip.zip_get('outbox.json', zipfile)
+ assert {:ok, {~c"outbox.json", json}} = :zip.zip_get(~c"outbox.json", zipfile)
assert %{
"@context" => "https://www.w3.org/ns/activitystreams",
@@ -253,7 +253,7 @@ test "it creates a zip archive with user data" do
"type" => "OrderedCollection"
} = Jason.decode!(json)
- assert {:ok, {'likes.json', json}} = :zip.zip_get('likes.json', zipfile)
+ assert {:ok, {~c"likes.json", json}} = :zip.zip_get(~c"likes.json", zipfile)
assert %{
"@context" => "https://www.w3.org/ns/activitystreams",
@@ -263,7 +263,7 @@ test "it creates a zip archive with user data" do
"type" => "OrderedCollection"
} = Jason.decode!(json)
- assert {:ok, {'bookmarks.json', json}} = :zip.zip_get('bookmarks.json', zipfile)
+ assert {:ok, {~c"bookmarks.json", json}} = :zip.zip_get(~c"bookmarks.json", zipfile)
assert %{
"@context" => "https://www.w3.org/ns/activitystreams",
@@ -273,7 +273,7 @@ test "it creates a zip archive with user data" do
"type" => "OrderedCollection"
} = Jason.decode!(json)
- assert {:ok, {'following.json', json}} = :zip.zip_get('following.json', zipfile)
+ assert {:ok, {~c"following.json", json}} = :zip.zip_get(~c"following.json", zipfile)
assert %{
"@context" => "https://www.w3.org/ns/activitystreams",
@@ -283,7 +283,7 @@ test "it creates a zip archive with user data" do
"type" => "OrderedCollection"
} = Jason.decode!(json)
- assert {:ok, {'chats.json', json}} = :zip.zip_get('chats.json', zipfile)
+ assert {:ok, {~c"chats.json", json}} = :zip.zip_get(~c"chats.json", zipfile)
chat_id = "http://localhost:4001/chats/#{chat.id}"
@@ -302,7 +302,7 @@ test "it creates a zip archive with user data" do
"type" => "OrderedCollection"
} = Jason.decode!(json)
- assert {:ok, {'chat_messages.json', json}} = :zip.zip_get('chat_messages.json', zipfile)
+ assert {:ok, {~c"chat_messages.json", json}} = :zip.zip_get(~c"chat_messages.json", zipfile)
chat_id = "http://localhost:4001/chats/#{chat.id}"
diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs
index 42d5adbc6d..d5221c4a02 100644
--- a/test/pleroma/user_test.exs
+++ b/test/pleroma/user_test.exs
@@ -985,7 +985,6 @@ test "gets an existing user by fully qualified nickname, case insensitive" do
assert user == fetched_user
end
- @tag capture_log: true
test "returns nil if no user could be fetched" do
{:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistent@social.heldscal.la")
assert fetched_user == "not found nonexistent@social.heldscal.la"
@@ -1012,9 +1011,16 @@ test "updates an existing user, if stale" do
{:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
- assert user.inbox
+ # Oban job was generated to refresh the stale user
+ assert_enqueued(worker: "Pleroma.Workers.UserRefreshWorker", args: %{"ap_id" => user.ap_id})
- refute user.last_refreshed_at == orig_user.last_refreshed_at
+ # Run job to refresh the user; just capture its output instead of fetching it again
+ assert {:ok, updated_user} =
+ perform_job(Pleroma.Workers.UserRefreshWorker, %{"ap_id" => user.ap_id})
+
+ assert updated_user.inbox
+
+ refute updated_user.last_refreshed_at == orig_user.last_refreshed_at
end
test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
@@ -1042,7 +1048,6 @@ test "if nicknames clash, the old user gets a prefix with the old id to the nick
assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
end
- @tag capture_log: true
test "it returns the old user if stale, but unfetchable" do
a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
diff --git a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
index 07bb960301..b57db3679a 100644
--- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -591,7 +591,6 @@ test "it inserts an incoming activity into the database", %{conn: conn} do
assert Activity.get_by_ap_id(data["id"])
end
- @tag capture_log: true
test "it inserts an incoming activity into the database" <>
"even if we can't fetch the user but have it in our db",
%{conn: conn} do
@@ -675,7 +674,6 @@ test "accept follow activity", %{conn: conn} do
assert_receive {:mix_shell, :info, ["https://relay.mastodon.host/actor"]}
end
- @tag capture_log: true
test "without valid signature, " <>
"it only accepts Create activities and requires enabled federation",
%{conn: conn} do
@@ -1098,7 +1096,6 @@ test "it clears `unreachable` federation status of the sender", %{conn: conn, da
assert Instances.reachable?(sender_host)
end
- @tag capture_log: true
test "it removes all follower collections but actor's", %{conn: conn} do
[actor, recipient] = insert_pair(:user)
@@ -1161,7 +1158,6 @@ test "it requires authentication", %{conn: conn} do
assert json_response(ret_conn, 200)
end
- @tag capture_log: true
test "forwarded report", %{conn: conn} do
admin = insert(:user, is_admin: true)
actor = insert(:user, local: false)
@@ -1237,7 +1233,6 @@ test "forwarded report", %{conn: conn} do
)
end
- @tag capture_log: true
test "forwarded report from mastodon", %{conn: conn} do
admin = insert(:user, is_admin: true)
actor = insert(:user, local: false)
diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs
index d4ca14c2c2..0843da6911 100644
--- a/test/pleroma/web/activity_pub/activity_pub_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_test.exs
@@ -293,9 +293,7 @@ test "fetches user featured collection" do
body: featured_data,
headers: [{"content-type", "application/activity+json"}]
}
- end)
- Tesla.Mock.mock_global(fn
%{
method: :get,
url: ^object_url
@@ -308,7 +306,18 @@ test "fetches user featured collection" do
end)
{:ok, user} = ActivityPub.make_user_from_ap_id(ap_id)
- Process.sleep(50)
+
+ assert_enqueued(
+ worker: Pleroma.Workers.RemoteFetcherWorker,
+ args: %{
+ "op" => "fetch_remote",
+ "id" => object_url,
+ "depth" => 1
+ }
+ )
+
+ # wait for oban
+ Pleroma.Tests.ObanHelpers.perform_all()
assert user.featured_address == featured_url
assert Map.has_key?(user.pinned_objects, object_url)
@@ -370,9 +379,7 @@ test "fetches user featured collection without embedded object" do
body: featured_data,
headers: [{"content-type", "application/activity+json"}]
}
- end)
- Tesla.Mock.mock_global(fn
%{
method: :get,
url: ^object_url
@@ -385,7 +392,18 @@ test "fetches user featured collection without embedded object" do
end)
{:ok, user} = ActivityPub.make_user_from_ap_id(ap_id)
- Process.sleep(50)
+
+ assert_enqueued(
+ worker: Pleroma.Workers.RemoteFetcherWorker,
+ args: %{
+ "op" => "fetch_remote",
+ "id" => object_url,
+ "depth" => 1
+ }
+ )
+
+ # wait for oban
+ Pleroma.Tests.ObanHelpers.perform_all()
assert user.featured_address == featured_url
assert Map.has_key?(user.pinned_objects, object_url)
@@ -2740,7 +2758,6 @@ test "allow fetching of accounts with an empty string name field" do
assert user.name == " "
end
- @tag capture_log: true
test "pin_data_from_featured_collection will ignore unsupported values" do
assert %{} ==
ActivityPub.pin_data_from_featured_collection(%{
diff --git a/test/pleroma/web/activity_pub/mrf_test.exs b/test/pleroma/web/activity_pub/mrf_test.exs
index 60eaea8fd1..67410cf58c 100644
--- a/test/pleroma/web/activity_pub/mrf_test.exs
+++ b/test/pleroma/web/activity_pub/mrf_test.exs
@@ -65,7 +65,6 @@ test "matches are case-insensitive" do
refute MRF.subdomain_match?(regexes, "example.com")
end
- @tag capture_log: true
test "logs sensible error on accidental wildcard" do
assert_raise Regex.CompileError, fn ->
assert capture_log(MRF.subdomains_regex(["*unsafe.tld"])) =~
diff --git a/test/pleroma/web/activity_pub/publisher_test.exs b/test/pleroma/web/activity_pub/publisher_test.exs
index 870f1f77a7..150b7bb596 100644
--- a/test/pleroma/web/activity_pub/publisher_test.exs
+++ b/test/pleroma/web/activity_pub/publisher_test.exs
@@ -216,7 +216,6 @@ test "publish to url with with different ports" do
refute called(Instances.set_reachable(inbox))
end
- @tag capture_log: true
test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
Instances,
[:passthrough],
diff --git a/test/pleroma/web/activity_pub/relay_test.exs b/test/pleroma/web/activity_pub/relay_test.exs
index ec9b0f09a9..5867246d7c 100644
--- a/test/pleroma/web/activity_pub/relay_test.exs
+++ b/test/pleroma/web/activity_pub/relay_test.exs
@@ -113,7 +113,6 @@ test "returns error when activity not `Create` type" do
assert Relay.publish(activity) == {:error, "Not implemented"}
end
- @tag capture_log: true
test "returns error when activity not public" do
activity = insert(:direct_note_activity)
assert Relay.publish(activity) == {:error, false}
diff --git a/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs
index 9521cc0ab0..f55f42c105 100644
--- a/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs
@@ -83,7 +83,6 @@ test "it works for incoming announces, fetching the announced object" do
assert(Activity.get_create_by_object_ap_id(data["object"]))
end
- @tag capture_log: true
test "it works for incoming announces with an existing activity" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
@@ -136,7 +135,6 @@ test "it works for incoming announces with an inlined activity" do
assert object.data["content"] == "this is a private toot"
end
- @tag capture_log: true
test "it rejects incoming announces with an inlined activity from another origin" do
Tesla.Mock.mock(fn
%{method: :get} -> %Tesla.Env{status: 404, body: ""}
diff --git a/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs
index 4a7ff51586..300151fb21 100644
--- a/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs
@@ -86,7 +86,6 @@ test "it fails for incoming deletes with spoofed origin" do
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
end
- @tag capture_log: true
test "it works for incoming user deletes" do
%{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
diff --git a/test/pleroma/web/activity_pub/transmogrifier/emoji_tag_building_test.exs b/test/pleroma/web/activity_pub/transmogrifier/emoji_tag_building_test.exs
new file mode 100644
index 0000000000..c632c199c1
--- /dev/null
+++ b/test/pleroma/web/activity_pub/transmogrifier/emoji_tag_building_test.exs
@@ -0,0 +1,14 @@
+defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiTagBuildingTest do
+ use Pleroma.DataCase, async: true
+
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+
+ test "it encodes the id to be a valid url" do
+ name = "hanapog"
+ url = "https://misskey.local.live/emojis/hana pog.png"
+
+ tag = Transmogrifier.build_emoji_tag({name, url})
+
+ assert tag["id"] == "https://misskey.local.live/emojis/hana%20pog.png"
+ end
+end
diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs
index 9bc3d4a114..75faae2cc0 100644
--- a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs
@@ -56,7 +56,6 @@ test "it ignores an incoming notice if we already have it" do
assert activity == returned_activity
end
- @tag capture_log: true
test "it fetches reply-to activities if we don't have them" do
data =
File.read!("test/fixtures/mastodon-post-activity.json")
@@ -104,7 +103,6 @@ test "it does not fetch reply-to activities beyond max replies depth limit" do
end
end
- @tag capture_log: true
test "it does not crash if the object in inReplyTo can't be fetched" do
data =
File.read!("test/fixtures/mastodon-post-activity.json")
@@ -662,7 +660,6 @@ test "returns object with inReplyTo when denied incoming reply", %{data: data} d
assert modified_object["inReplyTo"] == []
end
- @tag capture_log: true
test "returns modified object when allowed incoming reply", %{data: data} do
object_with_reply =
Map.put(
@@ -848,7 +845,6 @@ test "the standalone note uses its own ID when context is missing" do
assert modified.data["context"] == object.data["id"]
end
- @tag capture_log: true
test "the reply note uses its parent's ID when context is missing and reply is unreachable" do
insert(:user, ap_id: "https://mk.absturztau.be/users/8ozbzjs3o8")
diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs
index f7857c2284..e13305f446 100644
--- a/test/pleroma/web/activity_pub/transmogrifier_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs
@@ -532,7 +532,6 @@ test "returns nil when cannot normalize object" do
end) =~ "Unsupported URI scheme"
end
- @tag capture_log: true
test "returns {:ok, %Object{}} for success case" do
assert {:ok, %Object{}} =
Transmogrifier.get_obj_helper(
diff --git a/test/pleroma/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs
index 17bd9ef023..55c0b6444e 100644
--- a/test/pleroma/web/admin_api/controllers/config_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs
@@ -194,7 +194,6 @@ test "POST /api/pleroma/admin/config with configdb disabled", %{conn: conn} do
setup do: clear_config(:configurable_from_database, true)
- @tag capture_log: true
test "create new config setting in db", %{conn: conn} do
ueberauth = Application.get_env(:ueberauth, Ueberauth)
on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
@@ -316,7 +315,6 @@ test "create new config setting in db", %{conn: conn} do
assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
end
- @tag capture_log: true
test "save configs setting without explicit key", %{conn: conn} do
adapter = Application.get_env(:http, :adapter)
send_user_agent = Application.get_env(:http, :send_user_agent)
@@ -611,52 +609,6 @@ test "saving special atoms", %{conn: conn} do
]
end
- test "saving full setting if value is in full_key_update list", %{conn: conn} do
- backends = Application.get_env(:logger, :backends)
- on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
-
- insert(:config,
- group: :logger,
- key: :backends,
- value: []
- )
-
- Pleroma.Config.TransferTask.load_and_update_env([], false)
-
- assert Application.get_env(:logger, :backends) == []
-
- conn =
- conn
- |> put_req_header("content-type", "application/json")
- |> post("/api/pleroma/admin/config", %{
- configs: [
- %{
- group: ":logger",
- key: ":backends",
- value: [":console"]
- }
- ]
- })
-
- assert json_response_and_validate_schema(conn, 200) == %{
- "configs" => [
- %{
- "group" => ":logger",
- "key" => ":backends",
- "value" => [
- ":console"
- ],
- "db" => [":backends"]
- }
- ],
- "need_reboot" => false
- }
-
- assert Application.get_env(:logger, :backends) == [
- :console
- ]
- end
-
test "saving full setting if value is not keyword", %{conn: conn} do
insert(:config,
group: :tesla,
@@ -1229,7 +1181,6 @@ test "proxy tuple ip", %{conn: conn} do
assert ":proxy_url" in db
end
- @tag capture_log: true
test "doesn't set keys not in the whitelist", %{conn: conn} do
clear_config(:database_config_whitelist, [
{:pleroma, :key1},
diff --git a/test/pleroma/web/feed/tag_controller_test.exs b/test/pleroma/web/feed/tag_controller_test.exs
index 58ab8f1377..7d196b228e 100644
--- a/test/pleroma/web/feed/tag_controller_test.exs
+++ b/test/pleroma/web/feed/tag_controller_test.exs
@@ -55,11 +55,11 @@ test "gets a feed (ATOM)", %{conn: conn} do
xml = parse(response)
- assert xpath(xml, ~x"//feed/title/text()") == '#pleromaart'
+ assert xpath(xml, ~x"//feed/title/text()") == ~c"#pleromaart"
assert xpath(xml, ~x"//feed/entry/title/text()"l) == [
- '42 This is :moominmamm...',
- 'yeah #PleromaArt'
+ ~c"42 This is :moominmamm...",
+ ~c"yeah #PleromaArt"
]
assert xpath(xml, ~x"//feed/entry/author/name/text()"ls) == [user.nickname, user.nickname]
@@ -73,10 +73,10 @@ test "gets a feed (ATOM)", %{conn: conn} do
resp = response(conn, 200)
xml = parse(resp)
- assert xpath(xml, ~x"//feed/title/text()") == '#pleromaart'
+ assert xpath(xml, ~x"//feed/title/text()") == ~c"#pleromaart"
assert xpath(xml, ~x"//feed/entry/title/text()"l) == [
- 'yeah #PleromaArt'
+ ~c"yeah #PleromaArt"
]
end
@@ -120,20 +120,20 @@ test "gets a feed (RSS)", %{conn: conn} do
|> response(200)
xml = parse(response)
- assert xpath(xml, ~x"//channel/title/text()") == '#pleromaart'
+ assert xpath(xml, ~x"//channel/title/text()") == ~c"#pleromaart"
assert xpath(xml, ~x"//channel/description/text()"s) ==
"These are public toots tagged with #pleromaart. You can interact with them if you have an account anywhere in the fediverse."
assert xpath(xml, ~x"//channel/link/text()") ==
- '#{Pleroma.Web.Endpoint.url()}/tags/pleromaart.rss'
+ ~c"#{Pleroma.Web.Endpoint.url()}/tags/pleromaart.rss"
assert xpath(xml, ~x"//channel/webfeeds:logo/text()") ==
- '#{Pleroma.Web.Endpoint.url()}/static/logo.svg'
+ ~c"#{Pleroma.Web.Endpoint.url()}/static/logo.svg"
assert xpath(xml, ~x"//channel/item/title/text()"l) == [
- '42 This is :moominmamm...',
- 'yeah #PleromaArt'
+ ~c"42 This is :moominmamm...",
+ ~c"yeah #PleromaArt"
]
assert xpath(xml, ~x"//channel/item/pubDate/text()"sl) == [
@@ -160,7 +160,7 @@ test "gets a feed (RSS)", %{conn: conn} do
|> response(200)
xml = parse(response)
- assert xpath(xml, ~x"//channel/title/text()") == '#pleromaart'
+ assert xpath(xml, ~x"//channel/title/text()") == ~c"#pleromaart"
assert xpath(xml, ~x"//channel/description/text()"s) ==
"These are public toots tagged with #pleromaart. You can interact with them if you have an account anywhere in the fediverse."
@@ -174,10 +174,10 @@ test "gets a feed (RSS)", %{conn: conn} do
resp = response(conn, 200)
xml = parse(resp)
- assert xpath(xml, ~x"//channel/title/text()") == '#pleromaart'
+ assert xpath(xml, ~x"//channel/title/text()") == ~c"#pleromaart"
assert xpath(xml, ~x"//channel/item/title/text()"l) == [
- 'yeah #PleromaArt'
+ ~c"yeah #PleromaArt"
]
end
diff --git a/test/pleroma/web/feed/user_controller_test.exs b/test/pleroma/web/feed/user_controller_test.exs
index d3c4108de0..1c17d47b43 100644
--- a/test/pleroma/web/feed/user_controller_test.exs
+++ b/test/pleroma/web/feed/user_controller_test.exs
@@ -88,7 +88,7 @@ test "gets an atom feed", %{conn: conn, user: user, object: object, max_id: max_
|> SweetXml.parse()
|> SweetXml.xpath(~x"//entry/title/text()"l)
- assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as']
+ assert activity_titles == [~c"Won't, didn'...", ~c"2hu", ~c"2hu & as"]
assert resp =~ FeedView.escape(object.data["content"])
assert resp =~ FeedView.escape(object.data["summary"])
assert resp =~ FeedView.escape(object.data["context"])
@@ -104,7 +104,7 @@ test "gets an atom feed", %{conn: conn, user: user, object: object, max_id: max_
|> SweetXml.parse()
|> SweetXml.xpath(~x"//entry/title/text()"l)
- assert activity_titles == ['2hu & as']
+ assert activity_titles == [~c"2hu & as"]
end
test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id} do
@@ -119,7 +119,7 @@ test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id
|> SweetXml.parse()
|> SweetXml.xpath(~x"//item/title/text()"l)
- assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as']
+ assert activity_titles == [~c"Won't, didn'...", ~c"2hu", ~c"2hu & as"]
assert resp =~ FeedView.escape(object.data["content"])
assert resp =~ FeedView.escape(object.data["summary"])
assert resp =~ FeedView.escape(object.data["context"])
@@ -135,7 +135,7 @@ test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id
|> SweetXml.parse()
|> SweetXml.xpath(~x"//item/title/text()"l)
- assert activity_titles == ['2hu & as']
+ assert activity_titles == [~c"2hu & as"]
end
test "returns 404 for a missing feed", %{conn: conn} do
@@ -167,7 +167,7 @@ test "returns feed with public and unlisted activities", %{conn: conn} do
|> SweetXml.xpath(~x"//entry/title/text()"l)
|> Enum.sort()
- assert activity_titles == ['public', 'unlisted']
+ assert activity_titles == [~c"public", ~c"unlisted"]
end
test "returns 404 when the user is remote", %{conn: conn} do
@@ -208,7 +208,7 @@ test "does not mangle HTML entities midway", %{
|> SweetXml.parse()
|> SweetXml.xpath(~x"//entry/title/text()"l)
- assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as']
+ assert activity_titles == [~c"Won't, didn'...", ~c"2hu", ~c"2hu & as"]
assert resp =~ FeedView.escape(object.data["content"])
assert resp =~ FeedView.escape(object.data["summary"])
assert resp =~ FeedView.escape(object.data["context"])
diff --git a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs
index d4912691ae..6ea7d15629 100644
--- a/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs
@@ -154,6 +154,7 @@ test "/api/v2/media, multilang, empty description_map", %{conn: conn, image: ima
end
test "/api/v2/media, upload_limit", %{conn: conn, user: user} do
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
desc = "Description of the binary"
upload_limit = Config.get([:instance, :upload_limit]) * 8 + 8
diff --git a/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs
index ad4144da44..d38767c960 100644
--- a/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs
@@ -130,7 +130,6 @@ test "search local-only status as an anonymous user" do
assert [] = results["statuses"]
end
- @tag capture_log: true
test "constructs hashtags from search query", %{conn: conn} do
results =
conn
diff --git a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs
index b104c9bfbe..61675661e4 100644
--- a/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs
@@ -152,7 +152,6 @@ test "filtering", %{conn: conn, user: user} do
end
describe "public" do
- @tag capture_log: true
test "the public timeline", %{conn: conn} do
user = insert(:user)
@@ -828,7 +827,6 @@ test "filtering", %{user: user, conn: conn} do
describe "hashtag" do
setup do: oauth_access(["n/a"])
- @tag capture_log: true
test "hashtag timeline", %{conn: conn} do
following = insert(:user)
diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs
index 2ef1a3c00b..af8844678e 100644
--- a/test/pleroma/web/mastodon_api/views/status_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs
@@ -201,7 +201,6 @@ test "returns the direct conversation id when given the `direct_conversation_id`
assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
end
- @tag capture_log: true
test "returns a temporary ap_id based user for activities missing db users" do
user = insert(:user)
@@ -538,7 +537,9 @@ test "quoted private post" do
# Create a public post quoting the private post
quote_private =
- insert(:note_activity, note: insert(:note, data: %{"quoteUrl" => private_object.data["id"]}))
+ insert(:note_activity,
+ note: insert(:note, data: %{"quoteUrl" => private_object.data["id"]})
+ )
status = StatusView.render("show.json", %{activity: quote_private})
diff --git a/test/pleroma/web/o_auth/ldap_authorization_test.exs b/test/pleroma/web/o_auth/ldap_authorization_test.exs
index 5ab8236b57..07ce2eed84 100644
--- a/test/pleroma/web/o_auth/ldap_authorization_test.exs
+++ b/test/pleroma/web/o_auth/ldap_authorization_test.exs
@@ -71,7 +71,7 @@ test "creates a new user after successful LDAP authorization" do
equalityMatch: fn _type, _value -> :ok end,
wholeSubtree: fn -> :ok end,
search: fn _connection, _options ->
- {:ok, {:eldap_search_result, [{:eldap_entry, '', []}], []}}
+ {:ok, {:eldap_search_result, [{:eldap_entry, ~c"", []}], []}}
end,
close: fn _connection ->
send(self(), :close_connection)
diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs
index 92334487c5..10dcf0e623 100644
--- a/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs
@@ -159,8 +159,8 @@ test "download shared pack", %{conn: conn} do
{:ok, arch} = :zip.unzip(resp, [:memory])
- assert Enum.find(arch, fn {n, _} -> n == 'pack.json' end)
- assert Enum.find(arch, fn {n, _} -> n == 'blank.png' end)
+ assert Enum.find(arch, fn {n, _} -> n == ~c"pack.json" end)
+ assert Enum.find(arch, fn {n, _} -> n == ~c"blank.png" end)
end
test "non existing pack", %{conn: conn} do
@@ -454,7 +454,7 @@ test "when the fallback source doesn't have all the files", ctx do
method: :get,
url: "https://nonshared-pack"
} ->
- {:ok, {'empty.zip', empty_arch}} = :zip.zip('empty.zip', [], [:memory])
+ {:ok, {~c"empty.zip", empty_arch}} = :zip.zip(~c"empty.zip", [], [:memory])
text(empty_arch)
end)
diff --git a/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs b/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs
index f17add774a..c78c03aba9 100644
--- a/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs
+++ b/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do
alias Pleroma.Chat
alias Pleroma.Chat.MessageReference
alias Pleroma.Object
+ alias Pleroma.Tests.ObanHelpers
alias Pleroma.UnstubbedConfigMock, as: ConfigMock
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
@@ -70,6 +71,8 @@ test "it displays a chat message" do
media_id: upload.id
)
+ ObanHelpers.perform_all()
+
object = Object.normalize(activity, fetch: false)
cm_ref = MessageReference.for_chat_and_object(chat, object)
diff --git a/test/pleroma/web/push/impl_test.exs b/test/pleroma/web/push/impl_test.exs
index cf7a504189..6b4544a506 100644
--- a/test/pleroma/web/push/impl_test.exs
+++ b/test/pleroma/web/push/impl_test.exs
@@ -5,6 +5,7 @@
defmodule Pleroma.Web.Push.ImplTest do
use Pleroma.DataCase, async: true
+ import ExUnit.CaptureLog
import Mox
import Pleroma.Factory
@@ -34,17 +35,6 @@ defmodule Pleroma.Web.Push.ImplTest do
:ok
end
- @sub %{
- endpoint: "https://example.com/example/1234",
- keys: %{
- auth: "8eDyX_uCN0XRhSbY5hs7Hg==",
- p256dh:
- "BCIWgsnyXDv1VkhqL2P7YRBvdeuDnlwAPT2guNhdIoW3IP7GmHh1SMKPLxRf7x8vJy6ZFK3ol2ohgn_-0yP7QQA="
- }
- }
- @api_key "BASgACIHpN1GYgzSRp"
- @message "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..."
-
test "performs sending notifications" do
user = insert(:user)
user2 = insert(:user)
@@ -70,39 +60,65 @@ test "performs sending notifications" do
type: "mention"
)
- assert Impl.perform(notif) == {:ok, [:ok, :ok]}
+ Impl.build(notif)
+ |> Enum.each(fn push -> assert match?(:ok, Impl.deliver(push)) end)
end
- @tag capture_log: true
- test "returns error if notif does not match " do
- assert Impl.perform(%{}) == {:error, :unknown_type}
+ test "returns error if notification activity type does not match" do
+ assert capture_log(fn ->
+ assert Impl.build(%{}) == []
+ end) =~ "WebPush: unknown activity type"
end
- test "successful message sending" do
- assert Impl.push_message(@message, @sub, @api_key, %Subscription{}) == :ok
- end
-
- @tag capture_log: true
test "fail message sending" do
- assert Impl.push_message(
- @message,
- Map.merge(@sub, %{endpoint: "https://example.com/example/bad"}),
- @api_key,
- %Subscription{}
- ) == :error
+ user = insert(:user)
+
+ insert(:push_subscription,
+ user: user,
+ endpoint: "https://example.com/example/bad",
+ data: %{alerts: %{"follow" => true}}
+ )
+
+ other_user = insert(:user)
+ {:ok, _, _, activity} = CommonAPI.follow(user, other_user)
+
+ notif =
+ insert(:notification,
+ user: user,
+ activity: activity,
+ type: "follow"
+ )
+
+ [push] = Impl.build(notif)
+
+ assert Impl.deliver(push) == :error
end
test "delete subscription if result send message between 400..500" do
- subscription = insert(:push_subscription)
+ user = insert(:user)
- assert Impl.push_message(
- @message,
- Map.merge(@sub, %{endpoint: "https://example.com/example/not_found"}),
- @api_key,
- subscription
- ) == :ok
+ bad_subscription =
+ insert(:push_subscription,
+ user: user,
+ endpoint: "https://example.com/example/not_found",
+ data: %{alerts: %{"follow" => true}}
+ )
- refute Pleroma.Repo.get(Subscription, subscription.id)
+ other_user = insert(:user)
+ {:ok, _, _, activity} = CommonAPI.follow(user, other_user)
+
+ notif =
+ insert(:notification,
+ user: user,
+ activity: activity,
+ type: "follow"
+ )
+
+ [push] = Impl.build(notif)
+
+ assert Impl.deliver(push) == :ok
+
+ refute Pleroma.Repo.get(Subscription, bad_subscription.id)
end
test "deletes subscription when token has been deleted" do
@@ -131,7 +147,7 @@ test "renders title and body for create activity" do
user,
object
) ==
- "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..."
+ "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis finibus turpis."
assert Impl.format_title(%{activity: activity, type: "mention"}) ==
"New Mention"
@@ -163,7 +179,7 @@ test "renders title and body for announce activity" do
object = Object.normalize(activity, fetch: false)
assert Impl.format_body(%{activity: announce_activity}, user, object) ==
- "@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..."
+ "@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis finibus turpis."
assert Impl.format_title(%{activity: announce_activity, type: "reblog"}) ==
"New Repeat"
@@ -234,6 +250,29 @@ test "renders title for create activity with direct visibility" do
"New Direct Message"
end
+ test "renders poll notification" do
+ user = insert(:user)
+ question = insert(:question, user: user)
+ activity = insert(:question_activity, question: question)
+
+ {:ok, [notification]} = Notification.create_poll_notifications(activity)
+
+ expected_title = "Poll Results"
+
+ expected_body =
+ """
+ Which flavor of ice cream do you prefer?
+
+ ○ chocolate
+ ○ vanilla
+ """
+ |> String.trim_trailing("\n")
+
+ content = Impl.build_content(notification, user, question)
+
+ assert match?(%{title: ^expected_title, body: ^expected_body}, content)
+ end
+
describe "build_content/3" do
test "builds content for chat messages" do
user = insert(:user)
@@ -332,7 +371,10 @@ test "returns regular content when hiding contents option disabled" do
user = insert(:user, nickname: "Bob")
user2 =
- insert(:user, nickname: "Rob", notification_settings: %{hide_notification_contents: false})
+ insert(:user,
+ nickname: "Rob",
+ notification_settings: %{hide_notification_contents: false}
+ )
{:ok, activity} =
CommonAPI.post(user, %{
@@ -348,7 +390,7 @@ test "returns regular content when hiding contents option disabled" do
assert Impl.build_content(notif, actor, object) == %{
body:
- "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini...",
+ "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis finibus turpis.",
title: "New Direct Message"
}
@@ -366,7 +408,7 @@ test "returns regular content when hiding contents option disabled" do
assert Impl.build_content(notif, actor, object) == %{
body:
- "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini...",
+ "@Bob: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis finibus turpis.",
title: "New Mention"
}
@@ -384,4 +426,23 @@ test "returns regular content when hiding contents option disabled" do
}
end
end
+
+ test "build/1 notification payload body starts with nickname of actor the notification originated from" do
+ user = insert(:user, nickname: "Bob")
+ user2 = insert(:user, nickname: "Tom")
+ insert(:push_subscription, user: user2, data: %{alerts: %{"mention" => true}})
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ status: "@Tom Hey are you okay?"
+ })
+
+ {:ok, [notification]} = Notification.create_notifications(activity)
+
+ [push] = Impl.build(notification)
+
+ {:ok, payload} = Jason.decode(push.payload)
+
+ assert String.starts_with?(payload["body"], "@Bob:")
+ end
end
diff --git a/test/pleroma/web/rich_media/card_test.exs b/test/pleroma/web/rich_media/card_test.exs
index 516ac99512..c76df99e20 100644
--- a/test/pleroma/web/rich_media/card_test.exs
+++ b/test/pleroma/web/rich_media/card_test.exs
@@ -5,6 +5,7 @@
defmodule Pleroma.Web.RichMedia.CardTest do
use Pleroma.DataCase, async: true
+ alias Pleroma.Tests.ObanHelpers
alias Pleroma.UnstubbedConfigMock, as: ConfigMock
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.RichMedia.Card
@@ -36,6 +37,8 @@ test "crawls URL in activity" do
content_type: "text/markdown"
})
+ ObanHelpers.perform_all()
+
assert %Card{url_hash: ^url_hash, fields: _} = Card.get_by_activity(activity)
end
@@ -50,6 +53,7 @@ test "recrawls URLs on status edits/updates" do
# Force a backfill
Card.get_by_activity(activity)
+ ObanHelpers.perform_all()
assert match?(
%Card{url_hash: ^original_url_hash, fields: _},
@@ -62,6 +66,7 @@ test "recrawls URLs on status edits/updates" do
# Force a backfill
Card.get_by_activity(activity)
+ ObanHelpers.perform_all()
assert match?(
%Card{url_hash: ^updated_url_hash, fields: _},
diff --git a/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs b/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs
index cc28aa7f39..e02dd437af 100644
--- a/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs
+++ b/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs
@@ -4,10 +4,11 @@
defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrlTest do
use Pleroma.DataCase, async: false
- use Oban.Testing, repo: Pleroma.Repo
+ use Oban.Testing, repo: Pleroma.Repo, testing: :inline
import Mox
+ alias Pleroma.Tests.ObanHelpers
alias Pleroma.UnstubbedConfigMock, as: ConfigMock
alias Pleroma.Web.RichMedia.Card
alias Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl
@@ -74,9 +75,19 @@ test "s3 signed url is parsed and correct ttl is set for rich media" do
Card.get_or_backfill_by_url(url)
- assert_enqueued(worker: Pleroma.Workers.RichMediaExpirationWorker, args: %{"url" => url})
+ # Find the backfill job
+ expected_job =
+ [
+ worker: "Pleroma.Workers.RichMediaWorker",
+ args: %{"op" => "backfill", "url" => url}
+ ]
- [%Oban.Job{scheduled_at: scheduled_at}] = all_enqueued()
+ assert_enqueued(expected_job)
+
+ # Run it manually
+ ObanHelpers.perform_all()
+
+ [%Oban.Job{scheduled_at: scheduled_at} | _] = all_enqueued()
timestamp_dt = Timex.parse!(timestamp, "{ISO:Basic:Z}")
diff --git a/test/pleroma/web/rich_media/parser/ttl/opengraph_test.exs b/test/pleroma/web/rich_media/parser/ttl/opengraph_test.exs
index 770968d477..6805e786df 100644
--- a/test/pleroma/web/rich_media/parser/ttl/opengraph_test.exs
+++ b/test/pleroma/web/rich_media/parser/ttl/opengraph_test.exs
@@ -8,6 +8,7 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.OpengraphTest do
import Mox
+ alias Pleroma.Tests.ObanHelpers
alias Pleroma.UnstubbedConfigMock, as: ConfigMock
alias Pleroma.Web.RichMedia.Card
@@ -36,6 +37,21 @@ test "OpenGraph TTL value is honored" do
Card.get_or_backfill_by_url(url)
- assert_enqueued(worker: Pleroma.Workers.RichMediaExpirationWorker, args: %{"url" => url})
+ # Find the backfill job
+ expected_job =
+ [
+ worker: "Pleroma.Workers.RichMediaWorker",
+ args: %{"op" => "backfill", "url" => url}
+ ]
+
+ assert_enqueued(expected_job)
+
+ # Run it manually
+ ObanHelpers.perform_all()
+
+ assert_enqueued(
+ worker: Pleroma.Workers.RichMediaWorker,
+ args: %{"op" => "expire", "url" => url}
+ )
end
end
diff --git a/test/pleroma/web/rich_media/parser_test.exs b/test/pleroma/web/rich_media/parser_test.exs
index 3fcb5c8089..a5f2563a20 100644
--- a/test/pleroma/web/rich_media/parser_test.exs
+++ b/test/pleroma/web/rich_media/parser_test.exs
@@ -13,6 +13,8 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
end
+ setup_all do: clear_config([:rich_media, :enabled], true)
+
test "returns error when no metadata present" do
assert {:error, _} = Parser.parse("https://example.com/empty")
end
@@ -127,4 +129,10 @@ test "refuses to crawl URLs of private network from posts" do
assert :error == Parser.parse(url)
end)
end
+
+ test "returns error when disabled" do
+ clear_config([:rich_media, :enabled], false)
+
+ assert match?({:error, :rich_media_disabled}, Parser.parse("https://example.com/ogp"))
+ end
end
diff --git a/test/pleroma/web/web_finger_test.exs b/test/pleroma/web/web_finger_test.exs
index 23aefb5640..44c0d75556 100644
--- a/test/pleroma/web/web_finger_test.exs
+++ b/test/pleroma/web/web_finger_test.exs
@@ -227,7 +227,6 @@ test "prevents spoofing" do
end
end
- @tag capture_log: true
test "prevents forgeries" do
Tesla.Mock.mock(fn
%{url: "https://fba.ryona.agency/.well-known/webfinger?resource=acct:graf@fba.ryona.agency"} ->
diff --git a/test/pleroma/workers/poll_worker_test.exs b/test/pleroma/workers/poll_worker_test.exs
new file mode 100644
index 0000000000..749df8affd
--- /dev/null
+++ b/test/pleroma/workers/poll_worker_test.exs
@@ -0,0 +1,49 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.PollWorkerTest do
+ use Pleroma.DataCase
+ use Oban.Testing, repo: Pleroma.Repo
+
+ import Mock
+ import Pleroma.Factory
+
+ alias Pleroma.Workers.PollWorker
+
+ test "poll notification job" do
+ user = insert(:user)
+ question = insert(:question, user: user)
+ activity = insert(:question_activity, question: question)
+
+ PollWorker.schedule_poll_end(activity)
+
+ expected_job_args = %{"activity_id" => activity.id, "op" => "poll_end"}
+
+ assert_enqueued(args: expected_job_args)
+
+ with_mocks([
+ {
+ Pleroma.Web.Streamer,
+ [],
+ [
+ stream: fn _, _ -> nil end
+ ]
+ },
+ {
+ Pleroma.Web.Push,
+ [],
+ [
+ send: fn _ -> nil end
+ ]
+ }
+ ]) do
+ [job] = all_enqueued(worker: PollWorker)
+ PollWorker.perform(job)
+
+ # Ensure notifications were streamed out when job executes
+ assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], :_))
+ assert called(Pleroma.Web.Push.send(:_))
+ end
+ end
+end
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 06545f2048..8730b83e80 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -249,6 +249,7 @@ def question_factory(attrs \\ %{}) do
"cc" => [user.follower_address],
"context" => Pleroma.Web.ActivityPub.Utils.generate_context_id(),
"closed" => DateTime.utc_now() |> DateTime.add(86_400) |> DateTime.to_iso8601(),
+ "content" => "Which flavor of ice cream do you prefer?",
"oneOf" => [
%{
"type" => "Note",
diff --git a/test/test_helper.exs b/test/test_helper.exs
index a117584ae8..fed7ce8a72 100644
--- a/test/test_helper.exs
+++ b/test/test_helper.exs
@@ -4,9 +4,9 @@
Code.put_compiler_option(:warnings_as_errors, true)
-ExUnit.configure(max_cases: System.schedulers_online())
+ExUnit.configure(capture_log: true, max_cases: System.schedulers_online())
-ExUnit.start(exclude: [:federated, :erratic])
+ExUnit.start(exclude: [:federated])
if match?({:unix, :darwin}, :os.type()) do
excluded = ExUnit.configuration() |> Keyword.get(:exclude, [])