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, [])