Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into alexgleason/pleroma-block-behavior

This commit is contained in:
lain 2020-10-26 17:50:34 +01:00
commit 04b7505c75
109 changed files with 695 additions and 474 deletions

2
.gitignore vendored
View File

@ -27,6 +27,8 @@ erl_crash.dump
# variables. # variables.
/config/*.secret.exs /config/*.secret.exs
/config/generated_config.exs /config/generated_config.exs
/config/*.env
# Database setup file, some may forget to delete it # Database setup file, some may forget to delete it
/config/setup_db.psql /config/setup_db.psql

View File

@ -25,6 +25,8 @@ before_script:
- apt-get update && apt-get install -y cmake - apt-get update && apt-get install -y cmake
- mix local.hex --force - mix local.hex --force
- mix local.rebar --force - mix local.rebar --force
- apt-get -qq update
- apt-get install -y libmagic-dev
build: build:
stage: build stage: build
@ -196,7 +198,7 @@ amd64:
variables: &release-variables variables: &release-variables
MIX_ENV: prod MIX_ENV: prod
before_script: &before-release before_script: &before-release
- apt-get update && apt-get install -y cmake - apt-get update && apt-get install -y cmake libmagic-dev
- echo "import Mix.Config" > config/prod.secret.exs - echo "import Mix.Config" > config/prod.secret.exs
- mix local.hex --force - mix local.hex --force
- mix local.rebar --force - mix local.rebar --force
@ -215,7 +217,7 @@ amd64-musl:
cache: *release-cache cache: *release-cache
variables: *release-variables variables: *release-variables
before_script: &before-release-musl before_script: &before-release-musl
- apk add git gcc g++ musl-dev make cmake - apk add git gcc g++ musl-dev make cmake file-dev
- echo "import Mix.Config" > config/prod.secret.exs - echo "import Mix.Config" > config/prod.secret.exs
- mix local.hex --force - mix local.hex --force
- mix local.rebar --force - mix local.rebar --force

View File

@ -9,10 +9,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Mix tasks for controlling user account confirmation status in bulk (`mix pleroma.user confirm_all` and `mix pleroma.user unconfirm_all`) - Mix tasks for controlling user account confirmation status in bulk (`mix pleroma.user confirm_all` and `mix pleroma.user unconfirm_all`)
- Mix task for sending confirmation emails to all unconfirmed users (`mix pleroma.email send_confirmation_mails`) - Mix task for sending confirmation emails to all unconfirmed users (`mix pleroma.email send_confirmation_mails`)
- Mix task option for force-unfollowing relays - Mix task option for force-unfollowing relays
- Media preview proxy (requires `ffmpeg` and `ImageMagick` to be installed and media proxy to be enabled; see `:media_preview_proxy` config for more details).
- Pleroma API: Importing the mutes users from CSV files.
- Experimental websocket-based federation between Pleroma instances.
- `[:activitypub, :blockers_visible]` config to control visibility of blockers. - `[:activitypub, :blockers_visible]` config to control visibility of blockers.
### Changed ### Changed
- **Breaking** Requires `libmagic` (or `file`) to guess file types.
- **Breaking:** Pleroma Admin API: emoji packs and files routes changed. - **Breaking:** Pleroma Admin API: emoji packs and files routes changed.
- **Breaking:** Sensitive/NSFW statuses no longer disable link previews. - **Breaking:** Sensitive/NSFW statuses no longer disable link previews.
- Search: Users are now findable by their urls. - Search: Users are now findable by their urls.
@ -23,11 +27,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Minimum lifetime for ephmeral activities changed to 10 minutes and made configurable (`:min_lifetime` option). - Minimum lifetime for ephmeral activities changed to 10 minutes and made configurable (`:min_lifetime` option).
- Introduced optional dependencies on `ffmpeg`, `ImageMagick`, `exiftool` software packages. Please refer to `docs/installation/optional/media_graphics_packages.md`. - Introduced optional dependencies on `ffmpeg`, `ImageMagick`, `exiftool` software packages. Please refer to `docs/installation/optional/media_graphics_packages.md`.
### Added
- Media preview proxy (requires `ffmpeg` and `ImageMagick` to be installed and media proxy to be enabled; see `:media_preview_proxy` config for more details).
- Pleroma API: Importing the mutes users from CSV files.
- Experimental websocket-based federation between Pleroma instances.
<details> <details>
<summary>API Changes</summary> <summary>API Changes</summary>
@ -50,6 +49,7 @@ switched to a new configuration mechanism, however it was not officially removed
- Add documented-but-missing chat pagination. - Add documented-but-missing chat pagination.
- Allow sending out emails again. - Allow sending out emails again.
- See your own post when addressing a user from a blocked domain. - See your own post when addressing a user from a blocked domain.
- Allow sending chat messages to yourself
## Unreleased (Patch) ## Unreleased (Patch)

View File

@ -123,7 +123,6 @@
# Configures the endpoint # Configures the endpoint
config :pleroma, Pleroma.Web.Endpoint, config :pleroma, Pleroma.Web.Endpoint,
instrumenters: [Pleroma.Web.Endpoint.Instrumenter],
url: [host: "localhost"], url: [host: "localhost"],
http: [ http: [
ip: {127, 0, 0, 1}, ip: {127, 0, 0, 1},
@ -143,7 +142,7 @@
secret_key_base: "aK4Abxf29xU9TTDKre9coZPUgevcVCFQJe/5xP/7Lt4BEif6idBIbjupVbOrbKxl", secret_key_base: "aK4Abxf29xU9TTDKre9coZPUgevcVCFQJe/5xP/7Lt4BEif6idBIbjupVbOrbKxl",
signing_salt: "CqaoopA2", signing_salt: "CqaoopA2",
render_errors: [view: Pleroma.Web.ErrorView, accepts: ~w(json)], render_errors: [view: Pleroma.Web.ErrorView, accepts: ~w(json)],
pubsub: [name: Pleroma.PubSub, adapter: Phoenix.PubSub.PG2], pubsub_server: Pleroma.PubSub,
secure_cookie_flag: true, secure_cookie_flag: true,
extra_cookie_attrs: [ extra_cookie_attrs: [
"SameSite=Lax" "SameSite=Lax"
@ -803,6 +802,8 @@
timeout: 300_000 timeout: 300_000
] ]
config :pleroma, :majic_pool, size: 2
private_instance? = :if_instance_is_private private_instance? = :if_instance_is_private
config :pleroma, :restrict_unauthenticated, config :pleroma, :restrict_unauthenticated,

View File

@ -829,13 +829,7 @@
key: :autofollowed_nicknames, key: :autofollowed_nicknames,
type: {:list, :string}, type: {:list, :string},
description: description:
"Set to nicknames of (local) users that every new user should automatically follow", "Set to nicknames of (local) users that every new user should automatically follow"
suggestions: [
"lain",
"kaniini",
"lanodan",
"rinpatch"
]
}, },
%{ %{
key: :attachment_links, key: :attachment_links,
@ -3713,5 +3707,19 @@
] ]
} }
] ]
},
%{
group: :pleroma,
key: :majic_pool,
type: :group,
description: "Majic/libmagic configuration",
children: [
%{
key: :size,
type: :integer,
description: "Number of majic workers to start.",
suggestions: [2]
}
]
} }
] ]

View File

@ -40,3 +40,5 @@ If any of the options are left unspecified, you will be prompted interactively.
- `--strip-uploads <Y|N>` - use ExifTool to strip uploads of sensitive location data - `--strip-uploads <Y|N>` - use ExifTool to strip uploads of sensitive location data
- `--anonymize-uploads <Y|N>` - randomize uploaded filenames - `--anonymize-uploads <Y|N>` - randomize uploaded filenames
- `--dedupe-uploads <Y|N>` - store files based on their hash to reduce data storage requirements if duplicates are uploaded with different filenames - `--dedupe-uploads <Y|N>` - store files based on their hash to reduce data storage requirements if duplicates are uploaded with different filenames
- `--skip-release-env` - skip generation the release environment file
- `--release-env-file` - release environment file path

View File

@ -0,0 +1,9 @@
# Generate release environment file
```sh tab="OTP"
./bin/pleroma_ctl release_env gen
```
```sh tab="From Source"
mix pleroma.release_env gen
```

View File

@ -1,11 +1,41 @@
# ChatMessages # AP Extensions
## Actor endpoints
ChatMessages are the messages sent in 1-on-1 chats. They are similar to The following endpoints are additionally present into our actors.
- `oauthRegistrationEndpoint` (`http://litepub.social/ns#oauthRegistrationEndpoint`)
- `uploadMedia` (`https://www.w3.org/ns/activitystreams#uploadMedia`)
### oauthRegistrationEndpoint
Points to MastodonAPI `/api/v1/apps` for now.
See <https://docs.joinmastodon.org/methods/apps/>
### uploadMedia
Inspired by <https://www.w3.org/wiki/SocialCG/ActivityPub/MediaUpload>, it is part of the ActivityStreams namespace because it used to be part of the ActivityPub specification and got removed from it.
Content-Type: multipart/form-data
Parameters:
- (required) `file`: The file being uploaded
- (optionnal) `description`: A plain-text description of the media, for accessibility purposes.
Response: HTTP 201 Created with the object into the body, no `Location` header provided as it doesn't have an `id`
The object given in the reponse should then be inserted into an Object's `attachment` field.
## ChatMessages
`ChatMessage`s are the messages sent in 1-on-1 chats. They are similar to
`Note`s, but the addresing is done by having a single AP actor in the `to` `Note`s, but the addresing is done by having a single AP actor in the `to`
field. Addressing multiple actors is not allowed. These messages are always field. Addressing multiple actors is not allowed. These messages are always
private, there is no public version of them. They are created with a `Create` private, there is no public version of them. They are created with a `Create`
activity. activity.
They are part of the `litepub` namespace as `http://litepub.social/ns#ChatMessage`.
Example: Example:
```json ```json

View File

@ -7,97 +7,105 @@ Feel free to contact us to be added to this list!
- Homepage: <https://www.pleroma.com/#desktopApp> - Homepage: <https://www.pleroma.com/#desktopApp>
- Source Code: <https://github.com/roma-apps/roma-desktop> - Source Code: <https://github.com/roma-apps/roma-desktop>
- Platforms: Windows, Mac, Linux - Platforms: Windows, Mac, Linux
- Features: Streaming Ready - Features: MastoAPI, Streaming Ready
### Social ### Social
- Source Code: <https://gitlab.gnome.org/World/Social> - Source Code: <https://gitlab.gnome.org/World/Social>
- Contact: [@brainblasted@social.libre.fi](https://social.libre.fi/users/brainblasted) - Contact: [@brainblasted@social.libre.fi](https://social.libre.fi/users/brainblasted)
- Platforms: Linux (GNOME) - Platforms: Linux (GNOME)
- Note(2019-01-28): Not at a pre-alpha stage yet - Note(2019-01-28): Not at a pre-alpha stage yet
- Features: MastoAPI
### Whalebird ### Whalebird
- Homepage: <https://whalebird.org/> - Homepage: <https://whalebird.org/>
- Source Code: <https://github.com/h3poteto/whalebird-desktop> - Source Code: <https://github.com/h3poteto/whalebird-desktop>
- Contact: [@h3poteto@pleroma.io](https://pleroma.io/users/h3poteto) - Contact: [@h3poteto@pleroma.io](https://pleroma.io/users/h3poteto)
- Platforms: Windows, Mac, Linux - Platforms: Windows, Mac, Linux
- Features: Streaming Ready - Features: MastoAPI, Streaming Ready
## Handheld ## Handheld
### AndStatus
- Homepage: <http://andstatus.org/>
- Source Code: <https://github.com/andstatus/andstatus/>
- Platforms: Android
- Features: MastoAPI, ActivityPub (Client-to-Server)
### Amaroq ### Amaroq
- Homepage: <https://itunes.apple.com/us/app/amaroq-for-mastodon/id1214116200> - Homepage: <https://itunes.apple.com/us/app/amaroq-for-mastodon/id1214116200>
- Source Code: <https://github.com/ReticentJohn/Amaroq> - Source Code: <https://github.com/ReticentJohn/Amaroq>
- Contact: [@eurasierboy@mastodon.social](https://mastodon.social/users/eurasierboy) - Contact: [@eurasierboy@mastodon.social](https://mastodon.social/users/eurasierboy)
- Platforms: iOS - Platforms: iOS
- Features: No Streaming - Features: MastoAPI, No Streaming
### Fedilab ### Fedilab
- Homepage: <https://fedilab.app/> - Homepage: <https://fedilab.app/>
- Source Code: <https://framagit.org/tom79/fedilab/> - Source Code: <https://framagit.org/tom79/fedilab/>
- Contact: [@fedilab@framapiaf.org](https://framapiaf.org/users/fedilab) - Contact: [@fedilab@framapiaf.org](https://framapiaf.org/users/fedilab)
- Platforms: Android - Platforms: Android
- Features: Streaming Ready, Moderation, Text Formatting - Features: MastoAPI, Streaming Ready, Moderation, Text Formatting
### Kyclos ### Kyclos
- Source Code: <https://git.pleroma.social/pleroma/harbour-kyclos> - Source Code: <https://git.pleroma.social/pleroma/harbour-kyclos>
- Platforms: SailfishOS - Platforms: SailfishOS
- Features: No Streaming - Features: MastoAPI, No Streaming
### Husky ### Husky
- Source code: <https://git.mentality.rip/FWGS/Husky> - Source code: <https://git.mentality.rip/FWGS/Husky>
- Contact: [@Husky@enigmatic.observer](https://enigmatic.observer/users/Husky) - Contact: [@Husky@enigmatic.observer](https://enigmatic.observer/users/Husky)
- Platforms: Android - Platforms: Android
- Features: No Streaming, Emoji Reactions, Text Formatting, FE Stickers - Features: MastoAPI, No Streaming, Emoji Reactions, Text Formatting, FE Stickers
### Fedi ### Fedi
- Homepage: <https://www.fediapp.com/> - Homepage: <https://www.fediapp.com/>
- Source Code: Proprietary, but gratis - Source Code: Proprietary, but gratis
- Platforms: iOS, Android - Platforms: iOS, Android
- Features: Pleroma-specific features like Reactions - Features: MastoAPI, Pleroma-specific features like Reactions
### Tusky ### Tusky
- Homepage: <https://tuskyapp.github.io/> - Homepage: <https://tuskyapp.github.io/>
- Source Code: <https://github.com/tuskyapp/Tusky> - Source Code: <https://github.com/tuskyapp/Tusky>
- Contact: [@ConnyDuck@mastodon.social](https://mastodon.social/users/ConnyDuck) - Contact: [@ConnyDuck@mastodon.social](https://mastodon.social/users/ConnyDuck)
- Platforms: Android - Platforms: Android
- Features: No Streaming - Features: MastoAPI, No Streaming
### Twidere ### Twidere
- Homepage: <https://twidere.mariotaku.org/> - Homepage: <https://twidere.mariotaku.org/>
- Source Code: <https://github.com/TwidereProject/Twidere-Android/> - Source Code: <https://github.com/TwidereProject/Twidere-Android/>
- Contact: <me@mariotaku.org> - Contact: <me@mariotaku.org>
- Platform: Android - Platform: Android
- Features: No Streaming - Features: MastoAPI, No Streaming
### Indigenous ### Indigenous
- Homepage: <https://indigenous.realize.be/> - Homepage: <https://indigenous.realize.be/>
- Source Code: <https://github.com/swentel/indigenous-android/> - Source Code: <https://github.com/swentel/indigenous-android/>
- Contact: [@realize.be@realize.be](@realize.be@realize.be) - Contact: [@swentel@realize.be](https://realize.be)
- Platforms: Android - Platforms: Android
- Features: No Streaming - Features: MastoAPI, No Streaming
## Alternative Web Interfaces ## Alternative Web Interfaces
### Brutaldon ### Brutaldon
- Homepage: <https://jfm.carcosa.net/projects/software/brutaldon/> - Homepage: <https://jfm.carcosa.net/projects/software/brutaldon/>
- Source Code: <https://git.carcosa.net/jmcbray/brutaldon> - Source Code: <https://git.carcosa.net/jmcbray/brutaldon>
- Contact: [@gcupc@glitch.social](https://glitch.social/users/gcupc) - Contact: [@gcupc@glitch.social](https://glitch.social/users/gcupc)
- Features: No Streaming - Features: MastoAPI, No Streaming
### Halcyon ### Halcyon
- Source Code: <https://notabug.org/halcyon-suite/halcyon> - Source Code: <https://notabug.org/halcyon-suite/halcyon>
- Contact: [@halcyon@social.csswg.org](https://social.csswg.org/users/halcyon) - Contact: [@halcyon@social.csswg.org](https://social.csswg.org/users/halcyon)
- Features: Streaming Ready - Features: MastoAPI, Streaming Ready
### Pinafore ### Pinafore
- Homepage: <https://pinafore.social/> - Homepage: <https://pinafore.social/>
- Source Code: <https://github.com/nolanlawson/pinafore> - Source Code: <https://github.com/nolanlawson/pinafore>
- Contact: [@pinafore@mastodon.technology](https://mastodon.technology/users/pinafore) - Contact: [@pinafore@mastodon.technology](https://mastodon.technology/users/pinafore)
- Note: Pleroma support is a secondary goal - Note: Pleroma support is a secondary goal
- Features: No Streaming - Features: MastoAPI, No Streaming
### Sengi ### Sengi
- Homepage: <https://nicolasconstant.github.io/sengi/> - Homepage: <https://nicolasconstant.github.io/sengi/>
- Source Code: <https://github.com/NicolasConstant/sengi> - Source Code: <https://github.com/NicolasConstant/sengi>
- Contact: [@sengi_app@mastodon.social](https://mastodon.social/users/sengi_app) - Contact: [@sengi_app@mastodon.social](https://mastodon.social/users/sengi_app)
- Features: MastoAPI
### DashFE ### DashFE
- Source Code: <https://notabug.org/daisuke/DashboardFE> - Source Code: <https://notabug.org/daisuke/DashboardFE>
@ -107,3 +115,4 @@ Feel free to contact us to be added to this list!
- Source Code: <https://git.freesoftwareextremist.com/bloat/> - Source Code: <https://git.freesoftwareextremist.com/bloat/>
- Contact: [@r@freesoftwareextremist.com](https://freesoftwareextremist.com/users/r) - Contact: [@r@freesoftwareextremist.com](https://freesoftwareextremist.com/users/r)
- Features: Does not requires JavaScript - Features: Does not requires JavaScript
- Features: MastoAPI

View File

@ -13,6 +13,7 @@ It assumes that you have administrative rights, either as root or a user with [s
* `erlang-parsetools` * `erlang-parsetools`
* `erlang-xmerl` * `erlang-xmerl`
* `git` * `git`
* `file-dev`
* Development Tools * Development Tools
* `cmake` * `cmake`
@ -42,7 +43,7 @@ sudo apk upgrade
* Install some tools, which are needed later: * Install some tools, which are needed later:
```shell ```shell
sudo apk add git build-base cmake sudo apk add git build-base cmake file-dev
``` ```
### Install Elixir and Erlang ### Install Elixir and Erlang

View File

@ -10,6 +10,7 @@ This guide will assume that you have administrative rights, either as root or a
* `git` * `git`
* `base-devel` * `base-devel`
* `cmake` * `cmake`
* `file`
#### Optional packages used in this guide #### Optional packages used in this guide
@ -30,7 +31,7 @@ sudo pacman -Syu
* Install some of the above mentioned programs: * Install some of the above mentioned programs:
```shell ```shell
sudo pacman -S git base-devel elixir cmake sudo pacman -S git base-devel elixir cmake file
``` ```
### Install PostgreSQL ### Install PostgreSQL

View File

@ -10,6 +10,7 @@ This guide will assume you are on Debian Stretch. This guide should also work wi
* `elixir` (1.8+, Follow the guide to install from the Erlang Solutions repo or use [asdf](https://github.com/asdf-vm/asdf) as the pleroma user) * `elixir` (1.8+, Follow the guide to install from the Erlang Solutions repo or use [asdf](https://github.com/asdf-vm/asdf) as the pleroma user)
* `erlang-dev` * `erlang-dev`
* `erlang-nox` * `erlang-nox`
* `libmagic-dev`
* `git` * `git`
* `build-essential` * `build-essential`
* `cmake` * `cmake`
@ -34,7 +35,7 @@ sudo apt full-upgrade
* Install some of the above mentioned programs: * Install some of the above mentioned programs:
```shell ```shell
sudo apt install git build-essential postgresql postgresql-contrib cmake sudo apt install git build-essential postgresql postgresql-contrib cmake libmagic-devel
``` ```
### Install Elixir and Erlang ### Install Elixir and Erlang
@ -100,6 +101,7 @@ sudo -Hu pleroma mix deps.get
mv config/{generated_config.exs,prod.secret.exs} mv config/{generated_config.exs,prod.secret.exs}
``` ```
* The previous command creates also the file `config/setup_db.psql`, with which you can create the database: * The previous command creates also the file `config/setup_db.psql`, with which you can create the database:
```shell ```shell
@ -180,6 +182,7 @@ sudo cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.se
``` ```
* Edit the service file and make sure that all paths fit your installation * Edit the service file and make sure that all paths fit your installation
* Check that `EnvironmentFile` contains the correct path to the env file. Or generate the env file: `sudo -Hu pleroma mix pleroma.release_env gen`
* Enable and start `pleroma.service`: * Enable and start `pleroma.service`:
```shell ```shell

View File

@ -17,6 +17,7 @@
- `git` - `git`
- `build-essential` - `build-essential`
- `cmake` - `cmake`
- `libmagic-dev`
#### このガイドで利用している追加パッケージ #### このガイドで利用している追加パッケージ
@ -36,7 +37,7 @@ sudo apt full-upgrade
* 上記に挙げたパッケージをインストールしておきます。 * 上記に挙げたパッケージをインストールしておきます。
``` ```
sudo apt install git build-essential postgresql postgresql-contrib cmake ffmpeg imagemagick sudo apt install git build-essential postgresql postgresql-contrib cmake ffmpeg imagemagick libmagic-dev
``` ```
### ElixirとErlangをインストールします ### ElixirとErlangをインストールします

View File

@ -29,6 +29,7 @@ Gentoo quite pointedly does not come with a cron daemon installed, and as such i
* `dev-lang/elixir` * `dev-lang/elixir`
* `dev-vcs/git` * `dev-vcs/git`
* `dev-util/cmake` * `dev-util/cmake`
* `sys-apps/file`
#### Optional ebuilds used in this guide #### Optional ebuilds used in this guide
@ -50,7 +51,7 @@ Gentoo quite pointedly does not come with a cron daemon installed, and as such i
* Emerge all required the required and suggested software in one go: * Emerge all required the required and suggested software in one go:
```shell ```shell
# emerge --ask dev-db/postgresql dev-lang/elixir dev-vcs/git www-servers/nginx app-crypt/certbot app-crypt/certbot-nginx dev-util/cmake # emerge --ask dev-db/postgresql dev-lang/elixir dev-vcs/git www-servers/nginx app-crypt/certbot app-crypt/certbot-nginx dev-util/cmake sys-apps/file
``` ```
If you would not like to install the optional packages, remove them from this line. If you would not like to install the optional packages, remove them from this line.

View File

@ -27,22 +27,23 @@ Other than things bundled in the OTP release Pleroma depends on:
* PostgreSQL (also utilizes extensions in postgresql-contrib) * PostgreSQL (also utilizes extensions in postgresql-contrib)
* nginx (could be swapped with another reverse proxy but this guide covers only it) * nginx (could be swapped with another reverse proxy but this guide covers only it)
* certbot (for Let's Encrypt certificates, could be swapped with another ACME client, but this guide covers only it) * certbot (for Let's Encrypt certificates, could be swapped with another ACME client, but this guide covers only it)
* libmagic/file
=== "Alpine" === "Alpine"
``` ```
echo "http://nl.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories echo "http://nl.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories
apk update apk update
apk add curl unzip ncurses postgresql postgresql-contrib nginx certbot apk add curl unzip ncurses postgresql postgresql-contrib nginx certbot file-dev
``` ```
=== "Debian/Ubuntu" === "Debian/Ubuntu"
``` ```
apt install curl unzip libncurses5 postgresql postgresql-contrib nginx certbot apt install curl unzip libncurses5 postgresql postgresql-contrib nginx certbot libmagic-dev
``` ```
### Installing optional packages ### Installing optional packages
Per [`docs/installation/optional/media_graphics_packages.md`](docs/installation/optional/media_graphics_packages.md): Per [`docs/installation/optional/media_graphics_packages.md`](optional/media_graphics_packages.md):
* ImageMagick * ImageMagick
* ffmpeg * ffmpeg
* exiftool * exiftool
@ -148,6 +149,9 @@ chown -R pleroma /etc/pleroma
# Run the config generator # Run the config generator
su pleroma -s $SHELL -lc "./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql" su pleroma -s $SHELL -lc "./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql"
# Run the environment file generator.
su pleroma -s $SHELL -lc "./bin/pleroma_ctl release_env gen"
# Create the postgres database # Create the postgres database
su postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql" su postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql"
@ -158,7 +162,7 @@ su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate"
# su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/" # su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/"
# Start the instance to verify that everything is working as expected # Start the instance to verify that everything is working as expected
su pleroma -s $SHELL -lc "./bin/pleroma daemon" su pleroma -s $SHELL -lc "export $(cat /opt/pleroma/config/pleroma.env); ./bin/pleroma daemon"
# Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly # Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly
sleep 20 && curl http://localhost:4000/api/v1/instance sleep 20 && curl http://localhost:4000/api/v1/instance
@ -310,4 +314,3 @@ This will create an account withe the username of 'joeuser' with the email addre
## Questions ## Questions
Questions about the installation or didnt it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**. Questions about the installation or didnt it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.

View File

@ -8,6 +8,7 @@ pidfile="/var/run/pleroma.pid"
directory=/opt/pleroma directory=/opt/pleroma
healthcheck_delay=60 healthcheck_delay=60
healthcheck_timer=30 healthcheck_timer=30
export $(cat /opt/pleroma/config/pleroma.env)
: ${pleroma_port:-4000} : ${pleroma_port:-4000}

View File

@ -17,6 +17,8 @@ Environment="MIX_ENV=prod"
Environment="HOME=/var/lib/pleroma" Environment="HOME=/var/lib/pleroma"
; Path to the folder containing the Pleroma installation. ; Path to the folder containing the Pleroma installation.
WorkingDirectory=/opt/pleroma WorkingDirectory=/opt/pleroma
; Path to the environment file. the file contains RELEASE_COOKIE and etc
EnvironmentFile=/opt/pleroma/config/pleroma.env
; Path to the Mix binary. ; Path to the Mix binary.
ExecStart=/usr/bin/mix phx.server ExecStart=/usr/bin/mix phx.server
@ -29,8 +31,6 @@ ProtectHome=true
ProtectSystem=full ProtectSystem=full
; Sets up a new /dev mount for the process and only adds API pseudo devices like /dev/null, /dev/zero or /dev/random but not physical devices. Disabled by default because it may not work on devices like the Raspberry Pi. ; Sets up a new /dev mount for the process and only adds API pseudo devices like /dev/null, /dev/zero or /dev/random but not physical devices. Disabled by default because it may not work on devices like the Raspberry Pi.
PrivateDevices=false PrivateDevices=false
; Ensures that the service process and all its children can never gain new privileges through execve().
NoNewPrivileges=true
; Drops the sysadmin capability from the daemon. ; Drops the sysadmin capability from the daemon.
CapabilityBoundingSet=~CAP_SYS_ADMIN CapabilityBoundingSet=~CAP_SYS_ADMIN

View File

@ -36,7 +36,9 @@ def run(["gen" | rest]) do
listen_port: :string, listen_port: :string,
strip_uploads: :string, strip_uploads: :string,
anonymize_uploads: :string, anonymize_uploads: :string,
dedupe_uploads: :string dedupe_uploads: :string,
skip_release_env: :boolean,
release_env_file: :string
], ],
aliases: [ aliases: [
o: :output, o: :output,
@ -241,6 +243,24 @@ def run(["gen" | rest]) do
write_robots_txt(static_dir, indexable, template_dir) write_robots_txt(static_dir, indexable, template_dir)
if Keyword.get(options, :skip_release_env, false) do
shell_info("""
Release environment file is skip. Please generate the release env file before start.
`MIX_ENV=#{Mix.env()} mix pleroma.release_env gen`
""")
else
shell_info("Generation the environment file:")
release_env_args =
with path when not is_nil(path) <- Keyword.get(options, :release_env_file) do
["gen", "--path", path]
else
_ -> ["gen"]
end
Mix.Tasks.Pleroma.ReleaseEnv.run(release_env_args)
end
shell_info( shell_info(
"\n All files successfully written! Refer to the installation instructions for your platform for next steps." "\n All files successfully written! Refer to the installation instructions for your platform for next steps."
) )

View File

@ -0,0 +1,76 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.ReleaseEnv do
use Mix.Task
import Mix.Pleroma
@shortdoc "Generate Pleroma environment file."
@moduledoc File.read!("docs/administration/CLI_tasks/release_environments.md")
def run(["gen" | rest]) do
{options, [], []} =
OptionParser.parse(
rest,
strict: [
force: :boolean,
path: :string
],
aliases: [
p: :path,
f: :force
]
)
file_path =
get_option(
options,
:path,
"Environment file path",
"./config/pleroma.env"
)
env_path = Path.expand(file_path)
proceed? =
if File.exists?(env_path) do
get_option(
options,
:force,
"Environment file already exists. Do you want to overwrite the #{env_path} file? (y/n)",
"n"
) === "y"
else
true
end
if proceed? do
case do_generate(env_path) do
{:error, reason} ->
shell_error(
File.Error.message(%{action: "write to file", reason: reason, path: env_path})
)
_ ->
shell_info("\nThe file generated: #{env_path}.\n")
shell_info("""
WARNING: before start pleroma app please make sure to make the file read-only and non-modifiable.
Example:
chmod 0444 #{file_path}
chattr +i #{file_path}
""")
end
else
shell_info("\nThe file is exist. #{env_path}.\n")
end
end
def do_generate(path) do
content = "RELEASE_COOKIE=#{Base.encode32(:crypto.strong_rand_bytes(32))}"
File.mkdir_p!(Path.dirname(path))
File.write(path, content)
end
end

View File

@ -419,7 +419,7 @@ def run(["list"]) do
|> Enum.each(fn user -> |> Enum.each(fn user ->
shell_info( shell_info(
"#{user.nickname} moderator: #{user.is_moderator}, admin: #{user.is_admin}, locked: #{ "#{user.nickname} moderator: #{user.is_moderator}, admin: #{user.is_admin}, locked: #{
user.locked user.is_locked
}, deactivated: #{user.deactivated}" }, deactivated: #{user.deactivated}"
) )
end) end)
@ -447,10 +447,10 @@ defp set_admin(user, value) do
defp set_locked(user, value) do defp set_locked(user, value) do
{:ok, user} = {:ok, user} =
user user
|> Changeset.change(%{locked: value}) |> Changeset.change(%{is_locked: value})
|> User.update_and_set_cache() |> User.update_and_set_cache()
shell_info("Locked status of #{user.nickname}: #{user.locked}") shell_info("Locked status of #{user.nickname}: #{user.is_locked}")
user user
end end

View File

@ -31,7 +31,12 @@ def init(%Plug.Conn{method: "GET"} = conn, {endpoint, handler, transport}) do
case conn do case conn do
%{halted: false} = conn -> %{halted: false} = conn ->
case Transport.connect(endpoint, handler, transport, __MODULE__, nil, conn.params) do case handler.connect(%{
endpoint: endpoint,
transport: transport,
options: [serializer: nil],
params: conn.params
}) do
{:ok, socket} -> {:ok, socket} ->
{:ok, conn, {__MODULE__, {socket, opts}}} {:ok, conn, {__MODULE__, {socket, opts}}}

View File

@ -95,11 +95,12 @@ def start(_type, _args) do
[ [
Pleroma.Stats, Pleroma.Stats,
Pleroma.JobQueueMonitor, Pleroma.JobQueueMonitor,
{Majic.Pool, [name: Pleroma.MajicPool, pool_size: Config.get([:majic_pool, :size], 2)]},
{Oban, Config.get(Oban)} {Oban, Config.get(Oban)}
] ++ ] ++
task_children(@env) ++ task_children(@env) ++
dont_run_in_test(@env) ++ dont_run_in_test(@env) ++
chat_child(@env, chat_enabled?()) ++ chat_child(chat_enabled?()) ++
[ [
Pleroma.Web.Endpoint, Pleroma.Web.Endpoint,
Pleroma.Gopher.Server Pleroma.Gopher.Server
@ -150,7 +151,10 @@ defp setup_instrumenters do
Pleroma.Web.Endpoint.MetricsExporter.setup() Pleroma.Web.Endpoint.MetricsExporter.setup()
Pleroma.Web.Endpoint.PipelineInstrumenter.setup() Pleroma.Web.Endpoint.PipelineInstrumenter.setup()
Pleroma.Web.Endpoint.Instrumenter.setup()
# Note: disabled until prometheus-phx is integrated into prometheus-phoenix:
# Pleroma.Web.Endpoint.Instrumenter.setup()
PrometheusPhx.setup()
end end
defp cachex_children do defp cachex_children do
@ -201,11 +205,14 @@ defp dont_run_in_test(_) do
] ]
end end
defp chat_child(_env, true) do defp chat_child(true) do
[Pleroma.Web.ChatChannel.ChatChannelState] [
Pleroma.Web.ChatChannel.ChatChannelState,
{Phoenix.PubSub, [name: Pleroma.PubSub, adapter: Phoenix.PubSub.PG2]}
]
end end
defp chat_child(_, _), do: [] defp chat_child(_), do: []
defp task_children(:test) do defp task_children(:test) do
[ [

View File

@ -1,120 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MIME do
@moduledoc """
Returns the mime-type of a binary and optionally a normalized file-name.
"""
@default "application/octet-stream"
@read_bytes 35
@spec file_mime_type(String.t(), String.t()) ::
{:ok, content_type :: String.t(), filename :: String.t()} | {:error, any()} | :error
def file_mime_type(path, filename) do
with {:ok, content_type} <- file_mime_type(path),
filename <- fix_extension(filename, content_type) do
{:ok, content_type, filename}
end
end
@spec file_mime_type(String.t()) :: {:ok, String.t()} | {:error, any()} | :error
def file_mime_type(filename) do
File.open(filename, [:read], fn f ->
check_mime_type(IO.binread(f, @read_bytes))
end)
end
def bin_mime_type(binary, filename) do
with {:ok, content_type} <- bin_mime_type(binary),
filename <- fix_extension(filename, content_type) do
{:ok, content_type, filename}
end
end
@spec bin_mime_type(binary()) :: {:ok, String.t()} | :error
def bin_mime_type(<<head::binary-size(@read_bytes), _::binary>>) do
{:ok, check_mime_type(head)}
end
def bin_mime_type(_), do: :error
def mime_type(<<_::binary>>), do: {:ok, @default}
defp fix_extension(filename, content_type) do
parts = String.split(filename, ".")
new_filename =
if length(parts) > 1 do
Enum.drop(parts, -1) |> Enum.join(".")
else
Enum.join(parts)
end
cond do
content_type == "application/octet-stream" ->
filename
ext = List.first(MIME.extensions(content_type)) ->
new_filename <> "." <> ext
true ->
Enum.join([new_filename, String.split(content_type, "/") |> List.last()], ".")
end
end
defp check_mime_type(<<0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, _::binary>>) do
"image/png"
end
defp check_mime_type(<<0x47, 0x49, 0x46, 0x38, _, 0x61, _::binary>>) do
"image/gif"
end
defp check_mime_type(<<0xFF, 0xD8, 0xFF, _::binary>>) do
"image/jpeg"
end
defp check_mime_type(<<0x1A, 0x45, 0xDF, 0xA3, _::binary>>) do
"video/webm"
end
defp check_mime_type(<<0x00, 0x00, 0x00, _, 0x66, 0x74, 0x79, 0x70, _::binary>>) do
"video/mp4"
end
defp check_mime_type(<<0x49, 0x44, 0x33, _::binary>>) do
"audio/mpeg"
end
defp check_mime_type(<<255, 251, _, 68, 0, 0, 0, 0, _::binary>>) do
"audio/mpeg"
end
defp check_mime_type(
<<0x4F, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, _::size(160), 0x80, 0x74, 0x68, 0x65,
0x6F, 0x72, 0x61, _::binary>>
) do
"video/ogg"
end
defp check_mime_type(<<0x4F, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, _::binary>>) do
"audio/ogg"
end
defp check_mime_type(<<"RIFF", _::binary-size(4), "WAVE", _::binary>>) do
"audio/wav"
end
defp check_mime_type(<<"RIFF", _::binary-size(4), "WEBP", _::binary>>) do
"image/webp"
end
defp check_mime_type(<<"RIFF", _::binary-size(4), "AVI.", _::binary>>) do
"video/avi"
end
defp check_mime_type(_) do
@default
end
end

View File

@ -66,6 +66,7 @@ defp get_description(opts, upload) do
end end
@spec store(source, options :: [option()]) :: {:ok, Map.t()} | {:error, any()} @spec store(source, options :: [option()]) :: {:ok, Map.t()} | {:error, any()}
@doc "Store a file. If using a `Plug.Upload{}` as the source, be sure to use `Majic.Plug` to ensure its content_type and filename is correct."
def store(upload, opts \\ []) do def store(upload, opts \\ []) do
opts = get_opts(opts) opts = get_opts(opts)
@ -139,14 +140,13 @@ defp get_opts(opts) do
end end
defp prepare_upload(%Plug.Upload{} = file, opts) do defp prepare_upload(%Plug.Upload{} = file, opts) do
with :ok <- check_file_size(file.path, opts.size_limit), with :ok <- check_file_size(file.path, opts.size_limit) do
{:ok, content_type, name} <- Pleroma.MIME.file_mime_type(file.path, file.filename) do
{:ok, {:ok,
%__MODULE__{ %__MODULE__{
id: UUID.generate(), id: UUID.generate(),
name: name, name: file.filename,
tempfile: file.path, tempfile: file.path,
content_type: content_type content_type: file.content_type
}} }}
end end
end end
@ -154,16 +154,17 @@ defp prepare_upload(%Plug.Upload{} = file, opts) do
defp prepare_upload(%{img: "data:image/" <> image_data}, opts) do defp prepare_upload(%{img: "data:image/" <> image_data}, opts) do
parsed = Regex.named_captures(~r/(?<filetype>jpeg|png|gif);base64,(?<data>.*)/, image_data) parsed = Regex.named_captures(~r/(?<filetype>jpeg|png|gif);base64,(?<data>.*)/, image_data)
data = Base.decode64!(parsed["data"], ignore: :whitespace) data = Base.decode64!(parsed["data"], ignore: :whitespace)
hash = String.downcase(Base.encode16(:crypto.hash(:sha256, data))) hash = Base.encode16(:crypto.hash(:sha256, data), lower: true)
with :ok <- check_binary_size(data, opts.size_limit), with :ok <- check_binary_size(data, opts.size_limit),
tmp_path <- tempfile_for_image(data), tmp_path <- tempfile_for_image(data),
{:ok, content_type, name} <- {:ok, %{mime_type: content_type}} <-
Pleroma.MIME.bin_mime_type(data, hash <> "." <> parsed["filetype"]) do Majic.perform({:bytes, data}, pool: Pleroma.MajicPool),
[ext | _] <- MIME.extensions(content_type) do
{:ok, {:ok,
%__MODULE__{ %__MODULE__{
id: UUID.generate(), id: UUID.generate(),
name: name, name: hash <> "." <> ext,
tempfile: tmp_path, tempfile: tmp_path,
content_type: content_type content_type: content_type
}} }}
@ -172,7 +173,7 @@ defp prepare_upload(%{img: "data:image/" <> image_data}, opts) do
# For Mix.Tasks.MigrateLocalUploads # For Mix.Tasks.MigrateLocalUploads
defp prepare_upload(%__MODULE__{tempfile: path} = upload, _opts) do defp prepare_upload(%__MODULE__{tempfile: path} = upload, _opts) do
with {:ok, content_type} <- Pleroma.MIME.file_mime_type(path) do with {:ok, %{mime_type: content_type}} <- Majic.perform(path, pool: Pleroma.MajicPool) do
{:ok, %__MODULE__{upload | content_type: content_type}} {:ok, %__MODULE__{upload | content_type: content_type}}
end end
end end

View File

@ -107,7 +107,7 @@ defmodule Pleroma.User do
field(:note_count, :integer, default: 0) field(:note_count, :integer, default: 0)
field(:follower_count, :integer, default: 0) field(:follower_count, :integer, default: 0)
field(:following_count, :integer, default: 0) field(:following_count, :integer, default: 0)
field(:locked, :boolean, default: false) field(:is_locked, :boolean, default: false)
field(:confirmation_pending, :boolean, default: false) field(:confirmation_pending, :boolean, default: false)
field(:password_reset_pending, :boolean, default: false) field(:password_reset_pending, :boolean, default: false)
field(:approval_pending, :boolean, default: false) field(:approval_pending, :boolean, default: false)
@ -136,7 +136,7 @@ defmodule Pleroma.User do
field(:pleroma_settings_store, :map, default: %{}) field(:pleroma_settings_store, :map, default: %{})
field(:fields, {:array, :map}, default: []) field(:fields, {:array, :map}, default: [])
field(:raw_fields, {:array, :map}, default: []) field(:raw_fields, {:array, :map}, default: [])
field(:discoverable, :boolean, default: false) field(:is_discoverable, :boolean, default: false)
field(:invisible, :boolean, default: false) field(:invisible, :boolean, default: false)
field(:allow_following_move, :boolean, default: true) field(:allow_following_move, :boolean, default: true)
field(:skip_thread_containment, :boolean, default: false) field(:skip_thread_containment, :boolean, default: false)
@ -436,7 +436,7 @@ def remote_user_changeset(struct \\ %User{local: false}, params) do
:avatar, :avatar,
:ap_enabled, :ap_enabled,
:banner, :banner,
:locked, :is_locked,
:last_refreshed_at, :last_refreshed_at,
:uri, :uri,
:follower_address, :follower_address,
@ -448,7 +448,7 @@ def remote_user_changeset(struct \\ %User{local: false}, params) do
:follower_count, :follower_count,
:fields, :fields,
:following_count, :following_count,
:discoverable, :is_discoverable,
:invisible, :invisible,
:actor_type, :actor_type,
:also_known_as, :also_known_as,
@ -479,7 +479,7 @@ def update_changeset(struct, params \\ %{}) do
:public_key, :public_key,
:inbox, :inbox,
:shared_inbox, :shared_inbox,
:locked, :is_locked,
:no_rich_text, :no_rich_text,
:default_scope, :default_scope,
:banner, :banner,
@ -495,7 +495,7 @@ def update_changeset(struct, params \\ %{}) do
:fields, :fields,
:raw_fields, :raw_fields,
:pleroma_settings_store, :pleroma_settings_store,
:discoverable, :is_discoverable,
:actor_type, :actor_type,
:also_known_as, :also_known_as,
:accepts_chat_messages :accepts_chat_messages
@ -847,7 +847,7 @@ def needs_update?(_), do: true
@spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()} @spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()}
# "Locked" (self-locked) users demand explicit authorization of follow requests # "Locked" (self-locked) users demand explicit authorization of follow requests
def maybe_direct_follow(%User{} = follower, %User{local: true, locked: true} = followed) do def maybe_direct_follow(%User{} = follower, %User{local: true, is_locked: true} = followed) do
follow(follower, followed, :follow_pending) follow(follower, followed, :follow_pending)
end end
@ -954,7 +954,7 @@ def get_follow_state(
end end
def locked?(%User{} = user) do def locked?(%User{} = user) do
user.locked || false user.is_locked || false
end end
def get_by_id(id) do def get_by_id(id) do
@ -1601,7 +1601,7 @@ def purge_user_changeset(user) do
note_count: 0, note_count: 0,
follower_count: 0, follower_count: 0,
following_count: 0, following_count: 0,
locked: false, is_locked: false,
confirmation_pending: false, confirmation_pending: false,
password_reset_pending: false, password_reset_pending: false,
approval_pending: false, approval_pending: false,
@ -1618,7 +1618,7 @@ def purge_user_changeset(user) do
pleroma_settings_store: %{}, pleroma_settings_store: %{},
fields: [], fields: [],
raw_fields: [], raw_fields: [],
discoverable: false, is_discoverable: false,
also_known_as: [] also_known_as: []
}) })
end end

View File

@ -164,7 +164,7 @@ defp filter_invisible_users(query) do
end end
defp filter_discoverable_users(query) do defp filter_discoverable_users(query) do
from(q in query, where: q.discoverable == true) from(q in query, where: q.is_discoverable == true)
end end
defp filter_internal_users(query) do defp filter_internal_users(query) do

View File

@ -172,7 +172,7 @@ def router do
def channel do def channel do
quote do quote do
# credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse # credo:disable-for-next-line Credo.Check.Consistency.MultiAliasImportRequireUse
use Phoenix.Channel import Phoenix.Channel
import Pleroma.Web.Gettext import Pleroma.Web.Gettext
end end
end end

View File

@ -828,7 +828,14 @@ defp restrict_muted(query, %{muting_user: %User{} = user} = opts) do
query = query =
from([activity] in query, from([activity] in query,
where: fragment("not (? = ANY(?))", activity.actor, ^mutes), where: fragment("not (? = ANY(?))", activity.actor, ^mutes),
where: fragment("not (?->'to' \\?| ?)", activity.data, ^mutes) where:
fragment(
"not (?->'to' \\?| ?) or ? = ?",
activity.data,
^mutes,
activity.actor,
^user.ap_id
)
) )
unless opts[:skip_preload] do unless opts[:skip_preload] do
@ -1268,11 +1275,11 @@ defp object_to_user_data(data) do
{String.trim(name, ":"), url} {String.trim(name, ":"), url}
end) end)
locked = data["manuallyApprovesFollowers"] || false is_locked = data["manuallyApprovesFollowers"] || false
capabilities = data["capabilities"] || %{} capabilities = data["capabilities"] || %{}
accepts_chat_messages = capabilities["acceptsChatMessages"] accepts_chat_messages = capabilities["acceptsChatMessages"]
data = Transmogrifier.maybe_fix_user_object(data) data = Transmogrifier.maybe_fix_user_object(data)
discoverable = data["discoverable"] || false is_discoverable = data["discoverable"] || false
invisible = data["invisible"] || false invisible = data["invisible"] || false
actor_type = data["type"] || "Person" actor_type = data["type"] || "Person"
@ -1297,8 +1304,8 @@ defp object_to_user_data(data) do
banner: banner, banner: banner,
fields: fields, fields: fields,
emoji: emojis, emoji: emojis,
locked: locked, is_locked: is_locked,
discoverable: discoverable, is_discoverable: is_discoverable,
invisible: invisible, invisible: invisible,
avatar: avatar, avatar: avatar,
name: data["name"], name: data["name"],

View File

@ -45,6 +45,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
when action in [:read_inbox, :update_outbox, :whoami, :upload_media] when action in [:read_inbox, :update_outbox, :whoami, :upload_media]
) )
plug(Majic.Plug, [pool: Pleroma.MajicPool] when action in [:upload_media])
plug( plug(
Pleroma.Web.Plugs.Cache, Pleroma.Web.Plugs.Cache,
[query_params: false, tracking_fun: &__MODULE__.track_object_fetch/2] [query_params: false, tracking_fun: &__MODULE__.track_object_fetch/2]
@ -412,7 +414,7 @@ defp handle_user_activity(
object = object =
object object
|> Map.merge(Map.take(params, ["to", "cc"])) |> Map.merge(Map.take(params, ["to", "cc"]))
|> Map.put("attributedTo", user.ap_id()) |> Map.put("attributedTo", user.ap_id)
|> Transmogrifier.fix_object() |> Transmogrifier.fix_object()
ActivityPub.create(%{ ActivityPub.create(%{
@ -456,7 +458,7 @@ def update_outbox(
%{assigns: %{user: %User{nickname: nickname} = user}} = conn, %{assigns: %{user: %User{nickname: nickname} = user}} = conn,
%{"nickname" => nickname} = params %{"nickname" => nickname} = params
) do ) do
actor = user.ap_id() actor = user.ap_id
params = params =
params params
@ -523,19 +525,6 @@ defp ensure_user_keys_present_and_maybe_refresh_for_user(user, for_user) do
{new_user, for_user} {new_user, for_user}
end end
@doc """
Endpoint based on <https://www.w3.org/wiki/SocialCG/ActivityPub/MediaUpload>
Parameters:
- (required) `file`: data of the media
- (optionnal) `description`: description of the media, intended for accessibility
Response:
- HTTP Code: 201 Created
- HTTP Body: ActivityPub object to be inserted into another's `attachment` field
Note: Will not point to a URL with a `Location` header because no standalone Activity has been created.
"""
def upload_media(%{assigns: %{user: %User{} = user}} = conn, %{"file" => file} = data) do def upload_media(%{assigns: %{user: %User{} = user}} = conn, %{"file" => file} = data) do
with {:ok, object} <- with {:ok, object} <-
ActivityPub.upload( ActivityPub.upload(

View File

@ -242,9 +242,7 @@ def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity)
end) end)
end end
@doc """ # Publishes an activity to all relevant peers.
Publishes an activity to all relevant peers.
"""
def publish(%User{} = actor, %Activity{} = activity) do def publish(%User{} = actor, %Activity{} = activity) do
public = is_public?(activity) public = is_public?(activity)

View File

@ -102,7 +102,7 @@ def handle(
%User{} = followed <- User.get_cached_by_ap_id(followed_user), %User{} = followed <- User.get_cached_by_ap_id(followed_user),
{_, {:ok, _}, _, _} <- {_, {:ok, _}, _, _} <-
{:following, User.follow(follower, followed, :follow_pending), follower, followed} do {:following, User.follow(follower, followed, :follow_pending), follower, followed} do
if followed.local && !followed.locked do if followed.local && !followed.is_locked do
{:ok, accept_data, _} = Builder.accept(followed, object) {:ok, accept_data, _} = Builder.accept(followed, object)
{:ok, _activity, _} = Pipeline.common_pipeline(accept_data, local: true) {:ok, _activity, _} = Pipeline.common_pipeline(accept_data, local: true)
end end
@ -306,6 +306,7 @@ def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do
streamables = streamables =
[[actor, recipient], [recipient, actor]] [[actor, recipient], [recipient, actor]]
|> Enum.uniq()
|> Enum.map(fn [user, other_user] -> |> Enum.map(fn [user, other_user] ->
if user.local do if user.local do
{:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id) {:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)

View File

@ -40,6 +40,7 @@ def fix_object(object, options \\ []) do
|> fix_in_reply_to(options) |> fix_in_reply_to(options)
|> fix_emoji |> fix_emoji
|> fix_tag |> fix_tag
|> set_sensitive
|> fix_content_map |> fix_content_map
|> fix_addressing |> fix_addressing
|> fix_summary |> fix_summary
@ -313,19 +314,21 @@ def fix_tag(%{"tag" => tag} = object) when is_list(tag) do
tags = tags =
tag tag
|> Enum.filter(fn data -> data["type"] == "Hashtag" and data["name"] end) |> Enum.filter(fn data -> data["type"] == "Hashtag" and data["name"] end)
|> Enum.map(fn data -> String.slice(data["name"], 1..-1) end) |> Enum.map(fn %{"name" => name} ->
name
|> String.slice(1..-1)
|> String.downcase()
end)
Map.put(object, "tag", tag ++ tags) Map.put(object, "tag", tag ++ tags)
end end
def fix_tag(%{"tag" => %{"type" => "Hashtag", "name" => hashtag} = tag} = object) do def fix_tag(%{"tag" => %{} = tag} = object) do
combined = [tag, String.slice(hashtag, 1..-1)] object
|> Map.put("tag", [tag])
Map.put(object, "tag", combined) |> fix_tag
end end
def fix_tag(%{"tag" => %{} = tag} = object), do: Map.put(object, "tag", [tag])
def fix_tag(object), do: object def fix_tag(object), do: object
# content map usually only has one language so this will do for now. # content map usually only has one language so this will do for now.
@ -927,7 +930,7 @@ def set_conversation(object) do
Map.put(object, "conversation", object["context"]) Map.put(object, "conversation", object["context"])
end end
def set_sensitive(%{"sensitive" => true} = object) do def set_sensitive(%{"sensitive" => _} = object) do
object object
end end

View File

@ -101,7 +101,7 @@ def render("user.json", %{user: user}) do
"name" => user.name, "name" => user.name,
"summary" => user.bio, "summary" => user.bio,
"url" => user.ap_id, "url" => user.ap_id,
"manuallyApprovesFollowers" => user.locked, "manuallyApprovesFollowers" => user.is_locked,
"publicKey" => %{ "publicKey" => %{
"id" => "#{user.ap_id}#main-key", "id" => "#{user.ap_id}#main-key",
"owner" => user.ap_id, "owner" => user.ap_id,
@ -110,7 +110,7 @@ def render("user.json", %{user: user}) do
"endpoints" => endpoints, "endpoints" => endpoints,
"attachment" => fields, "attachment" => fields,
"tag" => emoji_tags, "tag" => emoji_tags,
"discoverable" => user.discoverable, "discoverable" => user.is_discoverable,
"capabilities" => capabilities "capabilities" => capabilities
} }
|> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user)) |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))

View File

@ -39,7 +39,7 @@ def render("credentials.json", %{user: user, for: for_user}) do
:fields, :fields,
:name, :name,
:nickname, :nickname,
:locked, :is_locked,
:no_rich_text, :no_rich_text,
:default_scope, :default_scope,
:hide_follows, :hide_follows,

View File

@ -52,7 +52,7 @@ def render("show.json", %{report: report, user: user, account: account, statuses
end end
def render("index_notes.json", %{notes: notes}) when is_list(notes) do def render("index_notes.json", %{notes: notes}) when is_list(notes) do
Enum.map(notes, &render(__MODULE__, "show_note.json", &1)) Enum.map(notes, &render(__MODULE__, "show_note.json", Map.from_struct(&1)))
end end
def render("index_notes.json", _), do: [] def render("index_notes.json", _), do: []

View File

@ -50,7 +50,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Chat do
"fields" => [] "fields" => []
}, },
"statuses_count" => 1, "statuses_count" => 1,
"locked" => false, "is_locked" => false,
"created_at" => "2020-04-16T13:40:15.000Z", "created_at" => "2020-04-16T13:40:15.000Z",
"display_name" => "lain", "display_name" => "lain",
"fields" => [], "fields" => [],

View File

@ -252,7 +252,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
"header" => "http://localhost:4001/images/banner.png", "header" => "http://localhost:4001/images/banner.png",
"header_static" => "http://localhost:4001/images/banner.png", "header_static" => "http://localhost:4001/images/banner.png",
"id" => "9toJCsKN7SmSf3aj5c", "id" => "9toJCsKN7SmSf3aj5c",
"locked" => false, "is_locked" => false,
"note" => "Tester Number 6", "note" => "Tester Number 6",
"pleroma" => %{ "pleroma" => %{
"background_image" => nil, "background_image" => nil,

View File

@ -274,7 +274,7 @@ defp build_attachment_link(_), do: ""
def format_input(text, format, options \\ []) def format_input(text, format, options \\ [])
@doc """ @doc """
Formatting text to plain text. Formatting text to plain text, BBCode, HTML, or Markdown
""" """
def format_input(text, "text/plain", options) do def format_input(text, "text/plain", options) do
text text
@ -285,9 +285,6 @@ def format_input(text, "text/plain", options) do
end).() end).()
end end
@doc """
Formatting text as BBCode.
"""
def format_input(text, "text/bbcode", options) do def format_input(text, "text/bbcode", options) do
text text
|> String.replace(~r/\r/, "") |> String.replace(~r/\r/, "")
@ -297,18 +294,12 @@ def format_input(text, "text/bbcode", options) do
|> Formatter.linkify(options) |> Formatter.linkify(options)
end end
@doc """
Formatting text to html.
"""
def format_input(text, "text/html", options) do def format_input(text, "text/html", options) do
text text
|> Formatter.html_escape("text/html") |> Formatter.html_escape("text/html")
|> Formatter.linkify(options) |> Formatter.linkify(options)
end end
@doc """
Formatting text to markdown.
"""
def format_input(text, "text/markdown", options) do def format_input(text, "text/markdown", options) do
text text
|> Formatter.mentions_escape(options) |> Formatter.mentions_escape(options)

View File

@ -9,6 +9,8 @@ defmodule Pleroma.Web.Endpoint do
socket("/socket", Pleroma.Web.UserSocket) socket("/socket", Pleroma.Web.UserSocket)
plug(Plug.Telemetry, event_prefix: [:phoenix, :endpoint])
plug(Pleroma.Web.Plugs.SetLocalePlug) plug(Pleroma.Web.Plugs.SetLocalePlug)
plug(CORSPlug) plug(CORSPlug)
plug(Pleroma.Web.Plugs.HTTPSecurityPlug) plug(Pleroma.Web.Plugs.HTTPSecurityPlug)

View File

@ -177,7 +177,6 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
user_params = user_params =
[ [
:no_rich_text, :no_rich_text,
:locked,
:hide_followers_count, :hide_followers_count,
:hide_follows_count, :hide_follows_count,
:hide_followers, :hide_followers,
@ -186,7 +185,6 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
:show_role, :show_role,
:skip_thread_containment, :skip_thread_containment,
:allow_following_move, :allow_following_move,
:discoverable,
:accepts_chat_messages :accepts_chat_messages
] ]
|> Enum.reduce(%{}, fn key, acc -> |> Enum.reduce(%{}, fn key, acc ->
@ -210,6 +208,8 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
if bot, do: {:ok, "Service"}, else: {:ok, "Person"} if bot, do: {:ok, "Service"}, else: {:ok, "Person"}
end) end)
|> Maps.put_if_present(:actor_type, params[:actor_type]) |> Maps.put_if_present(:actor_type, params[:actor_type])
|> Maps.put_if_present(:is_locked, params[:locked])
|> Maps.put_if_present(:is_discoverable, params[:discoverable])
# What happens here: # What happens here:
# #

View File

@ -24,7 +24,7 @@ def login(%{assigns: %{user: %User{}}} = conn, _params) do
redirect(conn, to: local_mastodon_root_path(conn)) redirect(conn, to: local_mastodon_root_path(conn))
end end
@doc "Local Mastodon FE login init action" # Local Mastodon FE login init action
def login(conn, %{"code" => auth_token}) do def login(conn, %{"code" => auth_token}) do
with {:ok, app} <- get_or_make_app(), with {:ok, app} <- get_or_make_app(),
{:ok, auth} <- Authorization.get_by_token(app, auth_token), {:ok, auth} <- Authorization.get_by_token(app, auth_token),
@ -35,7 +35,7 @@ def login(conn, %{"code" => auth_token}) do
end end
end end
@doc "Local Mastodon FE callback action" # Local Mastodon FE callback action
def login(conn, _) do def login(conn, _) do
with {:ok, app} <- get_or_make_app() do with {:ok, app} <- get_or_make_app() do
path = path =

View File

@ -11,6 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.Plugs.OAuthScopesPlug
action_fallback(Pleroma.Web.MastodonAPI.FallbackController) action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
plug(Majic.Plug, [pool: Pleroma.MajicPool] when action in [:create, :create2])
plug(Pleroma.Web.ApiSpec.CastAndValidate) plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(:put_view, Pleroma.Web.MastodonAPI.StatusView) plug(:put_view, Pleroma.Web.MastodonAPI.StatusView)

View File

@ -127,9 +127,8 @@ def index(%{assigns: %{user: user}} = conn, %{ids: ids} = _params) do
@doc """ @doc """
POST /api/v1/statuses POST /api/v1/statuses
Creates a scheduled status when `scheduled_at` param is present and it's far enough
""" """
# Creates a scheduled status when `scheduled_at` param is present and it's far enough
def create( def create(
%{ %{
assigns: %{user: user}, assigns: %{user: user},
@ -160,11 +159,7 @@ def create(
end end
end end
@doc """ # Creates a regular status
POST /api/v1/statuses
Creates a regular status
"""
def create(%{assigns: %{user: user}, body_params: %{status: _} = params} = conn, _) do def create(%{assigns: %{user: user}, body_params: %{status: _} = params} = conn, _) do
params = Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id]) params = Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id])

View File

@ -242,7 +242,7 @@ defp do_render("show.json", %{user: user} = opts) do
username: username_from_nickname(user.nickname), username: username_from_nickname(user.nickname),
acct: user.nickname, acct: user.nickname,
display_name: display_name, display_name: display_name,
locked: user.locked, locked: user.is_locked,
created_at: Utils.to_masto_date(user.inserted_at), created_at: Utils.to_masto_date(user.inserted_at),
followers_count: followers_count, followers_count: followers_count,
following_count: following_count, following_count: following_count,
@ -261,7 +261,7 @@ defp do_render("show.json", %{user: user} = opts) do
sensitive: false, sensitive: false,
fields: user.raw_fields, fields: user.raw_fields,
pleroma: %{ pleroma: %{
discoverable: user.discoverable, discoverable: user.is_discoverable,
actor_type: user.actor_type actor_type: user.actor_type
} }
}, },

View File

@ -30,7 +30,7 @@ defp do_purge(method, url, headers, options) do
{:ok, %{status: status} = env} when 400 <= status and status < 500 -> {:ok, %{status: status} = env} when 400 <= status and status < 500 ->
{:error, env} {:error, env}
{:error, error} = error -> {:error, _} = error ->
error error
_ -> _ ->

View File

@ -10,7 +10,7 @@ defmodule Pleroma.Web.Metadata.Providers.RestrictIndexing do
""" """
@impl true @impl true
def build_tags(%{user: %{local: true, discoverable: true}}), do: [] def build_tags(%{user: %{local: true, is_discoverable: true}}), do: []
def build_tags(_) do def build_tags(_) do
[ [

View File

@ -17,6 +17,11 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
require Pleroma.Constants require Pleroma.Constants
plug(
Majic.Plug,
[pool: Pleroma.MajicPool] when action in [:update_avatar, :update_background, :update_banner]
)
plug( plug(
OpenApiSpex.Plug.PutApiSpec, OpenApiSpex.Plug.PutApiSpec,
[module: Pleroma.Web.ApiSpec] when action == :confirmation_resend [module: Pleroma.Web.ApiSpec] when action == :confirmation_resend

View File

@ -9,6 +9,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotController do
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.Plugs.OAuthScopesPlug
plug(Majic.Plug, [pool: Pleroma.MajicPool] when action in [:update])
plug(Pleroma.Web.ApiSpec.CastAndValidate) plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(OAuthScopesPlug, %{scopes: ["read:accounts"]} when action == :show) plug(OAuthScopesPlug, %{scopes: ["read:accounts"]} when action == :show)
plug(OAuthScopesPlug, %{scopes: ["write:accounts"]} when action != :show) plug(OAuthScopesPlug, %{scopes: ["write:accounts"]} when action != :show)
@ -22,14 +23,15 @@ def show(%{assigns: %{user: user}} = conn, _params) do
@doc "PUT /api/v1/pleroma/mascot" @doc "PUT /api/v1/pleroma/mascot"
def update(%{assigns: %{user: user}, body_params: %{file: file}} = conn, _) do def update(%{assigns: %{user: user}, body_params: %{file: file}} = conn, _) do
with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)), with {:content_type, "image" <> _} <- {:content_type, file.content_type},
# Reject if not an image {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)) do
%{type: "image"} = attachment <- render_attachment(object) do attachment = render_attachment(object)
{:ok, _user} = User.mascot_update(user, attachment) {:ok, _user} = User.mascot_update(user, attachment)
json(conn, attachment) json(conn, attachment)
else else
%{type: _} -> render_error(conn, :unsupported_media_type, "mascots can only be images") {:content_type, _} ->
render_error(conn, :unsupported_media_type, "mascots can only be images")
end end
end end

View File

@ -228,7 +228,7 @@
<body> <body>
<div class="container"> <div class="container">
<h1><%= Pleroma.Config.get([:instance, :name]) %></h1> <h1><%= Pleroma.Config.get([:instance, :name]) %></h1>
<%= render @view_module, @view_template, assigns %> <%= @inner_content %>
</div> </div>
</body> </body>
</html> </html>

View File

@ -181,7 +181,7 @@
</div> </div>
</div> </div>
<% end %> <% end %>
<%= render @view_module, @view_template, assigns %> <%= @inner_content %>
</td> </td>
</tr> </tr>

View File

@ -10,7 +10,7 @@ video, audio {
} }
</style> </style>
<%= render @view_module, @view_template, assigns %> <%= @inner_content %>
</body> </body>
</html> </html>

View File

@ -9,7 +9,7 @@
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<%= render @view_module, @view_template, assigns %> <%= @inner_content %>
</div> </div>
</body> </body>
</html> </html>

15
mix.exs
View File

@ -114,10 +114,10 @@ defp oauth_deps do
# Type `mix help deps` for examples and options. # Type `mix help deps` for examples and options.
defp deps do defp deps do
[ [
{:phoenix, "~> 1.4.17"}, {:phoenix, "~> 1.5.5"},
{:tzdata, "~> 1.0.3"}, {:tzdata, "~> 1.0.3"},
{:plug_cowboy, "~> 2.3"}, {:plug_cowboy, "~> 2.3"},
{:phoenix_pubsub, "~> 1.1"}, {:phoenix_pubsub, "~> 2.0"},
{:phoenix_ecto, "~> 4.0"}, {:phoenix_ecto, "~> 4.0"},
{:ecto_enum, "~> 1.4"}, {:ecto_enum, "~> 1.4"},
{:ecto_sql, "~> 3.4.4"}, {:ecto_sql, "~> 3.4.4"},
@ -165,9 +165,16 @@ defp deps do
{:telemetry, "~> 0.3"}, {:telemetry, "~> 0.3"},
{:poolboy, "~> 1.5"}, {:poolboy, "~> 1.5"},
{:prometheus, "~> 4.6"}, {:prometheus, "~> 4.6"},
{:prometheus_ex, "~> 3.0"}, {:prometheus_ex,
git: "https://git.pleroma.social/pleroma/elixir-libraries/prometheus.ex.git",
ref: "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5",
override: true},
{:prometheus_plugs, "~> 1.1"}, {:prometheus_plugs, "~> 1.1"},
{:prometheus_phoenix, "~> 1.3"}, {:prometheus_phoenix, "~> 1.3"},
# Note: once `prometheus_phx` is integrated into `prometheus_phoenix`, remove the former:
{:prometheus_phx,
git: "https://git.pleroma.social/pleroma/elixir-libraries/prometheus-phx.git",
branch: "no-logging"},
{:prometheus_ecto, "~> 1.4"}, {:prometheus_ecto, "~> 1.4"},
{:recon, "~> 2.5"}, {:recon, "~> 2.5"},
{:quack, "~> 0.1.1"}, {:quack, "~> 0.1.1"},
@ -188,6 +195,8 @@ defp deps do
git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git",
ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"}, ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"},
{:restarter, path: "./restarter"}, {:restarter, path: "./restarter"},
{:majic,
git: "https://git.pleroma.social/pleroma/elixir-libraries/majic", branch: "develop"},
{:open_api_spex, {:open_api_spex,
git: "https://git.pleroma.social/pleroma/elixir-libraries/open_api_spex.git", git: "https://git.pleroma.social/pleroma/elixir-libraries/open_api_spex.git",
ref: "f296ac0924ba3cf79c7a588c4c252889df4c2edd"}, ref: "f296ac0924ba3cf79c7a588c4c252889df4c2edd"},

View File

@ -18,8 +18,9 @@
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"},
"cors_plug": {:hex, :cors_plug, "2.0.2", "2b46083af45e4bc79632bd951550509395935d3e7973275b2b743bd63cc942ce", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f0d0e13f71c51fd4ef8b2c7e051388e4dfb267522a83a22392c856de7e46465f"}, "cors_plug": {:hex, :cors_plug, "2.0.2", "2b46083af45e4bc79632bd951550509395935d3e7973275b2b743bd63cc942ce", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f0d0e13f71c51fd4ef8b2c7e051388e4dfb267522a83a22392c856de7e46465f"},
"cowboy": {:hex, :cowboy, "2.8.0", "f3dc62e35797ecd9ac1b50db74611193c29815401e53bac9a5c0577bd7bc667d", [:rebar3], [{:cowlib, "~> 2.9.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "4643e4fba74ac96d4d152c75803de6fad0b3fa5df354c71afdd6cbeeb15fac8a"}, "cowboy": {:hex, :cowboy, "2.8.0", "f3dc62e35797ecd9ac1b50db74611193c29815401e53bac9a5c0577bd7bc667d", [:rebar3], [{:cowlib, "~> 2.9.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "4643e4fba74ac96d4d152c75803de6fad0b3fa5df354c71afdd6cbeeb15fac8a"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.0", "69fdb5cf92df6373e15675eb4018cf629f5d8e35e74841bb637d6596cb797bbc", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "42868c229d9a2900a1501c5d0355bfd46e24c862c322b0b4f5a6f14fe0216753"},
"cowlib": {:hex, :cowlib, "2.9.1", "61a6c7c50cf07fdd24b2f45b89500bb93b6686579b069a89f88cb211e1125c78", [:rebar3], [], "hexpm", "e4175dc240a70d996156160891e1c62238ede1729e45740bdd38064dad476170"}, "cowlib": {:hex, :cowlib, "2.9.1", "61a6c7c50cf07fdd24b2f45b89500bb93b6686579b069a89f88cb211e1125c78", [:rebar3], [], "hexpm", "e4175dc240a70d996156160891e1c62238ede1729e45740bdd38064dad476170"},
"credo": {:hex, :credo, "1.4.0", "92339d4cbadd1e88b5ee43d427b639b68a11071b6f73854e33638e30a0ea11f5", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1fd3b70dce216574ce3c18bdf510b57e7c4c85c2ec9cad4bff854abaf7e58658"}, "credo": {:hex, :credo, "1.4.1", "16392f1edd2cdb1de9fe4004f5ab0ae612c92e230433968eab00aafd976282fc", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "155f8a2989ad77504de5d8291fa0d41320fdcaa6a1030472e9967f285f8c7692"},
"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", "f63a705f92c26955977ee62a313012e309a4d77a", [ref: "f63a705f92c26955977ee62a313012e309a4d77a"]}, "crypt": {:git, "https://github.com/msantos/crypt.git", "f63a705f92c26955977ee62a313012e309a4d77a", [ref: "f63a705f92c26955977ee62a313012e309a4d77a"]},
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"}, "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
@ -32,7 +33,7 @@
"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_sql": {:hex, :ecto_sql, "3.4.5", "30161f81b167d561a9a2df4329c10ae05ff36eca7ccc84628f2c8b9fa1e43323", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "31990c6a3579b36a3c0841d34a94c275e727de8b84f58509da5f1b2032c98ac2"}, "ecto_sql": {:hex, :ecto_sql, "3.4.5", "30161f81b167d561a9a2df4329c10ae05ff36eca7ccc84628f2c8b9fa1e43323", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "31990c6a3579b36a3c0841d34a94c275e727de8b84f58509da5f1b2032c98ac2"},
"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.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"}, "elixir_make": {:hex, :elixir_make, "0.6.1", "8faa29a5597faba999aeeb72bbb9c91694ef8068f0131192fb199f98d32994ef", [:mix], [], "hexpm", "35d33270680f8d839a4003c3e9f43afb595310a592405a00afc12de4c7f55a18"},
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"}, "esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
"eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"}, "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"},
"ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"}, "ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},
@ -65,6 +66,7 @@
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"}, "jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
"libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"}, "libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"},
"linkify": {:hex, :linkify, "0.2.0", "2518bbbea21d2caa9d372424e1ad845b640c6630e2d016f1bd1f518f9ebcca28", [:mix], [], "hexpm", "b8ca8a68b79e30b7938d6c996085f3db14939f29538a59ca5101988bb7f917f6"}, "linkify": {:hex, :linkify, "0.2.0", "2518bbbea21d2caa9d372424e1ad845b640c6630e2d016f1bd1f518f9ebcca28", [:mix], [], "hexpm", "b8ca8a68b79e30b7938d6c996085f3db14939f29538a59ca5101988bb7f917f6"},
"majic": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/majic", "4c692e544b28d1f5e543fb8a44be090f8cd96f80", [branch: "develop"]},
"makeup": {:hex, :makeup, "1.0.3", "e339e2f766d12e7260e6672dd4047405963c5ec99661abdc432e6ec67d29ef95", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "2e9b4996d11832947731f7608fed7ad2f9443011b3b479ae288011265cdd3dad"}, "makeup": {:hex, :makeup, "1.0.3", "e339e2f766d12e7260e6672dd4047405963c5ec99661abdc432e6ec67d29ef95", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "2e9b4996d11832947731f7608fed7ad2f9443011b3b479ae288011265cdd3dad"},
"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"},
"meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm", "d34f013c156db51ad57cc556891b9720e6a1c1df5fe2e15af999c84d6cebeb1a"}, "meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm", "d34f013c156db51ad57cc556891b9720e6a1c1df5fe2e15af999c84d6cebeb1a"},
@ -84,14 +86,14 @@
"p1_utils": {:hex, :p1_utils, "1.0.18", "3fe224de5b2e190d730a3c5da9d6e8540c96484cf4b4692921d1e28f0c32b01c", [:rebar3], [], "hexpm", "1fc8773a71a15553b179c986b22fbeead19b28fe486c332d4929700ffeb71f88"}, "p1_utils": {:hex, :p1_utils, "1.0.18", "3fe224de5b2e190d730a3c5da9d6e8540c96484cf4b4692921d1e28f0c32b01c", [:rebar3], [], "hexpm", "1fc8773a71a15553b179c986b22fbeead19b28fe486c332d4929700ffeb71f88"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "1.2.1", "9cbe354b58121075bd20eb83076900a3832324b7dd171a6895fab57b6bb2752c", [:mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}], "hexpm", "d3b40a4a4630f0b442f19eca891fcfeeee4c40871936fed2f68e1c4faa30481f"}, "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "1.2.1", "9cbe354b58121075bd20eb83076900a3832324b7dd171a6895fab57b6bb2752c", [:mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}], "hexpm", "d3b40a4a4630f0b442f19eca891fcfeeee4c40871936fed2f68e1c4faa30481f"},
"phoenix": {:hex, :phoenix, "1.4.17", "1b1bd4cff7cfc87c94deaa7d60dd8c22e04368ab95499483c50640ef3bd838d8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a8e5d7a3d76d452bb5fb86e8b7bd115f737e4f8efe202a463d4aeb4a5809611"}, "phoenix": {:hex, :phoenix, "1.5.6", "8298cdb4e0f943242ba8410780a6a69cbbe972fef199b341a36898dd751bdd66", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0dc4d39af1306b6aa5122729b0a95ca779e42c708c6fe7abbb3d336d5379e956"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "c5e666a341ff104d0399d8f0e4ff094559b2fde13a5985d4cb5023b2c2ac558b"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.2.1", "13f124cf0a3ce0f1948cf24654c7b9f2347169ff75c1123f44674afee6af3b03", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 2.15", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "478a1bae899cac0a6e02be1deec7e2944b7754c04e7d4107fc5a517f877743c0"},
"phoenix_html": {:hex, :phoenix_html, "2.14.2", "b8a3899a72050f3f48a36430da507dd99caf0ac2d06c77529b1646964f3d563e", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "58061c8dfd25da5df1ea0ca47c972f161beb6c875cd293917045b92ffe1bf617"}, "phoenix_html": {:hex, :phoenix_html, "2.14.2", "b8a3899a72050f3f48a36430da507dd99caf0ac2d06c77529b1646964f3d563e", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "58061c8dfd25da5df1ea0ca47c972f161beb6c875cd293917045b92ffe1bf617"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm", "1f13f9f0f3e769a667a6b6828d29dec37497a082d195cc52dbef401a9b69bf38"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
"phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.0", "2acfa0db038a7649e0a4614eee970e6ed9a39d191ccd79a03583b51d0da98165", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "b8bbae4b59a676de6b8bd8675eda37bc8b4424812ae429d6fdcb2b039e00003b"}, "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.3.2", "43d3518349a22b8b1910ea28b4dd5119926d5017b3187db3fbd1a1e05769a851", [:mix], [{:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.0", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "3e2ac4e883db7af0702d75ba00c19901760e8342b91f8f66e13941de552e777f"},
"plug": {:hex, :plug, "1.10.4", "41eba7d1a2d671faaf531fa867645bd5a3dce0957d8e2a3f398ccff7d2ef017f", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad1e233fe73d2eec56616568d260777b67f53148a999dc2d048f4eb9778fe4a0"}, "plug": {:hex, :plug, "1.10.4", "41eba7d1a2d671faaf531fa867645bd5a3dce0957d8e2a3f398ccff7d2ef017f", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad1e233fe73d2eec56616568d260777b67f53148a999dc2d048f4eb9778fe4a0"},
"plug_cowboy": {:hex, :plug_cowboy, "2.3.0", "149a50e05cb73c12aad6506a371cd75750c0b19a32f81866e1a323dda9e0e99d", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bc595a1870cef13f9c1e03df56d96804db7f702175e4ccacdb8fc75c02a7b97e"}, "plug_cowboy": {:hex, :plug_cowboy, "2.4.0", "e936ef151751f386804c51f87f7300f5aaae6893cdad726559c3930c6c032948", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e25ddcfc06b1b76e55af79d078b03cbc86bbcb99ce4e5e0a5e4a8114ee039be6"},
"plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"}, "plug_crypto": {:hex, :plug_crypto, "1.2.0", "1cb20793aa63a6c619dd18bb33d7a3aa94818e5fd39ad357051a67f26dfa2df6", [:mix], [], "hexpm", "a48b538ae8bf381ffac344520755f3007cc10bd8e90b240af98ea29b69683fc2"},
"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"},
@ -99,8 +101,9 @@
"pot": {:hex, :pot, "0.11.0", "61bad869a94534739dd4614a25a619bc5c47b9970e9a0ea5bef4628036fc7a16", [:rebar3], [], "hexpm", "57ee6ee6bdeb639661ffafb9acefe3c8f966e45394de6a766813bb9e1be4e54b"}, "pot": {:hex, :pot, "0.11.0", "61bad869a94534739dd4614a25a619bc5c47b9970e9a0ea5bef4628036fc7a16", [:rebar3], [], "hexpm", "57ee6ee6bdeb639661ffafb9acefe3c8f966e45394de6a766813bb9e1be4e54b"},
"prometheus": {:hex, :prometheus, "4.6.0", "20510f381db1ccab818b4cf2fac5fa6ab5cc91bc364a154399901c001465f46f", [:mix, :rebar3], [], "hexpm", "4905fd2992f8038eccd7aa0cd22f40637ed618c0bed1f75c05aacec15b7545de"}, "prometheus": {:hex, :prometheus, "4.6.0", "20510f381db1ccab818b4cf2fac5fa6ab5cc91bc364a154399901c001465f46f", [:mix, :rebar3], [], "hexpm", "4905fd2992f8038eccd7aa0cd22f40637ed618c0bed1f75c05aacec15b7545de"},
"prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"}, "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"},
"prometheus_ex": {:hex, :prometheus_ex, "3.0.5", "fa58cfd983487fc5ead331e9a3e0aa622c67232b3ec71710ced122c4c453a02f", [:mix], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm", "9fd13404a48437e044b288b41f76e64acd9735fb8b0e3809f494811dfa66d0fb"}, "prometheus_ex": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus.ex.git", "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5", [ref: "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5"]},
"prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "c4d1404ac4e9d3d963da601db2a7d8ea31194f0017057fabf0cfb9bf5a6c8c75"}, "prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "c4d1404ac4e9d3d963da601db2a7d8ea31194f0017057fabf0cfb9bf5a6c8c75"},
"prometheus_phx": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus-phx.git", "9cd8f248c9381ffedc799905050abce194a97514", [branch: "no-logging"]},
"prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"}, "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"},
"quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "d736bfa7444112eb840027bb887832a0e403a4a3437f48028c3b29a2dbbd2543"}, "quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "d736bfa7444112eb840027bb887832a0e403a4a3437f48028c3b29a2dbbd2543"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
@ -109,13 +112,13 @@
"sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"}, "sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"},
"sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm", "2e1ec458f892ffa81f9f8386e3f35a1af6db7a7a37748a64478f13163a1f3573"}, "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm", "2e1ec458f892ffa81f9f8386e3f35a1af6db7a7a37748a64478f13163a1f3573"},
"swoosh": {:hex, :swoosh, "1.0.0", "c547cfc83f30e12d5d1fdcb623d7de2c2e29a5becfc68bf8f42ba4d23d2c2756", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [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", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "b3b08e463f876cb6167f7168e9ad99a069a724e124bcee61847e0e1ed13f4a0d"}, "swoosh": {:hex, :swoosh, "1.0.6", "6765e334c67dacabe721f0d701c7e5a6f06e4595c90df6f91e73ebd54d555833", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, 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", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "7c50ef78e4acfd1cbd4907dc1fa87b5540675a6be9dc979d04890f49d7ec1830"},
"syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"}, "syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
"telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"}, "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
"tesla": {:git, "https://github.com/teamon/tesla/", "9f7261ca49f9f901ceb73b60219ad6f8a9f6aa30", [ref: "9f7261ca49f9f901ceb73b60219ad6f8a9f6aa30"]}, "tesla": {:git, "https://github.com/teamon/tesla/", "9f7261ca49f9f901ceb73b60219ad6f8a9f6aa30", [ref: "9f7261ca49f9f901ceb73b60219ad6f8a9f6aa30"]},
"timex": {:hex, :timex, "3.6.2", "845cdeb6119e2fef10751c0b247b6c59d86d78554c83f78db612e3290f819bc2", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "26030b46199d02a590be61c2394b37ea25a3664c02fafbeca0b24c972025d47a"}, "timex": {:hex, :timex, "3.6.2", "845cdeb6119e2fef10751c0b247b6c59d86d78554c83f78db612e3290f819bc2", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "26030b46199d02a590be61c2394b37ea25a3664c02fafbeca0b24c972025d47a"},
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"}, "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
"tzdata": {:hex, :tzdata, "1.0.3", "73470ad29dde46e350c60a66e6b360d3b99d2d18b74c4c349dbebbc27a09a3eb", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a6e1ee7003c4d04ecbd21dd3ec690d4c6662db5d3bbdd7262d53cdf5e7c746c1"}, "tzdata": {:hex, :tzdata, "1.0.4", "a3baa4709ea8dba552dca165af6ae97c624a2d6ac14bd265165eaa8e8af94af6", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "b02637db3df1fd66dd2d3c4f194a81633d0e4b44308d36c1b2fdfd1e4e6f169b"},
"ueberauth": {:hex, :ueberauth, "0.6.3", "d42ace28b870e8072cf30e32e385579c57b9cc96ec74fa1f30f30da9c14f3cc0", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "afc293d8a1140d6591b53e3eaf415ca92842cb1d32fad3c450c6f045f7f91b60"}, "ueberauth": {:hex, :ueberauth, "0.6.3", "d42ace28b870e8072cf30e32e385579c57b9cc96ec74fa1f30f30da9c14f3cc0", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "afc293d8a1140d6591b53e3eaf415ca92842cb1d32fad3c450c6f045f7f91b60"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"},
"unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"}, "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"},

View File

@ -3,8 +3,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-20 13:18+0000\n" "POT-Creation-Date: 2020-09-20 13:18+0000\n"
"PO-Revision-Date: 2020-09-20 14:48+0000\n" "PO-Revision-Date: 2020-10-22 18:25+0000\n"
"Last-Translator: Kana <gudzpoz@live.com>\n" "Last-Translator: shironeko <shironeko@tesaguri.club>\n"
"Language-Team: Chinese (Simplified) <https://translate.pleroma.social/" "Language-Team: Chinese (Simplified) <https://translate.pleroma.social/"
"projects/pleroma/pleroma/zh_Hans/>\n" "projects/pleroma/pleroma/zh_Hans/>\n"
"Language: zh_Hans\n" "Language: zh_Hans\n"
@ -49,7 +49,7 @@ msgstr "是被保留的"
## From Ecto.Changeset.validate_confirmation/3 ## From Ecto.Changeset.validate_confirmation/3
msgid "does not match confirmation" msgid "does not match confirmation"
msgstr "" msgstr "与验证不符"
## From Ecto.Changeset.no_assoc_constraint/3 ## From Ecto.Changeset.no_assoc_constraint/3
msgid "is still associated with this entry" msgid "is still associated with this entry"
@ -138,12 +138,12 @@ msgstr "不能获取收藏"
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:438 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:438
#, elixir-format #, elixir-format
msgid "Can't like object" msgid "Can't like object"
msgstr "" msgstr "不能喜欢对象"
#: lib/pleroma/web/common_api/utils.ex:563 #: lib/pleroma/web/common_api/utils.ex:563
#, elixir-format #, elixir-format
msgid "Cannot post an empty status without attachments" msgid "Cannot post an empty status without attachments"
msgstr "" msgstr "无法发送空白且不包含附件的状态"
#: lib/pleroma/web/common_api/utils.ex:511 #: lib/pleroma/web/common_api/utils.ex:511
#, elixir-format #, elixir-format
@ -153,100 +153,100 @@ msgstr ""
#: lib/pleroma/config/config_db.ex:191 #: lib/pleroma/config/config_db.ex:191
#, elixir-format #, elixir-format
msgid "Config with params %{params} not found" msgid "Config with params %{params} not found"
msgstr "" msgstr "无法找到包含参数 %{params} 的配置"
#: lib/pleroma/web/common_api/common_api.ex:181 #: lib/pleroma/web/common_api/common_api.ex:181
#: lib/pleroma/web/common_api/common_api.ex:185 #: lib/pleroma/web/common_api/common_api.ex:185
#, elixir-format #, elixir-format
msgid "Could not delete" msgid "Could not delete"
msgstr "" msgstr "无法删除"
#: lib/pleroma/web/common_api/common_api.ex:231 #: lib/pleroma/web/common_api/common_api.ex:231
#, elixir-format #, elixir-format
msgid "Could not favorite" msgid "Could not favorite"
msgstr "" msgstr "无法收藏"
#: lib/pleroma/web/common_api/common_api.ex:453 #: lib/pleroma/web/common_api/common_api.ex:453
#, elixir-format #, elixir-format
msgid "Could not pin" msgid "Could not pin"
msgstr "" msgstr "无法置顶"
#: lib/pleroma/web/common_api/common_api.ex:278 #: lib/pleroma/web/common_api/common_api.ex:278
#, elixir-format #, elixir-format
msgid "Could not unfavorite" msgid "Could not unfavorite"
msgstr "" msgstr "无法取消收藏"
#: lib/pleroma/web/common_api/common_api.ex:463 #: lib/pleroma/web/common_api/common_api.ex:463
#, elixir-format #, elixir-format
msgid "Could not unpin" msgid "Could not unpin"
msgstr "" msgstr "无法取消置顶"
#: lib/pleroma/web/common_api/common_api.ex:216 #: lib/pleroma/web/common_api/common_api.ex:216
#, elixir-format #, elixir-format
msgid "Could not unrepeat" msgid "Could not unrepeat"
msgstr "" msgstr "无法取消转发"
#: lib/pleroma/web/common_api/common_api.ex:512 #: lib/pleroma/web/common_api/common_api.ex:512
#: lib/pleroma/web/common_api/common_api.ex:521 #: lib/pleroma/web/common_api/common_api.ex:521
#, elixir-format #, elixir-format
msgid "Could not update state" msgid "Could not update state"
msgstr "" msgstr "无法更新状态"
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:207 #: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:207
#, elixir-format #, elixir-format
msgid "Error." msgid "Error."
msgstr "" msgstr "错误。"
#: lib/pleroma/web/twitter_api/twitter_api.ex:106 #: lib/pleroma/web/twitter_api/twitter_api.ex:106
#, elixir-format #, elixir-format
msgid "Invalid CAPTCHA" msgid "Invalid CAPTCHA"
msgstr "" msgstr "无效的验证码"
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:116 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:116
#: lib/pleroma/web/oauth/oauth_controller.ex:568 #: lib/pleroma/web/oauth/oauth_controller.ex:568
#, elixir-format #, elixir-format
msgid "Invalid credentials" msgid "Invalid credentials"
msgstr "" msgstr "无效的凭据"
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38 #: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
#, elixir-format #, elixir-format
msgid "Invalid credentials." msgid "Invalid credentials."
msgstr "" msgstr "无效的凭据。"
#: lib/pleroma/web/common_api/common_api.ex:355 #: lib/pleroma/web/common_api/common_api.ex:355
#, elixir-format #, elixir-format
msgid "Invalid indices" msgid "Invalid indices"
msgstr "" msgstr "无效的索引"
#: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:29 #: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:29
#, elixir-format #, elixir-format
msgid "Invalid parameters" msgid "Invalid parameters"
msgstr "" msgstr "无效的参数"
#: lib/pleroma/web/common_api/utils.ex:414 #: lib/pleroma/web/common_api/utils.ex:414
#, elixir-format #, elixir-format
msgid "Invalid password." msgid "Invalid password."
msgstr "" msgstr "无效的密码。"
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:220 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:220
#, elixir-format #, elixir-format
msgid "Invalid request" msgid "Invalid request"
msgstr "" msgstr "无效的请求"
#: lib/pleroma/web/twitter_api/twitter_api.ex:109 #: lib/pleroma/web/twitter_api/twitter_api.ex:109
#, elixir-format #, elixir-format
msgid "Kocaptcha service unavailable" msgid "Kocaptcha service unavailable"
msgstr "" msgstr "Kocaptcha 服务不可用"
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:112 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:112
#, elixir-format #, elixir-format
msgid "Missing parameters" msgid "Missing parameters"
msgstr "" msgstr "缺少参数"
#: lib/pleroma/web/common_api/utils.ex:547 #: lib/pleroma/web/common_api/utils.ex:547
#, elixir-format #, elixir-format
msgid "No such conversation" msgid "No such conversation"
msgstr "" msgstr "没有该对话"
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:388 #: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:388
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:414 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:456 #: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:414 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:456

View File

@ -0,0 +1,15 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Repo.Migrations.RefactorLockedUserField do
use Ecto.Migration
def up do
execute("ALTER TABLE users RENAME COLUMN locked TO is_locked;")
end
def down do
execute("ALTER TABLE users RENAME COLUMN is_locked TO locked;")
end
end

View File

@ -0,0 +1,15 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Repo.Migrations.RefactorDiscoverableUserField do
use Ecto.Migration
def up do
execute("ALTER TABLE users RENAME COLUMN discoverable TO is_discoverable;")
end
def down do
execute("ALTER TABLE users RENAME COLUMN is_discoverable TO discoverable;")
end
end

View File

@ -0,0 +1,68 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"Emoji": "toot:Emoji",
"Hashtag": "as:Hashtag",
"atomUri": "ostatus:atomUri",
"conversation": "ostatus:conversation",
"inReplyToAtomUri": "ostatus:inReplyToAtomUri",
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"movedTo": "as:movedTo",
"ostatus": "http://ostatus.org#",
"toot": "http://joinmastodon.org/ns#"
}
],
"actor": "http://mastodon.example.org/users/admin",
"cc": [
"http://mastodon.example.org/users/admin/followers",
"http://localtesting.pleroma.lol/users/lain"
],
"id": "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity",
"nickname": "lain",
"object": {
"atomUri": "http://mastodon.example.org/users/admin/statuses/99512778738411822",
"attachment": [],
"attributedTo": "http://mastodon.example.org/users/admin",
"cc": [
"http://mastodon.example.org/users/admin/followers",
"http://localtesting.pleroma.lol/users/lain"
],
"content": "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span> #moo</p>",
"conversation": "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation",
"id": "http://mastodon.example.org/users/admin/statuses/99512778738411822",
"inReplyTo": null,
"inReplyToAtomUri": null,
"published": "2018-02-12T14:08:20Z",
"summary": "cw",
"tag": [
{
"href": "http://localtesting.pleroma.lol/users/lain",
"name": "@lain@localtesting.pleroma.lol",
"type": "Mention"
},
{
"href": "http://mastodon.example.org/tags/nsfw",
"name": "#NSFW",
"type": "Hashtag"
}
],
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"type": "Note",
"url": "http://mastodon.example.org/@admin/99512778738411822"
},
"published": "2018-02-12T14:08:20Z",
"signature": {
"created": "2018-02-12T14:08:20Z",
"creator": "http://mastodon.example.org/users/admin#main-key",
"signatureValue": "rnNfcopkc6+Ju73P806popcfwrK9wGYHaJVG1/ZvrlEbWVDzaHjkXqj9Q3/xju5l8CSn9tvSgCCtPFqZsFQwn/pFIFUcw7ZWB2xi4bDm3NZ3S4XQ8JRaaX7og5hFxAhWkGhJhAkfxVnOg2hG+w2d/7d7vRVSC1vo5ip4erUaA/PkWusZvPIpxnRWoXaxJsFmVx0gJgjpJkYDyjaXUlp+jmaoseeZ4EPQUWqHLKJ59PRG0mg8j2xAjYH9nQaN14qMRmTGPxY8gfv/CUFcatA+8VJU9KEsJkDAwLVvglydNTLGrxpAJU78a2eaht0foV43XUIZGe3DKiJPgE+UOKGCJw==",
"type": "RsaSignature2017"
},
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"type": "Create"
}

View File

@ -5,6 +5,8 @@
defmodule Mix.Tasks.Pleroma.InstanceTest do defmodule Mix.Tasks.Pleroma.InstanceTest do
use ExUnit.Case use ExUnit.Case
@release_env_file "./test/pleroma.test.env"
setup do setup do
File.mkdir_p!(tmp_path()) File.mkdir_p!(tmp_path())
@ -16,6 +18,8 @@ defmodule Mix.Tasks.Pleroma.InstanceTest do
File.rm_rf(Path.join(static_dir, "robots.txt")) File.rm_rf(Path.join(static_dir, "robots.txt"))
end end
if File.exists?(@release_env_file), do: File.rm_rf(@release_env_file)
Pleroma.Config.put([:instance, :static_dir], static_dir) Pleroma.Config.put([:instance, :static_dir], static_dir)
end) end)
@ -69,7 +73,9 @@ test "running gen" do
"--dedupe-uploads", "--dedupe-uploads",
"n", "n",
"--anonymize-uploads", "--anonymize-uploads",
"n" "n",
"--release-env-file",
@release_env_file
]) ])
end end
@ -91,6 +97,9 @@ test "running gen" do
assert generated_config =~ "filters: [Pleroma.Upload.Filter.ExifTool]" assert generated_config =~ "filters: [Pleroma.Upload.Filter.ExifTool]"
assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql() assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql()
assert File.exists?(Path.expand("./test/instance/static/robots.txt")) assert File.exists?(Path.expand("./test/instance/static/robots.txt"))
assert File.exists?(@release_env_file)
assert File.read!(@release_env_file) =~ ~r/^RELEASE_COOKIE=.*/
end end
defp generated_setup_psql do defp generated_setup_psql do

View File

@ -0,0 +1,30 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.ReleaseEnvTest do
use ExUnit.Case
import ExUnit.CaptureIO, only: [capture_io: 1]
@path "config/pleroma.test.env"
def do_clean do
if File.exists?(@path) do
File.rm_rf(@path)
end
end
setup do
do_clean()
on_exit(fn -> do_clean() end)
:ok
end
test "generate pleroma.env" do
assert capture_io(fn ->
Mix.Tasks.Pleroma.ReleaseEnv.run(["gen", "--path", @path, "--force"])
end) =~ "The file generated"
assert File.read!(@path) =~ "RELEASE_COOKIE="
end
end

View File

@ -248,14 +248,19 @@ test "All statuses set" do
user = User.get_cached_by_nickname(user.nickname) user = User.get_cached_by_nickname(user.nickname)
assert user.is_moderator assert user.is_moderator
assert user.locked assert user.is_locked
assert user.is_admin assert user.is_admin
refute user.confirmation_pending refute user.confirmation_pending
end end
test "All statuses unset" do test "All statuses unset" do
user = user =
insert(:user, locked: true, is_moderator: true, is_admin: true, confirmation_pending: true) insert(:user,
is_locked: true,
is_moderator: true,
is_admin: true,
confirmation_pending: true
)
Mix.Tasks.Pleroma.User.run([ Mix.Tasks.Pleroma.User.run([
"set", "set",
@ -280,7 +285,7 @@ test "All statuses unset" do
user = User.get_cached_by_nickname(user.nickname) user = User.get_cached_by_nickname(user.nickname)
refute user.is_moderator refute user.is_moderator
refute user.locked refute user.is_locked
refute user.is_admin refute user.is_admin
assert user.confirmation_pending assert user.confirmation_pending
end end

View File

@ -346,7 +346,7 @@ test "it creates notifications when someone likes user's status with a filtered
describe "follow / follow_request notifications" do describe "follow / follow_request notifications" do
test "it creates `follow` notification for approved Follow activity" do test "it creates `follow` notification for approved Follow activity" do
user = insert(:user) user = insert(:user)
followed_user = insert(:user, locked: false) followed_user = insert(:user, is_locked: false)
{:ok, _, _, _activity} = CommonAPI.follow(user, followed_user) {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
assert FollowingRelationship.following?(user, followed_user) assert FollowingRelationship.following?(user, followed_user)
@ -361,7 +361,7 @@ test "it creates `follow` notification for approved Follow activity" do
test "it creates `follow_request` notification for pending Follow activity" do test "it creates `follow_request` notification for pending Follow activity" do
user = insert(:user) user = insert(:user)
followed_user = insert(:user, locked: true) followed_user = insert(:user, is_locked: true)
{:ok, _, _, _activity} = CommonAPI.follow(user, followed_user) {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
refute FollowingRelationship.following?(user, followed_user) refute FollowingRelationship.following?(user, followed_user)
@ -383,7 +383,7 @@ test "it creates `follow_request` notification for pending Follow activity" do
test "it doesn't create a notification for follow-unfollow-follow chains" do test "it doesn't create a notification for follow-unfollow-follow chains" do
user = insert(:user) user = insert(:user)
followed_user = insert(:user, locked: false) followed_user = insert(:user, is_locked: false)
{:ok, _, _, _activity} = CommonAPI.follow(user, followed_user) {:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
assert FollowingRelationship.following?(user, followed_user) assert FollowingRelationship.following?(user, followed_user)
@ -397,10 +397,10 @@ test "it doesn't create a notification for follow-unfollow-follow chains" do
end end
test "dismisses the notification on follow request rejection" do test "dismisses the notification on follow request rejection" do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
follower = insert(:user) follower = insert(:user)
{:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user) {:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
assert [notification] = Notification.for_user(user) assert [_notification] = Notification.for_user(user)
{:ok, _follower} = CommonAPI.reject_follow_request(follower, user) {:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
assert [] = Notification.for_user(user) assert [] = Notification.for_user(user)
end end

View File

@ -82,7 +82,7 @@ test "Disabled via config" do
Pleroma.Config.put([:instance, :cleanup_attachments], false) Pleroma.Config.put([:instance, :cleanup_attachments], false)
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -116,7 +116,7 @@ test "in subdirectories" do
Pleroma.Config.put([:instance, :cleanup_attachments], true) Pleroma.Config.put([:instance, :cleanup_attachments], true)
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -155,7 +155,7 @@ test "with dedupe enabled" do
File.mkdir_p!(uploads_dir) File.mkdir_p!(uploads_dir)
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -188,7 +188,7 @@ test "with objects that have legacy data.url attribute" do
Pleroma.Config.put([:instance, :cleanup_attachments], true) Pleroma.Config.put([:instance, :cleanup_attachments], true)
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -225,7 +225,7 @@ test "With custom base_url" do
Pleroma.Config.put([:instance, :cleanup_attachments], true) Pleroma.Config.put([:instance, :cleanup_attachments], true)
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }

View File

@ -13,7 +13,7 @@ defmodule Pleroma.Upload.Filter.AnonymizeFilenameTest do
upload_file = %Upload{ upload_file = %Upload{
name: "an… image.jpg", name: "an… image.jpg",
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg") path: Path.absname("test/fixtures/image_tmp.jpg")
} }

View File

@ -18,7 +18,7 @@ test "adds shasum" do
upload = %Upload{ upload = %Upload{
name: "an… image.jpg", name: "an… image.jpg",
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
tempfile: Path.absname("test/fixtures/image_tmp.jpg") tempfile: Path.absname("test/fixtures/image_tmp.jpg")
} }

View File

@ -16,7 +16,7 @@ test "apply exiftool filter" do
upload = %Pleroma.Upload{ upload = %Pleroma.Upload{
name: "image_with_GPS_data.jpg", name: "image_with_GPS_data.jpg",
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/DSCN0010.jpg"), path: Path.absname("test/fixtures/DSCN0010.jpg"),
tempfile: Path.absname("test/fixtures/DSCN0010_tmp.jpg") tempfile: Path.absname("test/fixtures/DSCN0010_tmp.jpg")
} }

View File

@ -17,7 +17,7 @@ test "apply mogrify filter" do
upload = %Upload{ upload = %Upload{
name: "an… image.jpg", name: "an… image.jpg",
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
tempfile: Path.absname("test/fixtures/image_tmp.jpg") tempfile: Path.absname("test/fixtures/image_tmp.jpg")
} }

View File

@ -18,7 +18,7 @@ test "apply mogrify filter" do
upload = %Pleroma.Upload{ upload = %Pleroma.Upload{
name: "an… image.jpg", name: "an… image.jpg",
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
tempfile: Path.absname("test/fixtures/image_tmp.jpg") tempfile: Path.absname("test/fixtures/image_tmp.jpg")
} }

View File

@ -20,7 +20,7 @@ test "applies filters" do
upload = %Pleroma.Upload{ upload = %Pleroma.Upload{
name: "an… image.jpg", name: "an… image.jpg",
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
tempfile: Path.absname("test/fixtures/image_tmp.jpg") tempfile: Path.absname("test/fixtures/image_tmp.jpg")
} }

View File

@ -11,7 +11,7 @@ defmodule Pleroma.UploadTest do
alias Pleroma.Uploaders.Uploader alias Pleroma.Uploaders.Uploader
@upload_file %Plug.Upload{ @upload_file %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "image.jpg" filename: "image.jpg"
} }
@ -112,7 +112,7 @@ test "does not allow descriptions longer than the post limit" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "image.jpg" filename: "image.jpg"
} }
@ -124,7 +124,7 @@ test "returns a media url" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "image.jpg" filename: "image.jpg"
} }
@ -140,7 +140,7 @@ test "copies the file to the configured folder with deduping" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "an [image.jpg" filename: "an [image.jpg"
} }
@ -156,7 +156,7 @@ test "copies the file to the configured folder without deduping" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "an [image.jpg" filename: "an [image.jpg"
} }
@ -165,63 +165,31 @@ test "copies the file to the configured folder without deduping" do
assert data["name"] == "an [image.jpg" assert data["name"] == "an [image.jpg"
end end
test "fixes incorrect content type" do test "fixes incorrect content type when base64 is given" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") params = %{
img: "data:image/png;base64,#{Base.encode64(File.read!("test/fixtures/image.jpg"))}"
file = %Plug.Upload{
content_type: "application/octet-stream",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "an [image.jpg"
} }
{:ok, data} = Upload.store(file, filters: [Pleroma.Upload.Filter.Dedupe]) {:ok, data} = Upload.store(params)
assert hd(data["url"])["mediaType"] == "image/jpeg" assert hd(data["url"])["mediaType"] == "image/jpeg"
end end
test "adds missing extension" do test "adds extension when base64 is given" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{ params = %{
content_type: "image/jpg", img: "data:image/png;base64,#{Base.encode64(File.read!("test/fixtures/image.jpg"))}"
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "an [image"
} }
{:ok, data} = Upload.store(file) {:ok, data} = Upload.store(params)
assert data["name"] == "an [image.jpg" assert String.ends_with?(data["name"], ".jpg")
end
test "fixes incorrect file extension" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
content_type: "image/jpg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "an [image.blah"
}
{:ok, data} = Upload.store(file)
assert data["name"] == "an [image.jpg"
end
test "don't modify filename of an unknown type" do
File.cp("test/fixtures/test.txt", "test/fixtures/test_tmp.txt")
file = %Plug.Upload{
content_type: "text/plain",
path: Path.absname("test/fixtures/test_tmp.txt"),
filename: "test.txt"
}
{:ok, data} = Upload.store(file)
assert data["name"] == "test.txt"
end end
test "copies the file to the configured folder with anonymizing filename" do test "copies the file to the configured folder with anonymizing filename" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "an [image.jpg" filename: "an [image.jpg"
} }
@ -235,7 +203,7 @@ test "escapes invalid characters in url" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "an… image.jpg" filename: "an… image.jpg"
} }
@ -250,7 +218,7 @@ test "escapes reserved uri characters" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: ":?#[]@!$&\\'()*+,;=.jpg" filename: ":?#[]@!$&\\'()*+,;=.jpg"
} }
@ -272,7 +240,7 @@ test "returns a media url with configured base_url" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg") File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"), path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "image.jpg" filename: "image.jpg"
} }

View File

@ -19,7 +19,7 @@ test "put file to local folder" do
file = %Pleroma.Upload{ file = %Pleroma.Upload{
name: "image.jpg", name: "image.jpg",
content_type: "image/jpg", content_type: "image/jpeg",
path: file_path, path: file_path,
tempfile: Path.absname("test/fixtures/image_tmp.jpg") tempfile: Path.absname("test/fixtures/image_tmp.jpg")
} }
@ -38,7 +38,7 @@ test "deletes local file" do
file = %Pleroma.Upload{ file = %Pleroma.Upload{
name: "image.jpg", name: "image.jpg",
content_type: "image/jpg", content_type: "image/jpeg",
path: file_path, path: file_path,
tempfile: Path.absname("test/fixtures/image_tmp.jpg") tempfile: Path.absname("test/fixtures/image_tmp.jpg")
} }

View File

@ -56,7 +56,7 @@ test "it returns path with bucket namespace when namespace is set" do
setup do setup do
file_upload = %Pleroma.Upload{ file_upload = %Pleroma.Upload{
name: "image-tet.jpg", name: "image-tet.jpg",
content_type: "image/jpg", content_type: "image/jpeg",
path: "test_folder/image-tet.jpg", path: "test_folder/image-tet.jpg",
tempfile: Path.absname("test/instance_static/add/shortcode.png") tempfile: Path.absname("test/instance_static/add/shortcode.png")
} }

View File

@ -66,7 +66,7 @@ test "excludes invisible users from results" do
end end
test "excludes users when discoverable is false" do test "excludes users when discoverable is false" do
insert(:user, %{nickname: "john 3000", discoverable: false}) insert(:user, %{nickname: "john 3000", is_discoverable: false})
insert(:user, %{nickname: "john 3001"}) insert(:user, %{nickname: "john 3001"})
users = User.search("john") users = User.search("john")

View File

@ -174,7 +174,7 @@ test "ap_following returns the following collection for the user" do
test "returns all pending follow requests" do test "returns all pending follow requests" do
unlocked = insert(:user) unlocked = insert(:user)
locked = insert(:user, locked: true) locked = insert(:user, is_locked: true)
follower = insert(:user) follower = insert(:user)
CommonAPI.follow(follower, unlocked) CommonAPI.follow(follower, unlocked)
@ -187,7 +187,7 @@ test "returns all pending follow requests" do
end end
test "doesn't return already accepted or duplicate follow requests" do test "doesn't return already accepted or duplicate follow requests" do
locked = insert(:user, locked: true) locked = insert(:user, is_locked: true)
pending_follower = insert(:user) pending_follower = insert(:user)
accepted_follower = insert(:user) accepted_follower = insert(:user)
@ -201,7 +201,7 @@ test "doesn't return already accepted or duplicate follow requests" do
end end
test "doesn't return follow requests for deactivated accounts" do test "doesn't return follow requests for deactivated accounts" do
locked = insert(:user, locked: true) locked = insert(:user, is_locked: true)
pending_follower = insert(:user, %{deactivated: true}) pending_follower = insert(:user, %{deactivated: true})
CommonAPI.follow(pending_follower, locked) CommonAPI.follow(pending_follower, locked)
@ -211,7 +211,7 @@ test "doesn't return follow requests for deactivated accounts" do
end end
test "clears follow requests when requester is blocked" do test "clears follow requests when requester is blocked" do
followed = insert(:user, locked: true) followed = insert(:user, is_locked: true)
follower = insert(:user) follower = insert(:user)
CommonAPI.follow(follower, followed) CommonAPI.follow(follower, followed)
@ -299,8 +299,8 @@ test "can't subscribe to a user who blocked us" do
end end
test "local users do not automatically follow local locked accounts" do test "local users do not automatically follow local locked accounts" do
follower = insert(:user, locked: true) follower = insert(:user, is_locked: true)
followed = insert(:user, locked: true) followed = insert(:user, is_locked: true)
{:ok, follower} = User.maybe_direct_follow(follower, followed) {:ok, follower} = User.maybe_direct_follow(follower, followed)
@ -1360,7 +1360,7 @@ test "it deactivates a user, all follow relationships and all activities", %{use
follower = insert(:user) follower = insert(:user)
{:ok, follower} = User.follow(follower, user) {:ok, follower} = User.follow(follower, user)
locked_user = insert(:user, name: "locked", locked: true) locked_user = insert(:user, name: "locked", is_locked: true)
{:ok, _} = User.follow(user, locked_user, :follow_pending) {:ok, _} = User.follow(user, locked_user, :follow_pending)
object = insert(:note, user: user) object = insert(:note, user: user)
@ -1450,7 +1450,7 @@ test "delete/1 purges a user when they wouldn't be fully deleted" do
note_count: 9, note_count: 9,
follower_count: 9, follower_count: 9,
following_count: 9001, following_count: 9001,
locked: true, is_locked: true,
confirmation_pending: true, confirmation_pending: true,
password_reset_pending: true, password_reset_pending: true,
approval_pending: true, approval_pending: true,
@ -1467,7 +1467,7 @@ test "delete/1 purges a user when they wouldn't be fully deleted" do
pleroma_settings_store: %{"q" => "x"}, pleroma_settings_store: %{"q" => "x"},
fields: [%{"gg" => "qq"}], fields: [%{"gg" => "qq"}],
raw_fields: [%{"gg" => "qq"}], raw_fields: [%{"gg" => "qq"}],
discoverable: true, is_discoverable: true,
also_known_as: ["https://lol.olo/users/loll"] also_known_as: ["https://lol.olo/users/loll"]
}) })
@ -1492,7 +1492,7 @@ test "delete/1 purges a user when they wouldn't be fully deleted" do
note_count: 0, note_count: 0,
follower_count: 0, follower_count: 0,
following_count: 0, following_count: 0,
locked: false, is_locked: false,
confirmation_pending: false, confirmation_pending: false,
password_reset_pending: false, password_reset_pending: false,
approval_pending: false, approval_pending: false,
@ -1509,7 +1509,7 @@ test "delete/1 purges a user when they wouldn't be fully deleted" do
pleroma_settings_store: %{}, pleroma_settings_store: %{},
fields: [], fields: [],
raw_fields: [], raw_fields: [],
discoverable: false, is_discoverable: false,
also_known_as: [] also_known_as: []
} = user } = user
end end

View File

@ -1487,9 +1487,9 @@ test "POST /api/ap/upload_media", %{conn: conn} do
desc = "Description of the image" desc = "Description of the image"
image = %Plug.Upload{ image = %Plug.Upload{
content_type: "image/jpg", content_type: "bad/content-type",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.png"
} }
object = object =
@ -1504,6 +1504,7 @@ test "POST /api/ap/upload_media", %{conn: conn} do
assert [%{"href" => object_href, "mediaType" => object_mediatype}] = object["url"] assert [%{"href" => object_href, "mediaType" => object_mediatype}] = object["url"]
assert is_binary(object_href) assert is_binary(object_href)
assert object_mediatype == "image/jpeg" assert object_mediatype == "image/jpeg"
assert String.ends_with?(object_href, ".jpg")
activity_request = %{ activity_request = %{
"@context" => "https://www.w3.org/ns/activitystreams", "@context" => "https://www.w3.org/ns/activitystreams",

View File

@ -505,22 +505,22 @@ test "increases replies count", %{user: user} do
# public # public
{:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "public")) {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "public"))
assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 1 assert object.data["repliesCount"] == 1
# unlisted # unlisted
{:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "unlisted")) {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "unlisted"))
assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 2 assert object.data["repliesCount"] == 2
# private # private
{:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "private")) {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "private"))
assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 2 assert object.data["repliesCount"] == 2
# direct # direct
{:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "direct")) {:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "direct"))
assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id) assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 2 assert object.data["repliesCount"] == 2
end end
end end
@ -779,6 +779,22 @@ test "does return activities from followed users on blocked domains" do
refute repeat_activity in activities refute repeat_activity in activities
end end
test "returns your own posts regardless of mute" do
user = insert(:user)
muted = insert(:user)
{:ok, muted_post} = CommonAPI.post(muted, %{status: "Im stupid"})
{:ok, reply} =
CommonAPI.post(user, %{status: "I'm muting you", in_reply_to_status_id: muted_post.id})
{:ok, _} = User.mute(user, muted)
[activity] = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true})
assert activity.id == reply.id
end
test "doesn't return muted activities" do test "doesn't return muted activities" do
activity_one = insert(:note_activity) activity_one = insert(:note_activity)
activity_two = insert(:note_activity) activity_two = insert(:note_activity)
@ -1056,7 +1072,7 @@ test "returns reblogs for users for whom reblogs have not been muted" do
describe "uploading files" do describe "uploading files" do
setup do setup do
test_file = %Plug.Upload{ test_file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -1147,7 +1163,7 @@ test "creates an undo activity for the last follow" do
test "creates an undo activity for a pending follow request" do test "creates an undo activity for a pending follow request" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, %{locked: true}) followed = insert(:user, %{is_locked: true})
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
{:ok, activity} = ActivityPub.unfollow(follower, followed) {:ok, activity} = ActivityPub.unfollow(follower, followed)

View File

@ -21,7 +21,7 @@ test "it's allowed when address is public" do
"type" => "Create" "type" => "Create"
} }
assert {:ok, message} = RejectNonPublic.filter(message) assert {:ok, _message} = RejectNonPublic.filter(message)
end end
test "it's allowed when cc address contain public address" do test "it's allowed when cc address contain public address" do
@ -34,7 +34,7 @@ test "it's allowed when cc address contain public address" do
"type" => "Create" "type" => "Create"
} }
assert {:ok, message} = RejectNonPublic.filter(message) assert {:ok, _message} = RejectNonPublic.filter(message)
end end
end end
@ -50,7 +50,7 @@ test "it's allowed when addrer of message in the follower addresses of user and
} }
Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], true) Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], true)
assert {:ok, message} = RejectNonPublic.filter(message) assert {:ok, _message} = RejectNonPublic.filter(message)
end end
test "it's rejected when addrer of message in the follower addresses of user and it disabled in config" do test "it's rejected when addrer of message in the follower addresses of user and it disabled in config" do
@ -80,7 +80,7 @@ test "it's allows when direct messages are allow" do
} }
Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], true) Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], true)
assert {:ok, message} = RejectNonPublic.filter(message) assert {:ok, _message} = RejectNonPublic.filter(message)
end end
test "it's reject when direct messages aren't allow" do test "it's reject when direct messages aren't allow" do

View File

@ -29,7 +29,7 @@ test "allows non-local follow requests" do
actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"]) actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"])
follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: true) follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: true)
message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id} message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id}
assert {:ok, message} = TagPolicy.filter(message) assert {:ok, _message} = TagPolicy.filter(message)
end end
end end

View File

@ -56,7 +56,7 @@ test "it handles our own uploads" do
user = insert(:user) user = insert(:user)
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }

View File

@ -77,7 +77,7 @@ test "validates for a basic object with an attachment", %{
user: user user: user
} do } do
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -98,7 +98,7 @@ test "validates for a basic object with an attachment in an array", %{
user: user user: user
} do } do
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -119,7 +119,7 @@ test "validates for a basic object with an attachment but without content", %{
user: user user: user
} do } do
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }

View File

@ -46,7 +46,7 @@ test "it works for incoming accepts which were pre-accepted" do
test "it works for incoming accepts which are referenced by IRI only" do test "it works for incoming accepts which are referenced by IRI only" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, locked: true) followed = insert(:user, is_locked: true)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
@ -72,7 +72,7 @@ test "it works for incoming accepts which are referenced by IRI only" do
test "it fails for incoming accepts which cannot be correlated" do test "it fails for incoming accepts which cannot be correlated" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, locked: true) followed = insert(:user, is_locked: true)
accept_data = accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json") File.read!("test/fixtures/mastodon-accept-activity.json")

View File

@ -144,7 +144,7 @@ test "it rejects incoming announces with an inlined activity from another origin
_user = insert(:user, local: false, ap_id: data["actor"]) _user = insert(:user, local: false, ap_id: data["actor"])
assert {:error, e} = Transmogrifier.handle_incoming(data) assert {:error, _e} = Transmogrifier.handle_incoming(data)
end end
test "it does not clobber the addressing on announce activities" do test "it does not clobber the addressing on announce activities" do

View File

@ -65,7 +65,7 @@ test "it works for incoming follow requests" do
end end
test "with locked accounts, it does create a Follow, but not an Accept" do test "with locked accounts, it does create a Follow, but not an Accept" do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
data = data =
File.read!("test/fixtures/mastodon-follow-activity.json") File.read!("test/fixtures/mastodon-follow-activity.json")
@ -188,7 +188,7 @@ test "it works for incoming follow requests from hubzilla" do
test "it works for incoming follows to locked account" do test "it works for incoming follows to locked account" do
pending_follower = insert(:user, ap_id: "http://mastodon.example.org/users/admin") pending_follower = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
data = data =
File.read!("test/fixtures/mastodon-follow-activity.json") File.read!("test/fixtures/mastodon-follow-activity.json")

View File

@ -14,7 +14,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.RejectHandlingTest do
test "it fails for incoming rejects which cannot be correlated" do test "it fails for incoming rejects which cannot be correlated" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, locked: true) followed = insert(:user, is_locked: true)
accept_data = accept_data =
File.read!("test/fixtures/mastodon-reject-activity.json") File.read!("test/fixtures/mastodon-reject-activity.json")
@ -33,7 +33,7 @@ test "it fails for incoming rejects which cannot be correlated" do
test "it works for incoming rejects which are referenced by IRI only" do test "it works for incoming rejects which are referenced by IRI only" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, locked: true) followed = insert(:user, is_locked: true)
{:ok, follower} = User.follow(follower, followed) {:ok, follower} = User.follow(follower, followed)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed) {:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)

View File

@ -154,6 +154,6 @@ test "it works for incoming update activities which lock the account" do
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(update_data) {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(update_data)
user = User.get_cached_by_ap_id(user.ap_id) user = User.get_cached_by_ap_id(user.ap_id)
assert user.locked == true assert user.is_locked == true
end end
end end

View File

@ -101,7 +101,7 @@ test "it fetches reply-to activities if we don't have them" do
{:ok, returned_activity} = Transmogrifier.handle_incoming(data) {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
returned_object = Object.normalize(returned_activity, false) returned_object = Object.normalize(returned_activity, false)
assert activity = assert %Activity{} =
Activity.get_create_by_object_ap_id( Activity.get_create_by_object_ap_id(
"https://mstdn.io/users/mayuutann/statuses/99568293732299394" "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
) )
@ -206,6 +206,16 @@ test "it works for incoming notices" do
assert user.note_count == 1 assert user.note_count == 1
end end
test "it works for incoming notices without the sensitive property but an nsfw hashtag" do
data = File.read!("test/fixtures/mastodon-post-activity-nsfw.json") |> Poison.decode!()
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
object_data = Object.normalize(data["object"], false).data
assert object_data["sensitive"] == true
end
test "it works for incoming notices with hashtags" do test "it works for incoming notices with hashtags" do
data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Poison.decode!() data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Poison.decode!()

View File

@ -193,7 +193,7 @@ test "fetches only Create activities" do
describe "update_follow_state_for_all/2" do describe "update_follow_state_for_all/2" do
test "updates the state of all Follow activities with the same actor and object" do test "updates the state of all Follow activities with the same actor and object" do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
follower = insert(:user) follower = insert(:user)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
@ -217,7 +217,7 @@ test "updates the state of all Follow activities with the same actor and object"
describe "update_follow_state/2" do describe "update_follow_state/2" do
test "updates the state of the given follow activity" do test "updates the state of the given follow activity" do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
follower = insert(:user) follower = insert(:user)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, user) {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)

View File

@ -180,7 +180,7 @@ test "it returns unapproved user" do
test "it returns non-discoverable users" do test "it returns non-discoverable users" do
insert(:user) insert(:user)
insert(:user, discoverable: false) insert(:user, is_discoverable: false)
{:ok, _results, total} = Search.user() {:ok, _results, total} = Search.user()

View File

@ -95,12 +95,26 @@ test "it blocks and does not federate if outgoing blocks are disabled", %{
describe "posting chat messages" do describe "posting chat messages" do
setup do: clear_config([:instance, :chat_limit]) setup do: clear_config([:instance, :chat_limit])
test "it posts a self-chat" do
author = insert(:user)
recipient = author
{:ok, activity} =
CommonAPI.post_chat_message(
author,
recipient,
"remember to buy milk when milk truk arive"
)
assert activity.data["type"] == "Create"
end
test "it posts a chat message without content but with an attachment" do test "it posts a chat message without content but with an attachment" do
author = insert(:user) author = insert(:user)
recipient = insert(:user) recipient = insert(:user)
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -622,7 +636,7 @@ test "it validates character limits are correctly enforced" do
assert {:error, "The status is over the character limit"} = assert {:error, "The status is over the character limit"} =
CommonAPI.post(user, %{status: "foobar"}) CommonAPI.post(user, %{status: "foobar"})
assert {:ok, activity} = CommonAPI.post(user, %{status: "12345"}) assert {:ok, _activity} = CommonAPI.post(user, %{status: "12345"})
end end
test "it can handle activities that expire" do test "it can handle activities that expire" do
@ -1071,7 +1085,7 @@ test "also unsubscribes a user" do
test "cancels a pending follow for a local user" do test "cancels a pending follow for a local user" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, locked: true) followed = insert(:user, is_locked: true)
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} = assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
CommonAPI.follow(follower, followed) CommonAPI.follow(follower, followed)
@ -1093,7 +1107,7 @@ test "cancels a pending follow for a local user" do
test "cancels a pending follow for a remote user" do test "cancels a pending follow for a remote user" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, locked: true, local: false, ap_enabled: true) followed = insert(:user, is_locked: true, local: false, ap_enabled: true)
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} = assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
CommonAPI.follow(follower, followed) CommonAPI.follow(follower, followed)
@ -1116,7 +1130,7 @@ test "cancels a pending follow for a remote user" do
describe "accept_follow_request/2" do describe "accept_follow_request/2" do
test "after acceptance, it sets all existing pending follow request states to 'accept'" do test "after acceptance, it sets all existing pending follow request states to 'accept'" do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
follower = insert(:user) follower = insert(:user)
follower_two = insert(:user) follower_two = insert(:user)
@ -1136,7 +1150,7 @@ test "after acceptance, it sets all existing pending follow request states to 'a
end end
test "after rejection, it sets all existing pending follow request states to 'reject'" do test "after rejection, it sets all existing pending follow request states to 'reject'" do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
follower = insert(:user) follower = insert(:user)
follower_two = insert(:user) follower_two = insert(:user)
@ -1156,7 +1170,7 @@ test "after rejection, it sets all existing pending follow request states to 're
end end
test "doesn't create a following relationship if the corresponding follow request doesn't exist" do test "doesn't create a following relationship if the corresponding follow request doesn't exist" do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
not_follower = insert(:user) not_follower = insert(:user)
CommonAPI.accept_follow_request(not_follower, user) CommonAPI.accept_follow_request(not_follower, user)

View File

@ -52,7 +52,7 @@ test "multiple origins can be added" do
end end
test "will be ignored" do test "will be ignored" do
assert {:ok, %SocketInfo{origin: origin, pid: pid_one}} = assert {:ok, %SocketInfo{origin: origin, pid: _pid_one}} =
FedRegistry.get_fed_socket(@good_domain_origin) FedRegistry.get_fed_socket(@good_domain_origin)
assert origin == "good.domain:80" assert origin == "good.domain:80"
@ -63,7 +63,7 @@ test "will be ignored" do
test "the newer process will be closed" do test "the newer process will be closed" do
pid_two = build_test_socket(@good_domain) pid_two = build_test_socket(@good_domain)
assert {:ok, %SocketInfo{origin: origin, pid: pid_one}} = assert {:ok, %SocketInfo{origin: origin, pid: _pid_one}} =
FedRegistry.get_fed_socket(@good_domain_origin) FedRegistry.get_fed_socket(@good_domain_origin)
assert origin == "good.domain:80" assert origin == "good.domain:80"

View File

@ -32,7 +32,7 @@ test "works by id" do
test "works by nickname" do test "works by nickname" do
user = insert(:user) user = insert(:user)
assert %{"id" => user_id} = assert %{"id" => _user_id} =
build_conn() build_conn()
|> get("/api/v1/accounts/#{user.nickname}") |> get("/api/v1/accounts/#{user.nickname}")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
@ -43,7 +43,7 @@ test "works by nickname for remote users" do
user = insert(:user, nickname: "user@example.com", local: false) user = insert(:user, nickname: "user@example.com", local: false)
assert %{"id" => user_id} = assert %{"id" => _user_id} =
build_conn() build_conn()
|> get("/api/v1/accounts/#{user.nickname}") |> get("/api/v1/accounts/#{user.nickname}")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
@ -380,7 +380,7 @@ test "gets an users media, excludes reblogs", %{conn: conn} do
other_user = insert(:user) other_user = insert(:user)
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -706,7 +706,7 @@ test "following / unfollowing a user", %{conn: conn} do
end end
test "cancelling follow request", %{conn: conn} do test "cancelling follow request", %{conn: conn} do
%{id: other_user_id} = insert(:user, %{locked: true}) %{id: other_user_id} = insert(:user, %{is_locked: true})
assert %{"id" => ^other_user_id, "following" => false, "requested" => true} = assert %{"id" => ^other_user_id, "following" => false, "requested" => true} =
conn conn
@ -1429,10 +1429,10 @@ test "returns an error if captcha is invalid", %{conn: conn} do
test "returns lists to which the account belongs" do test "returns lists to which the account belongs" do
%{user: user, conn: conn} = oauth_access(["read:lists"]) %{user: user, conn: conn} = oauth_access(["read:lists"])
other_user = insert(:user) other_user = insert(:user)
assert {:ok, %Pleroma.List{id: list_id} = list} = Pleroma.List.create("Test List", user) assert {:ok, %Pleroma.List{id: _list_id} = list} = Pleroma.List.create("Test List", user)
{:ok, %{following: _following}} = Pleroma.List.follow(list, other_user) {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
assert [%{"id" => list_id, "title" => "Test List"}] = assert [%{"id" => _list_id, "title" => "Test List"}] =
conn conn
|> get("/api/v1/accounts/#{other_user.id}/lists") |> get("/api/v1/accounts/#{other_user.id}/lists")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)

View File

@ -12,7 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
describe "locked accounts" do describe "locked accounts" do
setup do setup do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
%{conn: conn} = oauth_access(["follow"], user: user) %{conn: conn} = oauth_access(["follow"], user: user)
%{user: user, conn: conn} %{user: user, conn: conn}
end end

View File

@ -14,7 +14,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
setup do setup do
image = %Plug.Upload{ image = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -74,7 +74,7 @@ test "/api/v2/media", %{conn: conn, user: user, image: image} do
setup %{user: actor} do setup %{user: actor} do
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -106,7 +106,7 @@ test "/api/v1/media/:id good request", %{conn: conn, object: object} do
setup %{user: actor} do setup %{user: actor} do
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }

View File

@ -167,7 +167,7 @@ test "Get MRF reason when posting a status is rejected by one", %{conn: conn} do
test "posting an undefined status with an attachment", %{user: user, conn: conn} do test "posting an undefined status with an attachment", %{user: user, conn: conn} do
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -408,7 +408,7 @@ test "creates a scheduled activity with a media attachment", %{user: user, conn:
|> Kernel.<>("Z") |> Kernel.<>("Z")
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -937,7 +937,7 @@ test "reblogged status for another user" do
|> get("/api/v1/statuses/#{reblog_activity1.id}") |> get("/api/v1/statuses/#{reblog_activity1.id}")
assert %{ assert %{
"reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2}, "reblog" => %{"id" => _id, "reblogged" => false, "reblogs_count" => 2},
"reblogged" => false, "reblogged" => false,
"favourited" => false, "favourited" => false,
"bookmarked" => false "bookmarked" => false

View File

@ -222,7 +222,7 @@ test "updates the user's name", %{conn: conn} do
test "updates the user's avatar", %{user: user, conn: conn} do test "updates the user's avatar", %{user: user, conn: conn} do
new_avatar = %Plug.Upload{ new_avatar = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -246,7 +246,7 @@ test "updates the user's avatar", %{user: user, conn: conn} do
test "updates the user's banner", %{user: user, conn: conn} do test "updates the user's banner", %{user: user, conn: conn} do
new_header = %Plug.Upload{ new_header = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }
@ -265,7 +265,7 @@ test "updates the user's banner", %{user: user, conn: conn} do
test "updates the user's background", %{conn: conn, user: user} do test "updates the user's background", %{conn: conn, user: user} do
new_header = %Plug.Upload{ new_header = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }

View File

@ -332,7 +332,7 @@ test "represent a relationship for the user blocking a domain" do
test "represent a relationship for the user with a pending follow request" do test "represent a relationship for the user with a pending follow request" do
user = insert(:user) user = insert(:user)
other_user = insert(:user, locked: true) other_user = insert(:user, is_locked: true)
{:ok, user, other_user, _} = CommonAPI.follow(user, other_user) {:ok, user, other_user, _} = CommonAPI.follow(user, other_user)
user = User.get_cached_by_id(user.id) user = User.get_cached_by_id(user.id)
@ -481,7 +481,7 @@ test "shows zero when no follow requests are pending" do
end end
test "shows non-zero when follow requests are pending" do test "shows non-zero when follow requests are pending" do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user})
@ -493,7 +493,7 @@ test "shows non-zero when follow requests are pending" do
end end
test "decreases when accepting a follow request" do test "decreases when accepting a follow request" do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user})
@ -510,7 +510,7 @@ test "decreases when accepting a follow request" do
end end
test "decreases when rejecting a follow request" do test "decreases when rejecting a follow request" do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user})
@ -527,14 +527,14 @@ test "decreases when rejecting a follow request" do
end end
test "shows non-zero when historical unapproved requests are present" do test "shows non-zero when historical unapproved requests are present" do
user = insert(:user, locked: true) user = insert(:user, is_locked: true)
assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user}) assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user})
other_user = insert(:user) other_user = insert(:user)
{:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user) {:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
{:ok, user} = User.update_and_set_cache(user, %{locked: false}) {:ok, user} = User.update_and_set_cache(user, %{is_locked: false})
assert %{locked: false, follow_requests_count: 1} = assert %{locked: false, follow_requests_count: 1} =
AccountView.render("show.json", %{user: user, for: user}) AccountView.render("show.json", %{user: user, for: user})

View File

@ -22,7 +22,7 @@ test "A scheduled activity with a media attachment" do
|> NaiveDateTime.to_iso8601() |> NaiveDateTime.to_iso8601()
file = %Plug.Upload{ file = %Plug.Upload{
content_type: "image/jpg", content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"), path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg" filename: "an_image.jpg"
} }

View File

@ -14,13 +14,13 @@ test "for remote user" do
test "for local user" do test "for local user" do
assert Pleroma.Web.Metadata.Providers.RestrictIndexing.build_tags(%{ assert Pleroma.Web.Metadata.Providers.RestrictIndexing.build_tags(%{
user: %Pleroma.User{local: true, discoverable: true} user: %Pleroma.User{local: true, is_discoverable: true}
}) == [] }) == []
end end
test "for local user when discoverable is false" do test "for local user when discoverable is false" do
assert Pleroma.Web.Metadata.Providers.RestrictIndexing.build_tags(%{ assert Pleroma.Web.Metadata.Providers.RestrictIndexing.build_tags(%{
user: %Pleroma.User{local: true, discoverable: false} user: %Pleroma.User{local: true, is_discoverable: false}
}) == [{:meta, [name: "robots", content: "noindex, noarchive"], []}] }) == [{:meta, [name: "robots", content: "noindex, noarchive"], []}]
end end
end end

View File

@ -16,14 +16,14 @@ test "for remote user" do
end end
test "for local user" do test "for local user" do
user = insert(:user, discoverable: false) user = insert(:user, is_discoverable: false)
assert Pleroma.Web.Metadata.build_tags(%{user: user}) =~ assert Pleroma.Web.Metadata.build_tags(%{user: user}) =~
"<meta content=\"noindex, noarchive\" name=\"robots\">" "<meta content=\"noindex, noarchive\" name=\"robots\">"
end end
test "for local user set to discoverable" do test "for local user set to discoverable" do
user = insert(:user, discoverable: true) user = insert(:user, is_discoverable: true)
refute Pleroma.Web.Metadata.build_tags(%{user: user}) =~ refute Pleroma.Web.Metadata.build_tags(%{user: user}) =~
"<meta content=\"noindex, noarchive\" name=\"robots\">" "<meta content=\"noindex, noarchive\" name=\"robots\">"
@ -33,14 +33,14 @@ test "for local user set to discoverable" do
describe "no metadata for private instances" do describe "no metadata for private instances" do
test "for local user set to discoverable" do test "for local user set to discoverable" do
clear_config([:instance, :public], false) clear_config([:instance, :public], false)
user = insert(:user, bio: "This is my secret fedi account bio", discoverable: true) user = insert(:user, bio: "This is my secret fedi account bio", is_discoverable: true)
assert "" = Pleroma.Web.Metadata.build_tags(%{user: user}) assert "" = Pleroma.Web.Metadata.build_tags(%{user: user})
end end
test "search exclusion metadata is included" do test "search exclusion metadata is included" do
clear_config([:instance, :public], false) clear_config([:instance, :public], false)
user = insert(:user, bio: "This is my secret fedi account bio", discoverable: false) user = insert(:user, bio: "This is my secret fedi account bio", is_discoverable: false)
assert ~s(<meta content="noindex, noarchive" name="robots">) == assert ~s(<meta content="noindex, noarchive" name="robots">) ==
Pleroma.Web.Metadata.build_tags(%{user: user}) Pleroma.Web.Metadata.build_tags(%{user: user})

View File

@ -77,7 +77,7 @@ test "GET /oauth/prepare_request encodes parameters as `state` and redirects", %
} }
) )
assert response = html_response(conn, 302) assert html_response(conn, 302)
redirect_query = URI.parse(redirected_to(conn)).query redirect_query = URI.parse(redirected_to(conn)).query
assert %{"state" => state_param} = URI.decode_query(redirect_query) assert %{"state" => state_param} = URI.decode_query(redirect_query)
@ -119,7 +119,7 @@ test "with user-bound registration, GET /oauth/<provider>/callback redirects to
} }
) )
assert response = html_response(conn, 302) assert html_response(conn, 302)
assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/ assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
end end
@ -182,7 +182,7 @@ test "on authentication error, GET /oauth/<provider>/callback redirects to `redi
} }
) )
assert response = html_response(conn, 302) assert html_response(conn, 302)
assert redirected_to(conn) == app.redirect_uris assert redirected_to(conn) == app.redirect_uris
assert get_flash(conn, :error) == "Failed to authenticate: (error description)." assert get_flash(conn, :error) == "Failed to authenticate: (error description)."
end end
@ -238,7 +238,7 @@ test "with valid params, POST /oauth/register?op=register redirects to `redirect
} }
) )
assert response = html_response(conn, 302) assert html_response(conn, 302)
assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/ assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
end end
@ -268,7 +268,7 @@ test "with unlisted `redirect_uri`, POST /oauth/register?op=register results in
} }
) )
assert response = html_response(conn, 401) assert html_response(conn, 401)
end end
test "with invalid params, POST /oauth/register?op=register renders registration_details page", test "with invalid params, POST /oauth/register?op=register renders registration_details page",
@ -336,7 +336,7 @@ test "with valid params, POST /oauth/register?op=connect redirects to `redirect_
} }
) )
assert response = html_response(conn, 302) assert html_response(conn, 302)
assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/ assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
end end
@ -367,7 +367,7 @@ test "with unlisted `redirect_uri`, POST /oauth/register?op=connect results in H
} }
) )
assert response = html_response(conn, 401) assert html_response(conn, 401)
end end
test "with invalid params, POST /oauth/register?op=connect renders registration_details page", test "with invalid params, POST /oauth/register?op=connect renders registration_details page",

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