Merge branch 'fork' into backend-new

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-06-30 12:06:48 +02:00
commit fc32646f7f
281 changed files with 1703 additions and 817 deletions

3
.gitignore vendored
View file

@ -61,3 +61,6 @@ pleroma.iml
*~ *~
*# *#
*.swp *.swp
archive-*
.gitlab-ci-local

View file

@ -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 variables: &global_variables
# Only used for the release # Only used for the release
@ -18,9 +18,7 @@ workflow:
- if: $CI_COMMIT_BRANCH - if: $CI_COMMIT_BRANCH
cache: &global_cache_policy cache: &global_cache_policy
key: key: $CI_JOB_IMAGE-$CI_COMMIT_SHORT_SHA
files:
- mix.lock
paths: paths:
- deps - deps
- _build - _build
@ -72,7 +70,7 @@ check-changelog:
tags: tags:
- amd64 - amd64
build-1.13.4: build-1.13.4-otp-25:
extends: extends:
- .build_changes_policy - .build_changes_policy
- .using-ci-base - .using-ci-base
@ -80,13 +78,12 @@ build-1.13.4:
script: script:
- mix compile --force - mix compile --force
build-1.15.7-otp-25: build-1.15.8-otp-26:
extends: extends:
- .build_changes_policy - .build_changes_policy
- .using-ci-base - .using-ci-base
stage: build stage: build
image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15-otp25 image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15.8-otp-26
allow_failure: true
script: script:
- mix compile --force - mix compile --force
@ -121,7 +118,7 @@ benchmark:
- mix ecto.migrate - mix ecto.migrate
- mix pleroma.load_testing - mix pleroma.load_testing
unit-testing-1.12.3: unit-testing-1.13.4-otp-25:
extends: extends:
- .build_changes_policy - .build_changes_policy
- .using-ci-base - .using-ci-base
@ -136,7 +133,7 @@ unit-testing-1.12.3:
script: &testing_script script: &testing_script
- mix ecto.create - mix ecto.create
- mix ecto.migrate - mix ecto.migrate
- mix test --cover --preload-modules - mix pleroma.test_runner --cover --preload-modules
coverage: '/^Line total: ([^ ]*%)$/' coverage: '/^Line total: ([^ ]*%)$/'
artifacts: artifacts:
reports: reports:
@ -144,34 +141,19 @@ unit-testing-1.12.3:
coverage_format: cobertura coverage_format: cobertura
path: coverage.xml path: coverage.xml
unit-testing-1.15.7-otp-25: unit-testing-1.15.8-otp-26:
extends: extends:
- .build_changes_policy - .build_changes_policy
- .using-ci-base - .using-ci-base
stage: test stage: test
image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15-otp25 image: git.pleroma.social:5050/pleroma/pleroma/ci-base:elixir-1.15.8-otp-26
allow_failure: true
cache: *testing_cache_policy cache: *testing_cache_policy
services: *testing_services services: *testing_services
script: *testing_script script: *testing_script
unit-testing-1.12-erratic: formatting-1.15:
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:
extends: .build_changes_policy extends: .build_changes_policy
image: &formatting_elixir elixir:1.13-alpine image: &formatting_elixir elixir:1.15-alpine
stage: lint stage: lint
cache: *testing_cache_policy cache: *testing_cache_policy
before_script: &current_bfr_script before_script: &current_bfr_script

View file

@ -0,0 +1 @@
Fix Emoji object IDs not always being valid

View file

@ -0,0 +1 @@
Elixir Logger configuration is now longer permitted through AdminFE and ConfigDB

View file

@ -0,0 +1 @@
Add options to the mix prune_objects task

View file

@ -0,0 +1 @@
Update Bandit to 1.5.2

View file

View file

View file

0
changelog.d/cleanup.skip Normal file
View file

View file

@ -0,0 +1 @@
Restore Cowboy's ability to stream MediaProxy responses without Chunked encoding.

View file

View file

@ -0,0 +1,2 @@
Update dependencies held back due to old Elixir version

View file

@ -0,0 +1 @@
Update and extend NetBSD installation docs

View file

@ -0,0 +1 @@
Elixir 1.15 compatibility

View file

@ -0,0 +1 @@
Gun Connection Pool was not retrying to acquire a connection if the pool was full and stale connections were reclaimed

View file

@ -0,0 +1 @@
no comment

View file

@ -0,0 +1 @@
Add missing indexes on foreign key relationships

View file

@ -0,0 +1 @@
Permit passing --chunk and --step values to the Pleroma.Search.Indexer Mix task

View file

@ -0,0 +1 @@
noop

View file

View file

@ -0,0 +1 @@
Use proper workers for fetching pins instead of an ad-hoc task, fixing a potential fetch loop

View file

@ -0,0 +1 @@
Rich Media backfilling is now an Oban job

View file

View file

View file

@ -0,0 +1 @@
End of poll notifications were not streamed over websockets or web push

View file

View file

@ -0,0 +1 @@
User profile refreshes are now asynchronous

View file

@ -0,0 +1 @@
Video thumbnails were not being generated due to a negative cache lookup logic error

View file

@ -0,0 +1 @@
Render nice web push notifications for polls

View file

@ -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 # Single RUN statement, otherwise intermediate images are created
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run

View file

@ -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 .

View file

@ -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 .

View file

@ -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 # Single RUN statement, otherwise intermediate images are created
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run

View file

@ -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 .

View file

@ -83,8 +83,8 @@
scheme: "https://" scheme: "https://"
config :pleroma, Pleroma.Uploaders.IPFS, config :pleroma, Pleroma.Uploaders.IPFS,
post_gateway_url: nil, post_gateway_url: "http://localhost:5001",
get_gateway_url: nil get_gateway_url: "http://localhost:8080"
config :pleroma, :emoji, config :pleroma, :emoji,
shortcode_globs: ["/emoji/custom/**/*.png"], shortcode_globs: ["/emoji/custom/**/*.png"],
@ -132,6 +132,8 @@
] ]
# Configures Elixir's Logger # Configures Elixir's Logger
config :logger, backends: [:console]
config :logger, :console, config :logger, :console,
level: :debug, level: :debug,
format: "\n$time $metadata[$level] $message\n", format: "\n$time $metadata[$level] $message\n",

View file

@ -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, group: :pleroma,
key: :frontend_configurations, key: :frontend_configurations,

View file

@ -36,7 +36,7 @@
# different ports. # different ports.
# Do not include timestamps in development logs # 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 # Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive. # in production as building large stacktraces may be expensive.

View file

@ -20,6 +20,7 @@
config :phoenix, serve_endpoints: true config :phoenix, serve_endpoints: true
# Do not print debug messages in production # Do not print debug messages in production
config :logger, Logger.Backends.Console, level: :info
config :logger, :console, level: :info config :logger, :console, level: :info
config :logger, :ex_syslogger, level: :info config :logger, :ex_syslogger, level: :info

View file

@ -53,7 +53,8 @@
hostname: System.get_env("DB_HOST") || "localhost", hostname: System.get_env("DB_HOST") || "localhost",
port: System.get_env("DB_PORT") || "5432", port: System.get_env("DB_PORT") || "5432",
pool: Ecto.Adapters.SQL.Sandbox, 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 config :pleroma, :dangerzone, override_repo_pool_size: true
@ -189,6 +190,8 @@
streamer_registry: false, streamer_registry: false,
test_http_pools: true test_http_pools: true
config :pleroma, Pleroma.Web.Streaming, sync_streaming: true
config :pleroma, Pleroma.Uploaders.Uploader, timeout: 1_000 config :pleroma, Pleroma.Uploaders.Uploader, timeout: 1_000
config :pleroma, Pleroma.Emoji.Loader, test_emoji: true config :pleroma, Pleroma.Emoji.Loader, test_emoji: true

View file

@ -21,16 +21,18 @@ Replaces embedded objects with references to them in the `objects` table. Only n
mix pleroma.database remove_embedded_objects [option ...] mix pleroma.database remove_embedded_objects [option ...]
``` ```
### Options ### Options
- `--vacuum` - run `VACUUM FULL` after the embedded objects are replaced with their references - `--vacuum` - run `VACUUM FULL` after the embedded objects are replaced with their references
## Prune old remote posts from the database ## 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 !!! 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" === "OTP"
@ -45,7 +47,11 @@ This will prune remote posts older than 90 days (configurable with [`config :ple
``` ```
### Options ### 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 ## Create a conversation for all existing DMs
@ -93,6 +99,9 @@ Can be safely re-run
## Vacuum the database ## 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 ### Analyze
Running an `analyze` vacuum job can improve performance by updating statistics used by the query planner. **It is safe to cancel this.** Running an `analyze` vacuum job can improve performance by updating statistics used by the query planner. **It is safe to cancel this.**

View file

@ -853,7 +853,7 @@ config :logger,
backends: [{ExSyslogger, :ex_syslogger}] backends: [{ExSyslogger, :ex_syslogger}]
config :logger, :ex_syslogger, config :logger, :ex_syslogger,
level: :warn level: :warning
``` ```
Another example, keeping console output and adding the pid to syslog output: Another example, keeping console output and adding the pid to syslog output:
@ -862,7 +862,7 @@ config :logger,
backends: [:console, {ExSyslogger, :ex_syslogger}] backends: [:console, {ExSyslogger, :ex_syslogger}]
config :logger, :ex_syslogger, config :logger, :ex_syslogger,
level: :warn, level: :warning,
option: [:pid, :ndelay] option: [:pid, :ndelay]
``` ```

View file

@ -1,7 +1,7 @@
## Required dependencies ## Required dependencies
* PostgreSQL >=11.0 * PostgreSQL >=11.0
* Elixir >=1.13.0 <1.15 * Elixir >=1.13.0 <1.17
* Erlang OTP >=22.2.0 (supported: <27) * Erlang OTP >=22.2.0 (supported: <27)
* git * git
* file / libmagic * file / libmagic

View file

@ -2,14 +2,41 @@
{! backend/installation/generic_dependencies.include !} {! 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 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 Note that `postgresql11-contrib` is needed for the Postgres extensions
Pleroma uses. 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. 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` `# 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 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: Create a user for Pleroma:
``` ```
@ -68,41 +72,98 @@ $ cd /home/pleroma
$ git clone -b stable https://git.pleroma.social/pleroma/pleroma.git $ 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 $ cd /home/pleroma/pleroma
$ export MIX_ENV=prod
$ mix deps.get $ 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 ## Install media / graphics packages (optional, see [`docs/installation/optional/media_graphics_packages.md`](../installation/optional/media_graphics_packages.md))
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 `# 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: 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 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`. `password`.
Once this is done, restart Postgres with `# /etc/rc.d/pgsql restart`. Once this is done, restart Postgres with `# /etc/rc.d/pgsql restart`.
Run the database migrations. Run the database migrations.
### pkgsrc installation
```
pleroma_ctl migrate
```
### Source installation
You will need to do this whenever you update with `git pull`: You will need to do this whenever you update with `git pull`:
``` ```
$ cd /home/pleroma/pleroma
$ MIX_ENV=prod mix ecto.migrate $ MIX_ENV=prod mix ecto.migrate
``` ```
## Configuring nginx ## Configuring nginx
Install the example configuration file Install the example configuration file
`/home/pleroma/pleroma/installation/pleroma.nginx` to (`$PREFIX/share/examples/pleroma/pleroma.nginx` or `/home/pleroma/pleroma/installation/pleroma.nginx`) to
`/usr/pkg/etc/nginx.conf`. `$PREFIX/etc/nginx.conf`.
Note that it will need to be wrapped in a `http {}` block. You should add 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: 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 --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 # cp /home/pleroma/pleroma/installation/netbsd/rc.d/pleroma /etc/rc.d/pleroma
# chmod +x /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=YES
pleroma_home="/home/pleroma"
pleroma_user="pleroma"
``` ```
Run `# /etc/rc.d/pleroma start` to start Pleroma.
## Conclusion ## 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. 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 Make sure your time is in sync, or other instances will receive your posts with

View file

@ -1,11 +1,14 @@
#!/bin/sh #!/bin/sh
# PROVIDE: pleroma # PROVIDE: pleroma
# REQUIRE: DAEMON pgsql # REQUIRE: DAEMON pgsql nginx
if [ -f /etc/rc.subr ]; then if [ -f /etc/rc.subr ]; then
. /etc/rc.subr . /etc/rc.subr
fi fi
pleroma_home="/home/pleroma"
pleroma_user="pleroma"
name="pleroma" name="pleroma"
rcvar=${name} rcvar=${name}
command="/usr/pkg/bin/elixir" command="/usr/pkg/bin/elixir"
@ -19,10 +22,10 @@ pleroma_env="HOME=${pleroma_home} MIX_ENV=prod"
check_pidfile() check_pidfile()
{ {
pid=$(pgrep -U "${pleroma_user}" /bin/beam.smp$) 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 # newer NetBSD
load_rc_config ${name} load_rc_config ${name}
run_rc_command "$1" run_rc_command "$1"
@ -39,7 +42,7 @@ else
stop) stop)
echo "Stopping ${name}." echo "Stopping ${name}."
check_pidfile check_pidfile
! [ -n ${pid} ] && kill ${pid} ! [ -n "${pid}" ] && kill "${pid}"
;; ;;
restart) restart)

View file

@ -14,7 +14,8 @@ defmodule Mix.Pleroma do
:swoosh, :swoosh,
:timex, :timex,
:fast_html, :fast_html,
:oban :oban,
:logger_backends
] ]
@cachex_children ["object", "user", "scrubber", "web_resp"] @cachex_children ["object", "user", "scrubber", "web_resp"]
@doc "Common functions to be reused in mix tasks" @doc "Common functions to be reused in mix tasks"

View file

@ -67,43 +67,168 @@ def run(["prune_objects" | args]) do
OptionParser.parse( OptionParser.parse(
args, args,
strict: [ strict: [
vacuum: :boolean vacuum: :boolean,
keep_threads: :boolean,
keep_non_public: :boolean,
prune_orphaned_activities: :boolean
] ]
) )
start_pleroma() start_pleroma()
deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) 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 = log_message =
NaiveDateTime.utc_now() if Keyword.get(options, :keep_non_public) do
|> NaiveDateTime.add(-(deadline * 86_400)) log_message <> ", keeping non public posts"
else
log_message
end
from(o in Object, log_message =
where: if Keyword.get(options, :keep_threads) do
fragment( log_message <> ", keeping threads intact"
"?->'to' \\? ? OR ?->'cc' \\? ?", else
o.data, log_message
^Pleroma.Constants.as_public(), end
o.data,
^Pleroma.Constants.as_public() log_message =
), if Keyword.get(options, :prune_orphaned_activities) do
where: o.inserted_at < ^time_deadline, log_message <> ", pruning orphaned activities"
where: 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()) fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host())
) )
end
|> Repo.delete_all(timeout: :infinity) |> 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 DELETE FROM hashtags AS ht
WHERE NOT EXISTS ( WHERE NOT EXISTS (
SELECT 1 FROM hashtags_objects hto SELECT 1 FROM hashtags_objects hto
WHERE ht.id = hto.hashtag_id) WHERE ht.id = hto.hashtag_id)
""" """
|> Repo.query()
Repo.query(prune_hashtags_query)
if Keyword.get(options, :vacuum) do if Keyword.get(options, :vacuum) do
Maintenance.vacuum("full") Maintenance.vacuum("full")
@ -226,7 +351,7 @@ def run(["set_text_search_config", tsconfig]) do
) )
end end
shell_info('Done.') shell_info(~c"Done.")
end end
end end

View file

@ -33,15 +33,18 @@ def run(["index" | options]) do
OptionParser.parse( OptionParser.parse(
options, options,
strict: [ strict: [
limit: :integer chunk: :integer,
limit: :integer,
step: :integer
] ]
) )
start_pleroma() start_pleroma()
chunk_size = Keyword.get(options, :chunk, 100)
limit = Keyword.get(options, :limit, 100_000) limit = Keyword.get(options, :limit, 100_000)
per_step = Keyword.get(options, :step, 1000)
per_step = 1000
chunks = max(div(limit, per_step), 1) chunks = max(div(limit, per_step), 1)
1..chunks 1..chunks
@ -65,7 +68,7 @@ def run(["index" | options]) do
IO.puts("Got #{length(ids)} activities, adding to indexer") IO.puts("Got #{length(ids)} activities, adding to indexer")
ids ids
|> Enum.chunk_every(100) |> Enum.chunk_every(chunk_size)
|> Enum.each(fn chunk -> |> Enum.each(fn chunk ->
IO.puts("Adding #{length(chunk)} activities to indexing queue") IO.puts("Adding #{length(chunk)} activities to indexing queue")

View file

@ -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

View file

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Config.TransferTask do 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 with {_, true} <- {:configurable, Config.get(:configurable_from_database)} do
# We need to restart applications for loaded settings take effect # We need to restart applications for loaded settings take effect
{logger, other} = settings =
(Repo.all(ConfigDB) ++ deleted_settings) (Repo.all(ConfigDB) ++ deleted_settings)
|> Enum.map(&merge_with_default/1) |> 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() started_applications = Application.started_applications()
@ -63,7 +58,7 @@ def load_and_update_env(deleted_settings \\ [], restart_pleroma? \\ true) do
[:pleroma | reject] [:pleroma | reject]
end end
other settings
|> Enum.map(&update/1) |> Enum.map(&update/1)
|> Enum.uniq() |> Enum.uniq()
|> Enum.reject(&(&1 in reject)) |> 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} {group, key, value, merged}
end 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 defp update({group, key, value, merged}) do
try do try do
:ok = update_env(group, key, merged) :ok = update_env(group, key, merged)

View file

@ -165,8 +165,7 @@ defp only_full_update?(%ConfigDB{group: group, key: key}) do
{:pleroma, :ecto_repos}, {:pleroma, :ecto_repos},
{:mime, :types}, {:mime, :types},
{:cors_plug, [:max_age, :methods, :expose, :headers]}, {:cors_plug, [:max_age, :methods, :expose, :headers]},
{:swarm, :node_blacklist}, {:swarm, :node_blacklist}
{:logger, :backends}
] ]
Enum.any?(full_key_update, fn 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() @spec module_name?(String.t()) :: boolean()
def module_name?(string) do def module_name?(string) do
Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Ueberauth|Swoosh)\./, string) or if String.contains?(string, ".") do
string in ["Oban", "Ueberauth", "ExSyslogger", "ConcurrentLimiter"] [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
end end

View file

@ -418,10 +418,10 @@ defp downloadable?(pack) do
end end
defp create_archive_and_cache(pack, hash) do 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}} = {: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]) ttl_per_file = Pleroma.Config.get!([:emoji, :shared_pack_cache_seconds_per_file])
overall_ttl = :timer.seconds(ttl_per_file * Enum.count(files)) 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 with :ok <- File.mkdir_p!(local_pack.path) do
files = Enum.map(remote_pack["files"], fn {_, path} -> to_charlist(path) end) files = Enum.map(remote_pack["files"], fn {_, path} -> to_charlist(path) end)
# Fallback cannot contain a pack.json file # 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) :zip.unzip(archive, cwd: to_charlist(local_pack.path), file_list: files)
end end

View file

@ -9,7 +9,7 @@ defp registry, do: Pleroma.Gun.ConnectionPool
def start_monitor do def start_monitor do
pid = pid =
case GenServer.start_link(__MODULE__, [], name: {:via, Registry, {registry(), "reclaimer"}}) do case GenServer.start(__MODULE__, [], name: {:via, Registry, {registry(), "reclaimer"}}) do
{:ok, pid} -> {:ok, pid} ->
pid pid

View file

@ -5,6 +5,9 @@
defmodule Pleroma.Gun.ConnectionPool.WorkerSupervisor do defmodule Pleroma.Gun.ConnectionPool.WorkerSupervisor do
@moduledoc "Supervisor for pool workers. Does not do anything except enforce max connection limit" @moduledoc "Supervisor for pool workers. Does not do anything except enforce max connection limit"
alias Pleroma.Config
alias Pleroma.Gun.ConnectionPool.Worker
use DynamicSupervisor use DynamicSupervisor
def start_link(opts) do def start_link(opts) do
@ -14,21 +17,28 @@ def start_link(opts) do
def init(_opts) do def init(_opts) do
DynamicSupervisor.init( DynamicSupervisor.init(
strategy: :one_for_one, strategy: :one_for_one,
max_children: Pleroma.Config.get([:connections_pool, :max_connections]) max_children: Config.get([:connections_pool, :max_connections])
) )
end end
def start_worker(opts, last_attempt \\ false) do def start_worker(opts, last_attempt \\ false)
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]
if Enum.any?(funs, fn fun -> fun.() end) do def start_worker(opts, true) do
:telemetry.execute([:pleroma, :connection_pool, :provision_failure], %{opts: opts}) case DynamicSupervisor.start_child(__MODULE__, {Worker, opts}) do
{:error, :pool_full} {:error, :max_children} ->
else :telemetry.execute([:pleroma, :connection_pool, :provision_failure], %{opts: opts})
start_worker(opts, true) {:error, :pool_full}
end
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 ->
res res

View file

@ -25,7 +25,7 @@ def missing_dependencies do
end end
def image_resize(url, options) do 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} <- {:ok, resized} <-
Operation.thumbnail_buffer(env.body, options.max_width, Operation.thumbnail_buffer(env.body, options.max_width,
height: options.max_height, height: options.max_height,
@ -45,8 +45,8 @@ def image_resize(url, options) do
@spec video_framegrab(String.t()) :: {:ok, binary()} | {:error, any()} @spec video_framegrab(String.t()) :: {:ok, binary()} | {:error, any()}
def video_framegrab(url) do def video_framegrab(url) do
with executable when is_binary(executable) <- System.find_executable("ffmpeg"), with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
false <- @cachex.exists?(:failed_media_helper_cache, url), {:ok, false} <- @cachex.exists?(:failed_media_helper_cache, url),
{:ok, env} <- HTTP.get(url, [], pool: :media), {:ok, env} <- HTTP.get(url, [], http_client_opts()),
{:ok, pid} <- StringIO.open(env.body) do {:ok, pid} <- StringIO.open(env.body) do
body_stream = IO.binstream(pid, 1) body_stream = IO.binstream(pid, 1)
@ -71,17 +71,19 @@ def video_framegrab(url) do
end) end)
case Task.yield(task, 5_000) do case Task.yield(task, 5_000) do
nil -> {:ok, result} ->
{:ok, result}
_ ->
Task.shutdown(task) Task.shutdown(task)
@cachex.put(:failed_media_helper_cache, url, nil) @cachex.put(:failed_media_helper_cache, url, nil)
{:error, {:ffmpeg, :timeout}} {:error, {:ffmpeg, :timeout}}
result ->
{:ok, result}
end end
else else
nil -> {:error, {:ffmpeg, :command_not_found}} nil -> {:error, {:ffmpeg, :command_not_found}}
{:error, _} = error -> error {:error, _} = error -> error
end end
end end
defp http_client_opts, do: Pleroma.Config.get([:media_proxy, :proxy_opts, :http], pool: :media)
end end

View file

@ -37,7 +37,7 @@ def head(url, headers \\ [], options \\ []), do: request(:head, url, "", headers
See `Pleroma.HTTP.request/5` 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()} {:ok, Env.t()} | {:error, any()}
def post(url, body, headers \\ [], options \\ []), def post(url, body, headers \\ [], options \\ []),
do: request(: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}` `{: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()} {:ok, Env.t()} | {:error, any()}
def request(method, url, body, headers, options) when is_binary(url) do def request(method, url, body, headers, options) when is_binary(url) do
uri = URI.parse(url) uri = URI.parse(url)

View file

@ -15,7 +15,7 @@ defmodule Pleroma.HTTP.AdapterHelper.Gun do
retry_timeout: 1_000 retry_timeout: 1_000
] ]
@type pool() :: :federation | :upload | :media | :default @type pool() :: :federation | :upload | :media | :rich_media | :default
@spec options(keyword(), URI.t()) :: keyword() @spec options(keyword(), URI.t()) :: keyword()
def options(incoming_opts \\ [], %URI{} = uri) do def options(incoming_opts \\ [], %URI{} = uri) do

View file

@ -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 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, local_only \\ true)
def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, local_only) 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]) |> Repo.update_all(set: [seen: true])
end end
@spec send(list(Notification.t())) :: :ok @doc "Streams a list of notifications over websockets and web push"
def send(notifications) do @spec stream(list(Notification.t())) :: :ok
def stream(notifications) do
Enum.each(notifications, fn notification -> Enum.each(notifications, fn notification ->
Streamer.stream(["user", "user:notification"], notification) Streamer.stream(["user", "user:notification"], notification)
Push.send(notification) Push.send(notification)

View file

@ -135,7 +135,10 @@ def make_update_object_data(original_data, new_data, date) do
else else
%{updated_object: updated_data} = %{updated_object: updated_data} =
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 updated_data
|> Map.put("updated", date) |> Map.put("updated", date)

View file

@ -8,7 +8,7 @@ defmodule Pleroma.ReverseProxy do
~w(if-unmodified-since if-none-match) ++ @range_headers ~w(if-unmodified-since if-none-match) ++ @range_headers
@resp_cache_headers ~w(etag date last-modified) @resp_cache_headers ~w(etag date last-modified)
@keep_resp_headers @resp_cache_headers ++ @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) ~w(content-range accept-ranges vary)
@default_cache_control_header "public, max-age=1209600" @default_cache_control_header "public, max-age=1209600"
@valid_resp_codes [200, 206, 304] @valid_resp_codes [200, 206, 304]
@ -180,6 +180,7 @@ defp response(conn, client, url, status, headers, opts) do
result = result =
conn conn
|> put_resp_headers(build_resp_headers(headers, opts)) |> put_resp_headers(build_resp_headers(headers, opts))
|> streaming_compat
|> send_chunked(status) |> send_chunked(status)
|> chunk_reply(client, opts) |> 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) @cachex.put(:failed_proxy_url_cache, url, true, ttl: ttl)
end 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 end

View file

@ -28,7 +28,7 @@ def search(user, search_query, options \\ []) do
|> Activity.with_preloaded_object() |> Activity.with_preloaded_object()
|> Activity.restrict_deactivated_users() |> Activity.restrict_deactivated_users()
|> restrict_public(user) |> restrict_public(user)
|> query_with(index_type, search_query, :websearch) |> query_with(index_type, search_query)
|> maybe_restrict_local(user) |> maybe_restrict_local(user)
|> maybe_restrict_author(author) |> maybe_restrict_author(author)
|> maybe_restrict_blocked(user) |> maybe_restrict_blocked(user)
@ -88,25 +88,7 @@ defp restrict_public(q, _user) do
) )
end end
defp query_with(q, :gin, search_query, :plain) do defp query_with(q, :gin, search_query) 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
%{rows: [[tsc]]} = %{rows: [[tsc]]} =
Ecto.Adapters.SQL.query!( Ecto.Adapters.SQL.query!(
Pleroma.Repo, Pleroma.Repo,
@ -124,19 +106,7 @@ defp query_with(q, :gin, search_query, :websearch) do
) )
end end
defp query_with(q, :rum, search_query, :plain) do defp query_with(q, :rum, search_query) 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
from([a, o] in q, from([a, o] in q,
where: where:
fragment( fragment(

View file

@ -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 defp url_from_spec(_upload, _base_url, {:url, url}), do: url
@spec base_url() :: binary
def base_url do def base_url do
uploader = @config_impl.get([Pleroma.Upload, :uploader]) 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]) public_endpoint = @config_impl.get([uploader, :public_endpoint])
case uploader do case uploader do
Pleroma.Uploaders.Local -> Pleroma.Uploaders.Local ->
upload_base_url || Pleroma.Web.Endpoint.url() <> "/media/" upload_base_url
Pleroma.Uploaders.S3 -> Pleroma.Uploaders.S3 ->
bucket = @config_impl.get([Pleroma.Uploaders.S3, :bucket]) bucket = @config_impl.get([Pleroma.Uploaders.S3, :bucket])
@ -296,11 +298,14 @@ def base_url do
!is_nil(truncated_namespace) -> !is_nil(truncated_namespace) ->
truncated_namespace truncated_namespace
!is_nil(namespace) -> !is_nil(namespace) and !is_nil(bucket) ->
namespace <> ":" <> bucket namespace <> ":" <> bucket
true -> !is_nil(bucket) ->
bucket bucket
true ->
""
end end
if public_endpoint do if public_endpoint do
@ -313,7 +318,7 @@ def base_url do
@config_impl.get([Pleroma.Uploaders.IPFS, :get_gateway_url]) @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 end
end end

View file

@ -9,8 +9,6 @@ defmodule Pleroma.Upload.Filter.Exiftool.StripLocation do
""" """
@behaviour Pleroma.Upload.Filter @behaviour Pleroma.Upload.Filter
@spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()}
# Formats not compatible with exiftool at this time # 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/heic"}), do: {:ok, :noop}
def filter(%Pleroma.Upload{content_type: "image/webp"}), do: {:ok, :noop} def filter(%Pleroma.Upload{content_type: "image/webp"}), do: {:ok, :noop}

View file

@ -38,7 +38,6 @@ defmodule Pleroma.Upload.Filter.Mogrifun do
[{"fill", "yellow"}, {"tint", "40"}] [{"fill", "yellow"}, {"tint", "40"}]
] ]
@spec filter(Pleroma.Upload.t()) :: {:ok, atom()} | {:error, String.t()}
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
try do try do
Filter.Mogrify.do_filter(file, [Enum.random(@filters)]) Filter.Mogrify.do_filter(file, [Enum.random(@filters)])

View file

@ -8,7 +8,6 @@ defmodule Pleroma.Upload.Filter.Mogrify do
@type conversion :: action :: String.t() | {action :: String.t(), opts :: String.t()} @type conversion :: action :: String.t() | {action :: String.t(), opts :: String.t()}
@type conversions :: conversion() | [conversion()] @type conversions :: conversion() | [conversion()]
@spec filter(Pleroma.Upload.t()) :: {:ok, :atom} | {:error, String.t()}
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
try do try do
do_filter(file, Pleroma.Config.get!([__MODULE__, :args])) do_filter(file, Pleroma.Config.get!([__MODULE__, :args]))

View file

@ -8,23 +8,10 @@ defmodule Pleroma.Uploaders.IPFS do
alias Tesla.Multipart 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) @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}" @placeholder "{CID}"
def placeholder, do: @placeholder def placeholder, do: @placeholder
@ -40,26 +27,26 @@ def get_file(file) do
end end
@impl true @impl true
def put_file(%Pleroma.Upload{} = upload) do def put_file(%Pleroma.Upload{tempfile: tempfile}) do
mp = mp =
Multipart.new() Multipart.new()
|> Multipart.add_content_type_param("charset=utf-8") |> 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 endpoint = ipfs_endpoint(@api_add)
{: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
error -> with {:ok, %{body: body}} when is_binary(body) <-
Logger.error("#{__MODULE__}: #{inspect(error)}") Pleroma.HTTP.post(endpoint, mp, [], params: ["cid-version": "1"], pool: :upload),
{:error, "JSON decode failed"} {_, {:ok, decoded}} <- {:json, Jason.decode(body)},
end {_, 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 -> error ->
Logger.error("#{__MODULE__}: #{inspect(error)}") Logger.error("#{__MODULE__}: #{inspect(error)}")
@ -69,9 +56,17 @@ def put_file(%Pleroma.Upload{} = upload) do
@impl true @impl true
def delete_file(file) do 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 {:ok, %{status: 204}} -> :ok
error -> {:error, inspect(error)} error -> {:error, inspect(error)}
end end
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 end

View file

@ -40,6 +40,7 @@ defmodule Pleroma.User do
alias Pleroma.Web.RelMe alias Pleroma.Web.RelMe
alias Pleroma.Webhook.Notify alias Pleroma.Webhook.Notify
alias Pleroma.Workers.BackgroundWorker alias Pleroma.Workers.BackgroundWorker
alias Pleroma.Workers.UserRefreshWorker
require Logger require Logger
require Pleroma.Constants require Pleroma.Constants
@ -2108,7 +2109,8 @@ defp verify_field_link(field, profile_urls) do
%{scheme: scheme, userinfo: nil, host: host} %{scheme: scheme, userinfo: nil, host: host}
when not_empty_string(host) and scheme in ["http", "https"] <- when not_empty_string(host) and scheme in ["http", "https"] <-
URI.parse(value), 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 "me" <- Pleroma.Web.RelMe.maybe_put_rel_me(value, profile_urls) do
CommonUtils.to_masto_date(NaiveDateTime.utc_now()) CommonUtils.to_masto_date(NaiveDateTime.utc_now())
else 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) 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 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) defp maybe_refresh(user) do
if needs_update?(user) do
case {cached_user, maybe_fetched_user} do UserRefreshWorker.new(%{"ap_id" => user.ap_id})
{_, {:ok, %User{} = user}} -> |> Oban.insert()
{:ok, user}
{%User{} = user, _} ->
{:ok, user}
_ ->
{:error, :not_found}
end end
end end
@ -2782,7 +2784,7 @@ defp add_to_block(%User{} = user, %User{} = blocked) do
end end
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()} {:ok, UserRelationship.t()} | {:ok, nil} | {:error, Ecto.Changeset.t()}
defp remove_from_block(%User{} = user, %User{} = blocked) do defp remove_from_block(%User{} = user, %User{} = blocked) do
with {:ok, relationship} <- UserRelationship.delete_block(user, blocked) do with {:ok, relationship} <- UserRelationship.delete_block(user, blocked) do

View file

@ -198,14 +198,14 @@ defp wait_backup(backup, current_processed, task) do
end end
@files [ @files [
'actor.json', ~c"actor.json",
'outbox.json', ~c"outbox.json",
'likes.json', ~c"likes.json",
'bookmarks.json', ~c"bookmarks.json",
'followers.json', ~c"followers.json",
'following.json', ~c"following.json",
'chats.json', ~c"chats.json",
'chat_messages.json' ~c"chat_messages.json"
] ]
@spec export(Pleroma.User.Backup.t(), pid()) :: {:ok, String.t()} | :error @spec export(Pleroma.User.Backup.t(), pid()) :: {:ok, String.t()} | :error
def export(%__MODULE__{} = backup, caller_pid) do def export(%__MODULE__{} = backup, caller_pid) do

View file

@ -1937,24 +1937,25 @@ def fetch_and_prepare_featured_from_ap_id(ap_id) do
end end
end end
def pinned_fetch_task(nil), do: nil def enqueue_pin_fetches(%{pinned_objects: pins}) do
# enqueue a task to fetch all pinned objects
def pinned_fetch_task(%{pinned_objects: pins}) do Enum.each(pins, fn {ap_id, _} ->
if Enum.all?(pins, fn {ap_id, _} -> if is_nil(Object.get_cached_by_ap_id(ap_id)) do
Object.get_cached_by_ap_id(ap_id) || Pleroma.Workers.RemoteFetcherWorker.enqueue("fetch_remote", %{
match?({:ok, _object}, Fetcher.fetch_object_from_id(ap_id)) "id" => ap_id,
end) do "depth" => 1
:ok })
else end
:error end)
end
end end
def enqueue_pin_fetches(_), do: nil
def make_user_from_ap_id(ap_id, additional \\ []) do def make_user_from_ap_id(ap_id, additional \\ []) do
user = User.get_cached_by_ap_id(ap_id) user = User.get_cached_by_ap_id(ap_id)
with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id, additional) do 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 if user do
user user

View file

@ -103,7 +103,11 @@ defp check_rbl(%{host: actor_host}, object) do
{:ok, object} {:ok, object}
else else
Task.start(fn -> Task.start(fn ->
reason = rblquery(query, :txt) || "undefined" reason =
case rblquery(query, :txt) do
[[result]] -> result
_ -> "undefined"
end
Logger.warning( Logger.warning(
"DNSRBL Rejected activity from #{actor_host} for reason: #{inspect(reason)}" "DNSRBL Rejected activity from #{actor_host} for reason: #{inspect(reason)}"

View file

@ -694,9 +694,9 @@ defp delete_object(object) do
with {:ok, _} <- Repo.delete(object), do: :ok with {:ok, _} <- Repo.delete(object), do: :ok
end end
defp send_notifications(meta) do defp stream_notifications(meta) do
Keyword.get(meta, :notifications, []) Keyword.get(meta, :notifications, [])
|> Notification.send() |> Notification.stream()
meta meta
end end
@ -727,7 +727,7 @@ defp add_notifications(meta, notifications) do
@impl true @impl true
def handle_after_transaction(meta) do def handle_after_transaction(meta) do
meta meta
|> send_notifications() |> stream_notifications()
|> send_streamables() |> send_streamables()
end end
end end

View file

@ -928,9 +928,11 @@ def add_emoji_tags(%{"emoji" => emoji} = object) do
def add_emoji_tags(object), do: object 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 <> ":", "name" => ":" <> name <> ":",
"type" => "Emoji", "type" => "Emoji",
"updated" => "1970-01-01T00:00:00Z", "updated" => "1970-01-01T00:00:00Z",

View file

@ -18,6 +18,8 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
alias OpenApiSpex.Plug.PutApiSpec alias OpenApiSpex.Plug.PutApiSpec
alias Plug.Conn alias Plug.Conn
require Logger
@impl Plug @impl Plug
def init(opts) do def init(opts) do
opts opts
@ -51,6 +53,10 @@ def call(conn, %{operation_id: operation_id, render_error: render_error} = opts)
conn conn
{:error, reason} -> {:error, reason} ->
Logger.error(
"Strict ApiSpec: request denied to #{conn.request_path} with params #{inspect(conn.params)}"
)
opts = render_error.init(reason) opts = render_error.init(reason)
conn conn

View file

@ -212,7 +212,9 @@ defp notification_type do
"pleroma:participation_accepted", "pleroma:participation_accepted",
"pleroma:participation_request", "pleroma:participation_request",
"pleroma:event_reminder", "pleroma:event_reminder",
"pleroma:event_update" "pleroma:event_update",
"admin.sign_up",
"admin.report"
], ],
description: """ description: """
The type of event that resulted in the notification. 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:chat_mention` - Someone mentioned you in a chat message
- `pleroma:report` - Someone was reported - `pleroma:report` - Someone was reported
- `status` - Someone you are subscribed to created a status - `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_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:event_update` An event you are participating in was edited
- `pleroma:participation_request - Someone wants to participate in your event - `pleroma:participation_request - Someone wants to participate in your event
- `pleroma:participation_accepted - Your event participation request was accepted - `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 end

View file

@ -79,7 +79,9 @@ def search_operation do
%Schema{type: :string, enum: ["accounts", "hashtags", "statuses"]}, %Schema{type: :string, enum: ["accounts", "hashtags", "statuses"]},
"Search type" "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( Operation.parameter(
:resolve, :resolve,
:query, :query,

View file

@ -110,7 +110,7 @@ defp register_user(connection, base, uid, name) do
} }
params = 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)) {_, [mail]} -> Map.put_new(params, :email, :erlang.list_to_binary(mail))
_ -> params _ -> params
end end

View file

@ -31,7 +31,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
# pagination is restricted to 40 activities at a time # pagination is restricted to 40 activities at a time
defp fetch_rich_media_for_activities(activities) do defp fetch_rich_media_for_activities(activities) do
Enum.each(activities, fn activity -> Enum.each(activities, fn activity ->
spawn(fn -> Card.get_by_activity(activity) end) Card.get_by_activity(activity)
end) end)
end end

View file

@ -104,7 +104,7 @@ def handle_info(:ping, state) do
end end
def handle_info(:close, state) do def handle_info(:close, state) do
{:stop, {:closed, 'connection closed by server'}, state} {:stop, {:closed, ~c"connection closed by server"}, state}
end end
def handle_info(msg, state) do def handle_info(msg, state) do

View file

@ -75,8 +75,7 @@ def whitelisted?(url) do
%{host: domain} = URI.parse(url) %{host: domain} = URI.parse(url)
mediaproxy_whitelist_domains = mediaproxy_whitelist_domains =
[:media_proxy, :whitelist] Config.get([:media_proxy, :whitelist], [])
|> Config.get()
|> Kernel.++(["#{Upload.base_url()}"]) |> Kernel.++(["#{Upload.base_url()}"])
|> Enum.map(&maybe_get_domain_from_url/1) |> Enum.map(&maybe_get_domain_from_url/1)

View file

@ -96,7 +96,7 @@ defp put_valid_until(changeset, attrs) do
|> validate_required([:valid_until]) |> validate_required([:valid_until])
end 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 def create(%App{} = app, %User{} = user, attrs \\ %{}) do
with {:ok, token} <- do_create(app, user, attrs) do with {:ok, token} <- do_create(app, user, attrs) do
if Pleroma.Config.get([:oauth2, :clean_expired_tokens]) do if Pleroma.Config.get([:oauth2, :clean_expired_tokens]) do

View file

@ -34,7 +34,9 @@ def perform(%Plug.Conn{assigns: assigns} = conn, %{scopes: scopes} = options) do
permissions = Enum.join(missing_scopes, " #{op} ") permissions = Enum.join(missing_scopes, " #{op} ")
error_message = error_message =
dgettext("errors", "Insufficient permissions: %{permissions}.", permissions: permissions) dgettext("errors", "Insufficient permissions: %{permissions}.",
permissions: permissions
)
conn conn
|> put_resp_content_type("application/json") |> put_resp_content_type("application/json")

View file

@ -20,17 +20,13 @@ def init do
end end
def vapid_config do def vapid_config do
Application.get_env(:web_push_encryption, :vapid_details, []) Application.get_env(:web_push_encryption, :vapid_details, nil)
end end
def enabled do def enabled, do: match?([subject: _, public_key: _, private_key: _], vapid_config())
case vapid_config() do
[] -> false
list when is_list(list) -> true
_ -> false
end
end
@spec send(Pleroma.Notification.t()) ::
{:ok, Oban.Job.t()} | {:error, Oban.Job.changeset() | term()}
def send(notification) do def send(notification) do
WebPusherWorker.enqueue("web_push", %{"notification_id" => notification.id}) WebPusherWorker.enqueue("web_push", %{"notification_id" => notification.id})
end end

View file

@ -16,62 +16,70 @@ defmodule Pleroma.Web.Push.Impl do
require Logger require Logger
import Ecto.Query import Ecto.Query
@body_chars 140
@types ["Create", "Follow", "Announce", "Like", "Move", "EmojiReact", "Update"] @types ["Create", "Follow", "Announce", "Like", "Move", "EmojiReact", "Update"]
@doc "Performs sending notifications for user subscriptions" @doc "Builds webpush notification payloads for the subscriptions enabled by the receiving user"
@spec perform(Notification.t()) :: list(any) | :error | {:error, :unknown_type} @spec build(Notification.t()) ::
def perform( list(%{content: map(), subscription: Subscription.t()}) | []
def build(
%{ %{
activity: %{data: %{"type" => activity_type}} = activity, activity: %{data: %{"type" => activity_type}} = activity,
user: %User{id: user_id} user_id: user_id
} = notification } = notification
) )
when activity_type in @types do 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) object = Object.normalize(activity, fetch: false)
user = User.get_cached_by_id(user_id) user = User.get_cached_by_id(user_id)
direct_conversation_id = Activity.direct_conversation_id(activity, user) direct_conversation_id = Activity.direct_conversation_id(activity, user)
for subscription <- fetch_subscriptions(user_id), subscriptions = fetch_subscriptions(user_id)
Subscription.enabled?(subscription, mastodon_type) do
%{ subscriptions
access_token: subscription.token.token, |> Enum.filter(&Subscription.enabled?(&1, notification.type))
notification_id: notification.id, |> Enum.map(fn subscription ->
notification_type: mastodon_type, payload =
icon: avatar_url, %{
preferred_locale: "en", access_token: subscription.token.token,
pleroma: %{ notification_id: notification.id,
activity_id: notification.activity.id, notification_type: notification.type,
direct_conversation_id: direct_conversation_id icon: avatar_url,
preferred_locale: "en",
pleroma: %{
activity_id: notification.activity.id,
direct_conversation_id: direct_conversation_id
}
} }
} |> Map.merge(build_content(notification, notification_actor, object))
|> Map.merge(build_content(notification, actor, object, mastodon_type)) |> Jason.encode!()
|> Jason.encode!()
|> push_message(build_sub(subscription), gcm_api_key, subscription) %{payload: payload, subscription: subscription}
end end)
|> (&{:ok, &1}).()
end end
def perform(_) do def build(notif) do
Logger.warning("Unknown notification type") Logger.warning("WebPush: unknown activity type: #{inspect(notif)}")
{:error, :unknown_type} []
end end
@doc "Push message to web" @doc "Deliver push notification to the provided webpush subscription"
def push_message(body, sub, api_key, subscription) do @spec deliver(%{payload: String.t(), subscription: Subscription.t()}) :: :ok | :error
case WebPushEncryption.send_web_push(body, sub, api_key) do 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 -> {:ok, %{status: code}} when code in 400..499 ->
Logger.debug("Removing subscription record") Logger.debug("Removing subscription record")
Repo.delete!(subscription) Repo.delete!(subscription)
:ok :ok
{:ok, %{status: code}} when code in 200..299 ->
:ok
{:ok, %{status: code}} -> {:ok, %{status: code}} ->
Logger.error("Web Push Notification failed with code: #{code}") Logger.error("Web Push Notification failed with code: #{code}")
:error :error
@ -100,107 +108,106 @@ def build_sub(subscription) do
} }
end end
def build_content(notification, actor, object, mastodon_type \\ nil)
def build_content( def build_content(
%{ %{
user: %{notification_settings: %{hide_notification_contents: true}} user: %{notification_settings: %{hide_notification_contents: true}}
} = notification, } = notification,
_actor, _user,
_object, _object
mastodon_type
) do ) do
%{body: format_title(notification, mastodon_type)} %{body: format_title(notification)}
end end
def build_content(notification, actor, object, mastodon_type) do def build_content(notification, user, object) do
mastodon_type = mastodon_type || notification.type
%{ %{
title: format_title(notification, mastodon_type), title: format_title(notification),
body: format_body(notification, actor, object, mastodon_type) body: format_body(notification, user, object)
} }
end end
def format_body(activity, actor, object, mastodon_type \\ nil) @spec format_body(Notification.t(), User.t(), Object.t()) :: String.t()
def format_body(_notification, user, %{data: %{"type" => "ChatMessage"} = object}) do
def format_body(_activity, actor, %{data: %{"type" => "ChatMessage"} = data}, _) do case object["content"] do
case data["content"] do nil -> "@#{user.nickname}: (Attachment)"
nil -> "@#{actor.nickname}: (Attachment)" content -> "@#{user.nickname}: #{Utils.scrub_html_and_truncate(content, @body_chars)}"
content -> "@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
end end
end end
def format_body( def format_body(
%{activity: %{data: %{"type" => "Create"}}}, %{type: "poll"} = _notification,
actor, _user,
%{data: %{"content" => content}}, %{data: %{"content" => content} = data} = _object
_mastodon_type
) do ) 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 end
def format_body( def format_body(
%{activity: %{data: %{"type" => "Announce"}}}, %{activity: %{data: %{"type" => "Announce"}}},
actor, user,
%{data: %{"content" => content}}, %{data: %{"content" => content}}
_mastodon_type
) do ) do
"@#{actor.nickname} repeated: #{Utils.scrub_html_and_truncate(content, 80)}" "@#{user.nickname} repeated: #{Utils.scrub_html_and_truncate(content, @body_chars)}"
end end
def format_body( def format_body(
%{activity: %{data: %{"type" => "EmojiReact", "content" => content}}}, %{activity: %{data: %{"type" => "EmojiReact", "content" => content}}},
actor, user,
_object, _object
_mastodon_type
) do ) do
"@#{actor.nickname} reacted with #{content}" "@#{user.nickname} reacted with #{content}"
end end
def format_body( def format_body(
%{activity: %{data: %{"type" => type}}} = notification, %{activity: %{data: %{"type" => type}}} = notification,
actor, user,
_object, _object
mastodon_type
) )
when type in ["Follow", "Like"] do when type in ["Follow", "Like"] do
mastodon_type = mastodon_type || notification.type case notification.type do
"follow" -> "@#{user.nickname} has followed you"
case mastodon_type do "follow_request" -> "@#{user.nickname} has requested to follow you"
"follow" -> "@#{actor.nickname} has followed you" "favourite" -> "@#{user.nickname} has favorited your post"
"follow_request" -> "@#{actor.nickname} has requested to follow you"
"favourite" -> "@#{actor.nickname} has favorited your post"
end end
end end
def format_body( def format_body(
%{activity: %{data: %{"type" => "Update"}}}, %{activity: %{data: %{"type" => "Update"}}},
actor, user,
_object, _object
_mastodon_type
) do ) do
"@#{actor.nickname} edited a status" "@#{user.nickname} edited a status"
end end
def format_title(activity, mastodon_type \\ nil) @spec format_title(Notification.t()) :: String.t()
def format_title(%{activity: %{data: %{"directMessage" => true}}}) do
def format_title(%{activity: %{data: %{"directMessage" => true}}}, _mastodon_type) do
"New Direct Message" "New Direct Message"
end end
def format_title(%{type: type}, mastodon_type) do def format_title(%{type: "mention"}), do: "New Mention"
case mastodon_type || type do def format_title(%{type: "status"}), do: "New Status"
"mention" -> "New Mention" def format_title(%{type: "follow"}), do: "New Follower"
"status" -> "New Status" def format_title(%{type: "follow_request"}), do: "New Follow Request"
"follow" -> "New Follower" def format_title(%{type: "reblog"}), do: "New Repeat"
"follow_request" -> "New Follow Request" def format_title(%{type: "favourite"}), do: "New Favorite"
"reblog" -> "New Repeat" def format_title(%{type: "update"}), do: "New Update"
"favourite" -> "New Favorite" def format_title(%{type: "pleroma:chat_mention"}), do: "New Chat Message"
"update" -> "New Update" def format_title(%{type: "pleroma:emoji_reaction"}), do: "New Reaction"
"pleroma:chat_mention" -> "New Chat Message" def format_title(%{type: "poll"}), do: "Poll Results"
"pleroma:emoji_reaction" -> "New Reaction" def format_title(%{type: type}), do: "New #{String.capitalize(type || "event")}"
type -> "New #{String.capitalize(type || "event")}"
end
end
end end

View file

@ -6,35 +6,25 @@ defmodule Pleroma.Web.RichMedia.Backfill do
alias Pleroma.Web.RichMedia.Card alias Pleroma.Web.RichMedia.Card
alias Pleroma.Web.RichMedia.Parser alias Pleroma.Web.RichMedia.Parser
alias Pleroma.Web.RichMedia.Parser.TTL alias Pleroma.Web.RichMedia.Parser.TTL
alias Pleroma.Workers.RichMediaExpirationWorker alias Pleroma.Workers.RichMediaWorker
require Logger require Logger
@backfiller Pleroma.Config.get([__MODULE__, :provider], Pleroma.Web.RichMedia.Backfill.Task)
@cachex Pleroma.Config.get([:cachex, :provider], Cachex) @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) 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 case Parser.parse(url) do
{:ok, fields} -> {:ok, fields} ->
{:ok, card} = Card.create(url, fields) {:ok, card} = Card.create(url, fields)
maybe_schedule_expiration(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) stream_update(args)
end end
@ -54,25 +44,16 @@ def run(%{url: url, url_hash: url_hash, attempt: attempt} = args)
e -> e ->
Logger.debug("Rich media error for #{url}: #{inspect(e)}") Logger.debug("Rich media error for #{url}: #{inspect(e)}")
{:error, e}
:timer.sleep(@retry * attempt)
run(%{args | attempt: attempt + 1})
end end
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 defp maybe_schedule_expiration(url, fields) do
case TTL.process(fields, url) do case TTL.process(fields, url) do
{:ok, ttl} when is_number(ttl) -> {:ok, ttl} when is_number(ttl) ->
timestamp = DateTime.from_unix!(ttl) timestamp = DateTime.from_unix!(ttl)
RichMediaExpirationWorker.new(%{"url" => url}, scheduled_at: timestamp) RichMediaWorker.new(%{"op" => "expire", "url" => url}, scheduled_at: timestamp)
|> Oban.insert() |> Oban.insert()
_ -> _ ->
@ -80,22 +61,14 @@ defp maybe_schedule_expiration(url, fields) do
end end
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.get_by_id(activity_id)
|> Pleroma.Activity.normalize() |> Pleroma.Activity.normalize()
|> Pleroma.Web.ActivityPub.ActivityPub.stream_out() |> Pleroma.Web.ActivityPub.ActivityPub.stream_out()
end end
defp warm_cache(key, val), do: @cachex.put(:rich_media_cache, key, val) 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 defp negative_cache(key, ttl \\ :timer.minutes(15)),
alias Pleroma.Web.RichMedia.Backfill do: @cachex.put(:rich_media_cache, key, nil, ttl: ttl)
def run(args) do
Task.Supervisor.start_child(Pleroma.TaskSupervisor, Backfill, :run, [args],
name: {:global, {:rich_media, args.url_hash}}
)
end
end end

View file

@ -7,8 +7,8 @@ defmodule Pleroma.Web.RichMedia.Card do
alias Pleroma.HTML alias Pleroma.HTML
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.Web.RichMedia.Backfill
alias Pleroma.Web.RichMedia.Parser alias Pleroma.Web.RichMedia.Parser
alias Pleroma.Workers.RichMediaWorker
@cachex Pleroma.Config.get([:cachex, :provider], Cachex) @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
@config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config) @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 def get_by_url(nil), do: nil
@spec get_or_backfill_by_url(String.t(), map()) :: t() | nil @spec get_or_backfill_by_url(String.t(), keyword()) :: t() | nil
def get_or_backfill_by_url(url, backfill_opts \\ %{}) do def get_or_backfill_by_url(url, opts \\ []) do
case get_by_url(url) do if @config_impl.get([:rich_media, :enabled]) do
%__MODULE__{} = card -> case get_by_url(url) do
card %__MODULE__{} = card ->
card
nil -> nil ->
backfill_opts = Map.put(backfill_opts, :url, url) 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 -> :error ->
nil nil
end
else
nil
end end
end end
@ -104,7 +109,8 @@ def get_by_object(object) do
@spec get_by_activity(Activity.t()) :: t() | nil | :error @spec get_by_activity(Activity.t()) :: t() | nil | :error
# Fake/Draft activity # Fake/Draft activity
def get_by_activity(%Activity{id: "pleroma:fakeid"} = activity) do 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 url when not is_nil(url) <- HTML.extract_first_external_url_from_object(object) do
case get_by_url(url) do case get_by_url(url) do
# Cache hit # Cache hit
@ -132,7 +138,7 @@ def get_by_activity(activity) do
nil nil
else else
{:cached, url} -> {:cached, url} ->
get_or_backfill_by_url(url, %{activity_id: activity.id}) get_or_backfill_by_url(url, activity_id: activity.id)
_ -> _ ->
:error :error

View file

@ -15,10 +15,14 @@ def parse(nil), do: nil
@spec parse(String.t()) :: {:ok, map()} | {:error, any()} @spec parse(String.t()) :: {:ok, map()} | {:error, any()}
def parse(url) do 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 {:ok, data} <- parse_url(url) do
data = Map.put(data, "url", url) data = Map.put(data, "url", url)
{:ok, data} {:ok, data}
else
{:config, _} -> {:error, :rich_media_disabled}
e -> e
end end
end end

View file

@ -173,7 +173,13 @@ def remove_socket(topic) do
def stream(topics, items) do def stream(topics, items) do
if should_env_send?() do if should_env_send?() do
for topic <- List.wrap(topics), item <- List.wrap(items) 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 end
end end

View file

@ -9,7 +9,7 @@ def string_from_xpath(_, :error), do: nil
def string_from_xpath(xpath, doc) do def string_from_xpath(xpath, doc) do
try do try do
{:xmlObj, :string, res} = :xmerl_xpath.string('string(#{xpath})', doc) {:xmlObj, :string, res} = :xmerl_xpath.string(~c"string(#{xpath})", doc)
res = res =
res res

View file

@ -16,7 +16,7 @@ defmodule Pleroma.Workers.NotificationWorker do
def perform(%Job{args: %{"op" => "create", "activity_id" => activity_id}}) do def perform(%Job{args: %{"op" => "create", "activity_id" => activity_id}}) do
with %Activity{} = activity <- find_activity(activity_id), with %Activity{} = activity <- find_activity(activity_id),
{:ok, notifications} <- Notification.create_notifications(activity) do {:ok, notifications} <- Notification.create_notifications(activity) do
Notification.send(notifications) Notification.stream(notifications)
end end
end end

View file

@ -14,8 +14,9 @@ defmodule Pleroma.Workers.PollWorker do
@impl Oban.Worker @impl Oban.Worker
def perform(%Job{args: %{"op" => "poll_end", "activity_id" => activity_id}}) do def perform(%Job{args: %{"op" => "poll_end", "activity_id" => activity_id}}) do
with %Activity{} = activity <- find_poll_activity(activity_id) do with %Activity{} = activity <- find_poll_activity(activity_id),
Notification.create_poll_notifications(activity) {:ok, notifications} <- Notification.create_poll_notifications(activity) do
Notification.stream(notifications)
end end
end end

View file

@ -1,15 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# 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

View file

@ -0,0 +1,19 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# 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

View file

@ -0,0 +1,14 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# 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

View file

@ -5,6 +5,7 @@
defmodule Pleroma.Workers.WebPusherWorker do defmodule Pleroma.Workers.WebPusherWorker do
alias Pleroma.Notification alias Pleroma.Notification
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.Web.Push.Impl
use Pleroma.Workers.WorkerHelper, queue: "web_push" 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.get(notification_id)
|> Repo.preload([:activity, :user]) |> Repo.preload([:activity, :user])
Pleroma.Web.Push.Impl.perform(notification) Impl.build(notification)
|> Enum.each(&Impl.deliver(&1))
end end
@impl Oban.Worker @impl Oban.Worker

57
mix.exs
View file

@ -12,7 +12,7 @@ def project do
elixir: "~> 1.13", elixir: "~> 1.13",
elixirc_paths: elixirc_paths(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()),
compilers: Mix.compilers(), 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]], xref: [exclude: [:eldap]],
dialyzer: [plt_add_apps: [:mix, :eldap]], dialyzer: [plt_add_apps: [:mix, :eldap]],
start_permanent: Mix.env() == :prod, start_permanent: Mix.env() == :prod,
@ -75,14 +75,15 @@ def copy_nginx_config(%{path: target_path} = release) do
def application do def application do
[ [
mod: {Pleroma.Application, []}, mod: {Pleroma.Application, []},
extra_applications: [ extra_applications:
:logger, [
:runtime_tools, :logger,
:comeonin, :runtime_tools,
:fast_sanitize, :comeonin,
:os_mon, :fast_sanitize,
:ssl :os_mon,
], :ssl
] ++ logger_application(),
included_applications: [:ex_syslogger] included_applications: [:ex_syslogger]
] ]
end end
@ -111,6 +112,22 @@ defp oauth_deps do
for s <- oauth_strategy_packages, do: {String.to_atom(s), ">= 0.0.0"} for s <- oauth_strategy_packages, do: {String.to_atom(s), ">= 0.0.0"}
end 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. # Specifies your project dependencies.
# #
# Type `mix help deps` for examples and options. # Type `mix help deps` for examples and options.
@ -123,15 +140,13 @@ defp deps do
{:ecto_enum, "~> 1.4"}, {:ecto_enum, "~> 1.4"},
{:postgrex, ">= 0.15.5"}, {:postgrex, ">= 0.15.5"},
{:phoenix_html, "~> 3.3"}, {:phoenix_html, "~> 3.3"},
{:phoenix_live_reload, "~> 1.3.3", only: :dev},
{:phoenix_live_view, "~> 0.19.0"}, {:phoenix_live_view, "~> 0.19.0"},
{:phoenix_live_dashboard, "~> 0.8.0"}, {:phoenix_live_dashboard, "~> 0.8.0"},
{:telemetry_metrics, "~> 0.6"}, {:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"}, {:telemetry_poller, "~> 1.0"},
{:tzdata, "~> 1.0.3"}, {:tzdata, "~> 1.0.3"},
{:plug_cowboy, "~> 2.6.1"}, {:plug_cowboy, "~> 2.5"},
# oban 2.14 requires Elixir 1.12+ {:oban, "~> 2.17.9"},
{:oban, "~> 2.13.4"},
{:gettext, "~> 0.20"}, {:gettext, "~> 0.20"},
{:bcrypt_elixir, "~> 2.2"}, {:bcrypt_elixir, "~> 2.2"},
{:fast_sanitize, "~> 0.2.0"}, {:fast_sanitize, "~> 0.2.0"},
@ -150,13 +165,11 @@ defp deps do
{:ex_aws, "~> 2.1.6"}, {:ex_aws, "~> 2.1.6"},
{:ex_aws_s3, "~> 2.0"}, {:ex_aws_s3, "~> 2.0"},
{:sweet_xml, "~> 0.7.2"}, {:sweet_xml, "~> 0.7.2"},
# earmark 1.4.23 requires Elixir 1.12+ {:earmark, "1.4.46"},
{:earmark, "1.4.22"},
{:bbcode_pleroma, "~> 0.2.0"}, {:bbcode_pleroma, "~> 0.2.0"},
{:cors_plug, "~> 2.0"}, {:cors_plug, "~> 2.0"},
{:web_push_encryption, "~> 0.3.1"}, {:web_push_encryption, "~> 0.3.1"},
# swoosh 1.11.2+ requires Elixir 1.12+ {:swoosh, "~> 1.16.9"},
{:swoosh, "~> 1.10.0"},
{:phoenix_swoosh, "~> 1.1"}, {:phoenix_swoosh, "~> 1.1"},
{:gen_smtp, "~> 0.13"}, {:gen_smtp, "~> 0.13"},
{:ex_syslogger, "~> 1.4"}, {:ex_syslogger, "~> 1.4"},
@ -188,14 +201,14 @@ defp deps do
{:vix, "~> 0.26.0"}, {:vix, "~> 0.26.0"},
{:elixir_make, "~> 0.7.7", override: true}, {:elixir_make, "~> 0.7.7", override: true},
{:blurhash, "~> 0.1.0", hex: :rinpatch_blurhash}, {:blurhash, "~> 0.1.0", hex: :rinpatch_blurhash},
{:exile, {:exile, "~> 0.10.0"},
git: "https://github.com/akash-akya/exile.git", {:bandit, "~> 1.5.2"},
ref: "be87c33b02a7c3c5d22d2ece01fbd462355b28ef"}, {:websock_adapter, "~> 0.5.6"},
{:bandit, "~> 1.2"},
{:icalendar, "~> 1.1"}, {:icalendar, "~> 1.1"},
{:geospatial, "~> 0.3.0"}, {:geospatial, "~> 0.3.0"},
## dev & test ## dev & test
{:phoenix_live_reload, "~> 1.3.3", only: :dev},
{:ex_doc, "~> 0.22", only: :dev, runtime: false}, {:ex_doc, "~> 0.22", only: :dev, runtime: false},
{:ex_machina, "~> 2.4", only: :test}, {:ex_machina, "~> 2.4", only: :test},
{:credo, "~> 1.6", only: [:dev, :test], runtime: false}, {:credo, "~> 1.6", only: [:dev, :test], runtime: false},
@ -206,7 +219,7 @@ defp deps do
{:websockex, "~> 0.4.3", only: :test}, {:websockex, "~> 0.4.3", only: :test},
{:benchee, "~> 1.0", only: :benchmark}, {:benchee, "~> 1.0", only: :benchmark},
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false} {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}
] ++ oauth_deps() ] ++ oauth_deps() ++ logger_deps()
end end
# Aliases are shortcuts or tasks specific to the current project. # Aliases are shortcuts or tasks specific to the current project.

View file

@ -1,6 +1,6 @@
%{ %{
"accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm", "11b18c220bcc2eab63b5470c038ef10eb6783bcb1fcdb11aa4137defa5ac1bb8"}, "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"}, "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"}, "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"}, "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"}, "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"}, "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"}, "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"}, "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"}, "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"}, "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"]}, "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"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "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"}, "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"}, "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
"eblurhash": {:git, "https://github.com/zotonic/eblurhash.git", "bc37ceb426ef021ee9927fb249bb93f7059194ab", [ref: "bc37ceb426ef021ee9927fb249bb93f7059194ab"]}, "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_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_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"}, "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"}, "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"}, "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_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_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"}, "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"}, "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_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"}, "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"}, "jose": {:hex, :jose, "1.11.6", "613fda82552128aa6fb804682e3a616f4bc15565a048dabd05b1ebd5827ed965", [:mix, :rebar3], [], "hexpm", "6275cb75504f9c1e60eeacb771adfeee4905a9e182103aa59b53fed651ff9738"},
"jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"}, "jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"},
"linkify": {:git, "https://gitlab.com/mkljczk/linkify", "b854b2f1701a5e13dfea50add729a8525a549f64", [branch: "master"]}, "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"}, "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": {: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"}, "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"}, "meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
"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"}, "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"}, "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"}, "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"}, "mogrify": {:hex, :mogrify, "0.8.0", "3506f3ca3f7b95a155f3b4ef803b5db176f5a0633723e3fe85e0d6399e3b11c8", [:mix], [], "hexpm", "2278d245f07056ea3b586e98801e933695147066fa4cf563f552c1b4f0ff8ad9"},
"mox": {:hex, :mox, "1.1.0", "0f5e399649ce9ab7602f72e718305c0f9cdc351190f72844599545e4996af73c", [:mix], [], "hexpm", "d44474c50be02d5b72131070281a5d3895c0e7a95c780e90bc0cfe712f633a13"}, "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_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"},
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"}, "nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]}, "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"}, "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"}, "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"}, "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"}, "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"}, "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_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_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"}, "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_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"}, "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"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"},
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"}, "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"}, "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"}, "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"}, "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"}, "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"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
"sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"}, "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"}, "syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
"table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"}, "table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"},
"telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"}, "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_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"}, "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"}, "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"}, "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"}, "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"}, "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"}, "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"}, "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": {: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"}, "websockex": {:hex, :websockex, "0.4.3", "92b7905769c79c6480c02daacaca2ddd49de936d912976a4d3c923723b647bf0", [:mix], [], "hexpm", "95f2e7072b85a3a4cc385602d42115b73ce0b74a9121d0d6dbbf557645ac53e4"},
} }

View file

@ -7,7 +7,10 @@ defmodule Pleroma.Repo.Migrations.CreateUserTrigramIndex do
def change do def change do
create_if_not_exists( 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
end end

View file

@ -20,7 +20,10 @@ def down do
drop_if_exists(index(:users, [], name: :users_trigram_index)) drop_if_exists(index(:users, [], name: :users_trigram_index))
create_if_not_exists( 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
end end

View file

@ -7,7 +7,10 @@ defmodule Pleroma.Repo.Migrations.AddTagIndexToObjects do
def change do def change do
drop_if_exists( 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)) create_if_not_exists(index(:objects, ["(data->'tag')"], using: :gin, name: :objects_tags))

Some files were not shown because too many files have changed in this diff Show more