Merge branch 'develop' into 'from/develop/tusooa/emit-move'
# Conflicts: # CHANGELOG.md # test/pleroma/user_test.exs
This commit is contained in:
commit
c80096522c
|
@ -1,4 +1,4 @@
|
||||||
image: elixir:1.9.4
|
image: git.pleroma.social:5050/pleroma/pleroma/ci-base
|
||||||
|
|
||||||
variables: &global_variables
|
variables: &global_variables
|
||||||
POSTGRES_DB: pleroma_test
|
POSTGRES_DB: pleroma_test
|
||||||
|
@ -26,12 +26,7 @@ stages:
|
||||||
before_script:
|
before_script:
|
||||||
- echo $MIX_ENV
|
- echo $MIX_ENV
|
||||||
- rm -rf _build/*/lib/pleroma
|
- rm -rf _build/*/lib/pleroma
|
||||||
- apt-get update && apt-get install -y cmake
|
|
||||||
- mix local.hex --force
|
|
||||||
- mix local.rebar --force
|
|
||||||
- mix deps.get
|
- mix deps.get
|
||||||
- apt-get -qq update
|
|
||||||
- apt-get install -y libmagic-dev
|
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
- rm -rf _build/*/lib/pleroma
|
- rm -rf _build/*/lib/pleroma
|
||||||
|
@ -39,7 +34,8 @@ after_script:
|
||||||
build:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
only:
|
only:
|
||||||
changes:
|
changes: &build_changes_policy
|
||||||
|
- ".gitlab-ci.yml"
|
||||||
- "**/*.ex"
|
- "**/*.ex"
|
||||||
- "**/*.exs"
|
- "**/*.exs"
|
||||||
- "mix.lock"
|
- "mix.lock"
|
||||||
|
@ -50,6 +46,7 @@ spec-build:
|
||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
|
- ".gitlab-ci.yml"
|
||||||
- "lib/pleroma/web/api_spec/**/*.ex"
|
- "lib/pleroma/web/api_spec/**/*.ex"
|
||||||
- "lib/pleroma/web/api_spec.ex"
|
- "lib/pleroma/web/api_spec.ex"
|
||||||
artifacts:
|
artifacts:
|
||||||
|
@ -64,7 +61,7 @@ benchmark:
|
||||||
variables:
|
variables:
|
||||||
MIX_ENV: benchmark
|
MIX_ENV: benchmark
|
||||||
services:
|
services:
|
||||||
- name: postgres:9.6
|
- name: postgres:9.6-alpine
|
||||||
alias: postgres
|
alias: postgres
|
||||||
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
||||||
script:
|
script:
|
||||||
|
@ -75,20 +72,16 @@ benchmark:
|
||||||
unit-testing:
|
unit-testing:
|
||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
changes:
|
changes: *build_changes_policy
|
||||||
- "**/*.ex"
|
|
||||||
- "**/*.exs"
|
|
||||||
- "mix.lock"
|
|
||||||
cache: &testing_cache_policy
|
cache: &testing_cache_policy
|
||||||
<<: *global_cache_policy
|
<<: *global_cache_policy
|
||||||
policy: pull
|
policy: pull
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- name: postgres:13
|
- name: postgres:13-alpine
|
||||||
alias: postgres
|
alias: postgres
|
||||||
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
||||||
script:
|
script:
|
||||||
- apt-get update && apt-get install -y libimage-exiftool-perl ffmpeg
|
|
||||||
- mix ecto.create
|
- mix ecto.create
|
||||||
- mix ecto.migrate
|
- mix ecto.migrate
|
||||||
- mix coveralls --preload-modules
|
- mix coveralls --preload-modules
|
||||||
|
@ -96,17 +89,15 @@ unit-testing:
|
||||||
unit-testing-erratic:
|
unit-testing-erratic:
|
||||||
stage: test
|
stage: test
|
||||||
retry: 2
|
retry: 2
|
||||||
|
allow_failure: true
|
||||||
only:
|
only:
|
||||||
changes:
|
changes: *build_changes_policy
|
||||||
- "**/*.ex"
|
|
||||||
- "**/*.exs"
|
|
||||||
- "mix.lock"
|
|
||||||
cache: &testing_cache_policy
|
cache: &testing_cache_policy
|
||||||
<<: *global_cache_policy
|
<<: *global_cache_policy
|
||||||
policy: pull
|
policy: pull
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- name: postgres:13
|
- name: postgres:13-alpine
|
||||||
alias: postgres
|
alias: postgres
|
||||||
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
||||||
script:
|
script:
|
||||||
|
@ -133,10 +124,7 @@ unit-testing-erratic:
|
||||||
unit-testing-rum:
|
unit-testing-rum:
|
||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
changes:
|
changes: *build_changes_policy
|
||||||
- "**/*.ex"
|
|
||||||
- "**/*.exs"
|
|
||||||
- "mix.lock"
|
|
||||||
cache: *testing_cache_policy
|
cache: *testing_cache_policy
|
||||||
services:
|
services:
|
||||||
- name: minibikini/postgres-with-rum:12
|
- name: minibikini/postgres-with-rum:12
|
||||||
|
@ -146,46 +134,42 @@ unit-testing-rum:
|
||||||
<<: *global_variables
|
<<: *global_variables
|
||||||
RUM_ENABLED: "true"
|
RUM_ENABLED: "true"
|
||||||
script:
|
script:
|
||||||
- apt-get update && apt-get install -y libimage-exiftool-perl ffmpeg
|
|
||||||
- mix ecto.create
|
- mix ecto.create
|
||||||
- mix ecto.migrate
|
- mix ecto.migrate
|
||||||
- "mix ecto.migrate --migrations-path priv/repo/optional_migrations/rum_indexing/"
|
- "mix ecto.migrate --migrations-path priv/repo/optional_migrations/rum_indexing/"
|
||||||
- mix test --preload-modules
|
- mix test --preload-modules
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
image: elixir:1.12
|
image: ¤t_elixir elixir:1.12-alpine
|
||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
changes:
|
changes: *build_changes_policy
|
||||||
- "**/*.ex"
|
|
||||||
- "**/*.exs"
|
|
||||||
- "mix.lock"
|
|
||||||
cache: *testing_cache_policy
|
cache: *testing_cache_policy
|
||||||
|
before_script: ¤t_bfr_script
|
||||||
|
- apk update
|
||||||
|
- apk add build-base cmake file-dev git openssl
|
||||||
|
- mix local.hex --force
|
||||||
|
- mix local.rebar --force
|
||||||
|
- mix deps.get
|
||||||
script:
|
script:
|
||||||
- mix format --check-formatted
|
- mix format --check-formatted
|
||||||
|
|
||||||
analysis:
|
analysis:
|
||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
changes:
|
changes: *build_changes_policy
|
||||||
- "**/*.ex"
|
|
||||||
- "**/*.exs"
|
|
||||||
- "mix.lock"
|
|
||||||
cache: *testing_cache_policy
|
cache: *testing_cache_policy
|
||||||
script:
|
script:
|
||||||
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
|
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
|
||||||
|
|
||||||
cycles:
|
cycles:
|
||||||
|
image: *current_elixir
|
||||||
stage: test
|
stage: test
|
||||||
image: elixir:1.11
|
|
||||||
only:
|
only:
|
||||||
changes:
|
changes: *build_changes_policy
|
||||||
- "**/*.ex"
|
|
||||||
- "**/*.exs"
|
|
||||||
- "mix.lock"
|
|
||||||
cache: {}
|
cache: {}
|
||||||
|
before_script: *current_bfr_script
|
||||||
script:
|
script:
|
||||||
- mix deps.get
|
|
||||||
- mix compile
|
- mix compile
|
||||||
- mix xref graph --format cycles --label compile | awk '{print $0} END{exit ($0 != "No cycles found")}'
|
- mix xref graph --format cycles --label compile | awk '{print $0} END{exit ($0 != "No cycles found")}'
|
||||||
|
|
||||||
|
@ -305,7 +289,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 file-dev
|
- apk add git build-base cmake file-dev openssl
|
||||||
- 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
|
||||||
|
|
41
CHANGELOG.md
41
CHANGELOG.md
|
@ -12,21 +12,61 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Allow users to remove their emails if instance does not need email to register
|
- Allow users to remove their emails if instance does not need email to register
|
||||||
|
- Uploadfilter `Pleroma.Upload.Filter.Exiftool` has been renamed to `Pleroma.Upload.Filter.Exiftool.StripLocation`
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- `activeMonth` and `activeHalfyear` fields in NodeInfo usage.users object
|
- `activeMonth` and `activeHalfyear` fields in NodeInfo usage.users object
|
||||||
- Experimental support for Finch. Put `config :tesla, :adapter, {Tesla.Adapter.Finch, name: MyFinch}` in your secrets file to use it. Reverse Proxy will still use Hackney.
|
- Experimental support for Finch. Put `config :tesla, :adapter, {Tesla.Adapter.Finch, name: MyFinch}` in your secrets file to use it. Reverse Proxy will still use Hackney.
|
||||||
|
- `ForceMentionsInPostContent` MRF policy
|
||||||
- AdminAPI: allow moderators to manage reports, users, invites, and custom emojis
|
- AdminAPI: allow moderators to manage reports, users, invites, and custom emojis
|
||||||
- AdminAPI: restrict moderators to access sensitive data: change user credentials, get password reset token, read private statuses and chats, etc
|
- AdminAPI: restrict moderators to access sensitive data: change user credentials, get password reset token, read private statuses and chats, etc
|
||||||
|
- PleromaAPI: Add remote follow API endpoint at `POST /api/v1/pleroma/remote_interaction`
|
||||||
|
- MastoAPI: Add `GET /api/v1/accounts/lookup`
|
||||||
|
- MastoAPI: Profile Directory support
|
||||||
|
- MastoAPI: Support v2 Suggestions (handpicked accounts only)
|
||||||
|
- Ability to log slow Ecto queries by configuring `:pleroma, :telemetry, :slow_queries_logging`
|
||||||
|
- Added Phoenix LiveDashboard at `/phoenix/live_dashboard`
|
||||||
|
- Added `/manifest.json` for progressive web apps.
|
||||||
|
- MastoAPI: Support for `birthday` and `show_birthday` field in `/api/v1/accounts/update_credentials`.
|
||||||
|
- Configuration: Add `birthday_required` and `birthday_min_age` settings to provide a way to require users to enter their birth date.
|
||||||
|
- PleromaAPI: Add `GET /api/v1/pleroma/birthdays` API endpoint
|
||||||
|
- Make backend-rendered pages translatable. This includes emails. Pages returned as a HTTP response are translated using the language specified in the `userLanguage` cookie, or the `Accept-Language` header. Emails are translated using the `language` field when registering. This language can be changed by `PATCH /api/v1/accounts/update_credentials` with the `language` field.
|
||||||
|
- Uploadfilter `Pleroma.Upload.Filter.Exiftool.ReadDescription` returns description values to the FE so they can pre fill the image description field
|
||||||
- Added move account API
|
- Added move account API
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies
|
- Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies
|
||||||
- Handle Reject for already-accepted Follows properly
|
- Handle Reject for already-accepted Follows properly
|
||||||
- Display OpenGraph data on alternative notice routes.
|
- Display OpenGraph data on alternative notice routes.
|
||||||
|
- Fix replies count for remote replies
|
||||||
|
- Fixed hashtags disappearing from the end of lines when Markdown is enabled
|
||||||
|
- ChatAPI: Add link headers
|
||||||
|
- Limited number of search results to 40 to prevent DoS attacks
|
||||||
|
- ActivityPub: fixed federation of attachment dimensions
|
||||||
|
- Fixed benchmarks
|
||||||
|
- Elixir 1.13 support
|
||||||
|
- Fixed crash when pinned_objects is nil
|
||||||
|
- Fixed slow timelines when there are a lot of deactivated users
|
||||||
|
- Fixed account deletion API
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
## 2.4.3 - 2022-05-06
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Private `/objects/` and `/activities/` leaking if cached by authenticated user
|
||||||
|
- SweetXML library DTD bomb
|
||||||
|
|
||||||
|
## 2.4.2 - 2022-01-10
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Federation issues caused by HTTP pool checkout timeouts
|
||||||
|
- Compatibility with Elixir 1.13
|
||||||
|
|
||||||
|
### Upgrade notes
|
||||||
|
|
||||||
|
1. Restart Pleroma
|
||||||
|
|
||||||
## 2.4.1 - 2021-08-29
|
## 2.4.1 - 2021-08-29
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -60,6 +100,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Improved Twittercard and OpenGraph meta tag generation including thumbnails and image dimension metadata when available.
|
- Improved Twittercard and OpenGraph meta tag generation including thumbnails and image dimension metadata when available.
|
||||||
- AdminAPI: sort users so the newest are at the top.
|
- AdminAPI: sort users so the newest are at the top.
|
||||||
- ActivityPub Client-to-Server(C2S): Limitation on the type of Activity/Object are lifted as they are now passed through ObjectValidators
|
- ActivityPub Client-to-Server(C2S): Limitation on the type of Activity/Object are lifted as they are now passed through ObjectValidators
|
||||||
|
- MRF (`AntiFollowbotPolicy`): Bot accounts are now also considered followbots. Users can still allow bots to follow them by first following the bot.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
|
6
COPYING
6
COPYING
|
@ -1,11 +1,11 @@
|
||||||
Unless otherwise stated this repository is copyright © 2017-2021
|
Unless otherwise stated this repository is copyright © 2017-2022
|
||||||
Pleroma Authors <https://pleroma.social/>, and is distributed under
|
Pleroma Authors <https://pleroma.social/>, and is distributed under
|
||||||
The GNU Affero General Public License Version 3, you should have received a
|
The GNU Affero General Public License Version 3, you should have received a
|
||||||
copy of the license file as AGPL-3.
|
copy of the license file as AGPL-3.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Files inside docs directory are copyright © 2021 Pleroma Authors
|
Files inside docs directory are copyright © 2022 Pleroma Authors
|
||||||
<https://pleroma.social/>, and are distributed under the Creative Commons
|
<https://pleroma.social/>, and are distributed under the Creative Commons
|
||||||
Attribution 4.0 International license, you should have received
|
Attribution 4.0 International license, you should have received
|
||||||
a copy of the license file as CC-BY-4.0.
|
a copy of the license file as CC-BY-4.0.
|
||||||
|
@ -30,7 +30,7 @@ priv/static/images/pleroma-fox-tan-shy.png
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
The following files are copyright © 2017-2020 Pleroma Authors
|
The following files are copyright © 2017-2022 Pleroma Authors
|
||||||
<https://pleroma.social/>, and are distributed under the Creative Commons
|
<https://pleroma.social/>, and are distributed under the Creative Commons
|
||||||
Attribution-ShareAlike 4.0 International license, you should have received
|
Attribution-ShareAlike 4.0 International license, you should have received
|
||||||
a copy of the license file as CC-BY-SA-4.0.
|
a copy of the license file as CC-BY-SA-4.0.
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
FROM elixir:1.9.4
|
||||||
|
|
||||||
|
RUN apt-get update &&\
|
||||||
|
apt-get install -y libmagic-dev cmake libimage-exiftool-perl ffmpeg &&\
|
||||||
|
mix local.hex --force &&\
|
||||||
|
mix local.rebar --force
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t git.pleroma.social:5050/pleroma/pleroma/ci-base:latest --push .
|
|
@ -149,8 +149,6 @@
|
||||||
]
|
]
|
||||||
|
|
||||||
# Configures Elixir's Logger
|
# Configures Elixir's Logger
|
||||||
config :logger, truncate: 65536
|
|
||||||
|
|
||||||
config :logger, :console,
|
config :logger, :console,
|
||||||
level: :debug,
|
level: :debug,
|
||||||
format: "\n$time $metadata[$level] $message\n",
|
format: "\n$time $metadata[$level] $message\n",
|
||||||
|
@ -189,6 +187,7 @@
|
||||||
email: "example@example.com",
|
email: "example@example.com",
|
||||||
notify_email: "noreply@example.com",
|
notify_email: "noreply@example.com",
|
||||||
description: "Pleroma: An efficient and flexible fediverse server",
|
description: "Pleroma: An efficient and flexible fediverse server",
|
||||||
|
short_description: "",
|
||||||
background_image: "/images/city.jpg",
|
background_image: "/images/city.jpg",
|
||||||
instance_thumbnail: "/instance/thumbnail.jpeg",
|
instance_thumbnail: "/instance/thumbnail.jpeg",
|
||||||
limit: 5_000,
|
limit: 5_000,
|
||||||
|
@ -258,7 +257,11 @@
|
||||||
show_reactions: true,
|
show_reactions: true,
|
||||||
password_reset_token_validity: 60 * 60 * 24,
|
password_reset_token_validity: 60 * 60 * 24,
|
||||||
profile_directory: true,
|
profile_directory: true,
|
||||||
privileged_staff: false
|
privileged_staff: false,
|
||||||
|
max_endorsed_users: 20,
|
||||||
|
birthday_required: false,
|
||||||
|
birthday_min_age: 0,
|
||||||
|
max_media_attachments: 1_000
|
||||||
|
|
||||||
config :pleroma, :welcome,
|
config :pleroma, :welcome,
|
||||||
direct_message: [
|
direct_message: [
|
||||||
|
@ -856,13 +859,6 @@
|
||||||
{Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy, [max_running: 5, max_waiting: 5]}
|
{Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy, [max_running: 5, max_waiting: 5]}
|
||||||
]
|
]
|
||||||
|
|
||||||
config :pleroma, :telemetry,
|
|
||||||
slow_queries_logging: [
|
|
||||||
enabled: false,
|
|
||||||
min_duration: 500_000,
|
|
||||||
exclude_sources: [nil, "oban_jobs"]
|
|
||||||
]
|
|
||||||
|
|
||||||
# Import environment specific config. This must remain at the bottom
|
# Import environment specific config. This must remain at the bottom
|
||||||
# of this file so it overrides the configuration defined above.
|
# of this file so it overrides the configuration defined above.
|
||||||
import_config "#{Mix.env()}.exs"
|
import_config "#{Mix.env()}.exs"
|
||||||
|
|
|
@ -536,6 +536,15 @@
|
||||||
"Very cool instance"
|
"Very cool instance"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
%{
|
||||||
|
key: :short_description,
|
||||||
|
type: :string,
|
||||||
|
description:
|
||||||
|
"Shorter version of instance description. It can be seen on `/api/v1/instance`",
|
||||||
|
suggestions: [
|
||||||
|
"Cool instance"
|
||||||
|
]
|
||||||
|
},
|
||||||
%{
|
%{
|
||||||
key: :limit,
|
key: :limit,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
|
@ -552,6 +561,14 @@
|
||||||
100_000
|
100_000
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
%{
|
||||||
|
key: :max_media_attachments,
|
||||||
|
type: :integer,
|
||||||
|
description: "Maximum number of post media attachments",
|
||||||
|
suggestions: [
|
||||||
|
1_000_000
|
||||||
|
]
|
||||||
|
},
|
||||||
%{
|
%{
|
||||||
key: :upload_limit,
|
key: :upload_limit,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
|
@ -742,6 +759,16 @@
|
||||||
3
|
3
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
%{
|
||||||
|
key: :max_endorsed_users,
|
||||||
|
type: :integer,
|
||||||
|
description: "The maximum number of recommended accounts. 0 will disable the feature.",
|
||||||
|
suggestions: [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
3
|
||||||
|
]
|
||||||
|
},
|
||||||
%{
|
%{
|
||||||
key: :autofollowed_nicknames,
|
key: :autofollowed_nicknames,
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
|
@ -947,6 +974,17 @@
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"Let moderators access sensitive data (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)"
|
"Let moderators access sensitive data (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :birthday_required,
|
||||||
|
type: :boolean,
|
||||||
|
description: "Require users to enter their birthday."
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :birthday_min_age,
|
||||||
|
type: :integer,
|
||||||
|
description:
|
||||||
|
"Minimum required age for users to create account. Only used if birthday is required."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1691,6 +1729,11 @@
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Sign object fetches with HTTP signatures"
|
description: "Sign object fetches with HTTP signatures"
|
||||||
},
|
},
|
||||||
|
%{
|
||||||
|
key: :authorized_fetch_mode,
|
||||||
|
type: :boolean,
|
||||||
|
description: "Require HTTP signatures for AP fetches"
|
||||||
|
},
|
||||||
%{
|
%{
|
||||||
key: :note_replies_output_limit,
|
key: :note_replies_output_limit,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
|
@ -2697,7 +2740,7 @@
|
||||||
key: :versions,
|
key: :versions,
|
||||||
type: {:list, :atom},
|
type: {:list, :atom},
|
||||||
description: "List of TLS version to use",
|
description: "List of TLS version to use",
|
||||||
suggestions: [:tlsv1, ":tlsv1.1", ":tlsv1.2"]
|
suggestions: [:tlsv1, ":tlsv1.1", ":tlsv1.2", ":tlsv1.3"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,8 @@ If any of the options are left unspecified, you will be prompted interactively.
|
||||||
- `--static-dir <path>` - the directory custom public files should be read from (custom emojis, frontend bundle overrides, robots.txt, etc.)
|
- `--static-dir <path>` - the directory custom public files should be read from (custom emojis, frontend bundle overrides, robots.txt, etc.)
|
||||||
- `--listen-ip <ip>` - the ip the app should listen to, defaults to 127.0.0.1
|
- `--listen-ip <ip>` - the ip the app should listen to, defaults to 127.0.0.1
|
||||||
- `--listen-port <port>` - the port the app should listen to, defaults to 4000
|
- `--listen-port <port>` - the port the app should listen to, defaults to 4000
|
||||||
- `--strip-uploads <Y|N>` - use ExifTool to strip uploads of sensitive location data
|
- `--strip-uploads-location <Y|N>` - use ExifTool to strip uploads of sensitive location data
|
||||||
|
- `--read-uploads-description <Y|N>` - use ExifTool to read image descriptions from uploads
|
||||||
- `--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
|
- `--skip-release-env` - skip generation the release environment file
|
||||||
|
|
|
@ -17,11 +17,11 @@ su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate"
|
||||||
## For from source installations (using git)
|
## For from source installations (using git)
|
||||||
|
|
||||||
1. Go to the working directory of Pleroma (default is `/opt/pleroma`)
|
1. Go to the working directory of Pleroma (default is `/opt/pleroma`)
|
||||||
2. Run `git pull`. This pulls the latest changes from upstream.
|
2. Run `git pull` [^1]. This pulls the latest changes from upstream.
|
||||||
3. Run `mix deps.get` [^1]. This pulls in any new dependencies.
|
3. Run `mix deps.get` [^1]. This pulls in any new dependencies.
|
||||||
4. Stop the Pleroma service.
|
4. Stop the Pleroma service.
|
||||||
5. Run `mix ecto.migrate` [^1] [^2]. This task performs database migrations, if there were any.
|
5. Run `mix ecto.migrate` [^1] [^2]. This task performs database migrations, if there were any.
|
||||||
6. Start the Pleroma service.
|
6. Start the Pleroma service.
|
||||||
|
|
||||||
[^1]: Depending on which install guide you followed (for example on Debian/Ubuntu), you want to run `mix` tasks as `pleroma` user by adding `sudo -Hu pleroma` before the command.
|
[^1]: Depending on which install guide you followed (for example on Debian/Ubuntu), you want to run `git` and `mix` tasks as `pleroma` user by adding `sudo -Hu pleroma` before the command.
|
||||||
[^2]: Prefix with `MIX_ENV=prod` to run it using the production config file.
|
[^2]: Prefix with `MIX_ENV=prod` to run it using the production config file.
|
||||||
|
|
|
@ -116,3 +116,9 @@ Feel free to contact us to be added to this list!
|
||||||
- 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
|
- Features: MastoAPI
|
||||||
|
|
||||||
|
### Glitch-lily
|
||||||
|
- Source Code: <https://lily.kazv.moe/infra/glitch-lily>
|
||||||
|
- Contact: [@tusooa@kazv.moe](https://kazv.moe/users/tusooa)
|
||||||
|
- Features: MastoAPI
|
||||||
|
- Based on [glitch-soc](https://github.com/glitch-soc/mastodon) frontend
|
||||||
|
|
|
@ -18,6 +18,7 @@ To add configuration to your config file, you can copy it from the base config.
|
||||||
* `email`: Email used to reach an Administrator/Moderator of the instance.
|
* `email`: Email used to reach an Administrator/Moderator of the instance.
|
||||||
* `notify_email`: Email used for notifications.
|
* `notify_email`: Email used for notifications.
|
||||||
* `description`: The instance’s description, can be seen in nodeinfo and ``/api/v1/instance``.
|
* `description`: The instance’s description, can be seen in nodeinfo and ``/api/v1/instance``.
|
||||||
|
* `short_description`: Shorter version of instance description, can be seen on ``/api/v1/instance``.
|
||||||
* `limit`: Posts character limit (CW/Subject included in the counter).
|
* `limit`: Posts character limit (CW/Subject included in the counter).
|
||||||
* `description_limit`: The character limit for image descriptions.
|
* `description_limit`: The character limit for image descriptions.
|
||||||
* `remote_limit`: Hard character limit beyond which remote posts will be dropped.
|
* `remote_limit`: Hard character limit beyond which remote posts will be dropped.
|
||||||
|
@ -125,6 +126,9 @@ To add configuration to your config file, you can copy it from the base config.
|
||||||
* `Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy`: Sets a default expiration on all posts made by users of the local instance. Requires `Pleroma.Workers.PurgeExpiredActivity` to be enabled for processing the scheduled delections.
|
* `Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy`: Sets a default expiration on all posts made by users of the local instance. Requires `Pleroma.Workers.PurgeExpiredActivity` to be enabled for processing the scheduled delections.
|
||||||
* `Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy`: Makes all bot posts to disappear from public timelines.
|
* `Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy`: Makes all bot posts to disappear from public timelines.
|
||||||
* `Pleroma.Web.ActivityPub.MRF.FollowBotPolicy`: Automatically follows newly discovered users from the specified bot account. Local accounts, locked accounts, and users with "#nobot" in their bio are respected and excluded from being followed.
|
* `Pleroma.Web.ActivityPub.MRF.FollowBotPolicy`: Automatically follows newly discovered users from the specified bot account. Local accounts, locked accounts, and users with "#nobot" in their bio are respected and excluded from being followed.
|
||||||
|
* `Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy`: Drops follow requests from followbots. Users can still allow bots to follow them by first following the bot.
|
||||||
|
* `Pleroma.Web.ActivityPub.MRF.KeywordPolicy`: Rejects or removes from the federated timeline or replaces keywords. (See [`:mrf_keyword`](#mrf_keyword)).
|
||||||
|
* `Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent`: Forces every mentioned user to be reflected in the post content.
|
||||||
* `transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo).
|
* `transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo).
|
||||||
* `transparency_exclusions`: Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value.
|
* `transparency_exclusions`: Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value.
|
||||||
|
|
||||||
|
@ -624,12 +628,18 @@ This filter replaces the filename (not the path) of an upload. For complete obfu
|
||||||
|
|
||||||
No specific configuration.
|
No specific configuration.
|
||||||
|
|
||||||
#### Pleroma.Upload.Filter.Exiftool
|
#### Pleroma.Upload.Filter.Exiftool.StripLocation
|
||||||
|
|
||||||
This filter only strips the GPS and location metadata with Exiftool leaving color profiles and attributes intact.
|
This filter only strips the GPS and location metadata with Exiftool leaving color profiles and attributes intact.
|
||||||
|
|
||||||
No specific configuration.
|
No specific configuration.
|
||||||
|
|
||||||
|
#### Pleroma.Upload.Filter.Exiftool.ReadDescription
|
||||||
|
|
||||||
|
This filter reads the ImageDescription and iptc:Caption-Abstract fields with Exiftool so clients can prefill the media description field.
|
||||||
|
|
||||||
|
No specific configuration.
|
||||||
|
|
||||||
#### Pleroma.Upload.Filter.Mogrify
|
#### Pleroma.Upload.Filter.Mogrify
|
||||||
|
|
||||||
* `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"implode", "1"}]`.
|
* `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"implode", "1"}]`.
|
||||||
|
|
|
@ -1636,3 +1636,117 @@ Returns the content of the document
|
||||||
"error": "Could not install frontend"
|
"error": "Could not install frontend"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `GET /api/v1/pleroma/admin/announcements`
|
||||||
|
|
||||||
|
### List announcements
|
||||||
|
|
||||||
|
- Params: `offset`, `limit`
|
||||||
|
|
||||||
|
- Response: JSON, list of announcements
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "AHDp0GBdRn1EPN5HN2",
|
||||||
|
"content": "some content",
|
||||||
|
"starts_at": null,
|
||||||
|
"ends_at": null,
|
||||||
|
"all_day": false,
|
||||||
|
"published_at": "2022-03-09T02:13:05",
|
||||||
|
"reactions": [],
|
||||||
|
"statuses": [],
|
||||||
|
"tags": [],
|
||||||
|
"emojis": [],
|
||||||
|
"updated_at": "2022-03-09T02:13:05"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that this differs from the Mastodon API variant: Mastodon API only returns *active* announcements, while this returns all.
|
||||||
|
|
||||||
|
## `GET /api/v1/pleroma/admin/announcements/:id`
|
||||||
|
|
||||||
|
### Display one announcement
|
||||||
|
|
||||||
|
- Response: JSON, one announcement
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "AHDp0GBdRn1EPN5HN2",
|
||||||
|
"content": "some content",
|
||||||
|
"starts_at": null,
|
||||||
|
"ends_at": null,
|
||||||
|
"all_day": false,
|
||||||
|
"published_at": "2022-03-09T02:13:05",
|
||||||
|
"reactions": [],
|
||||||
|
"statuses": [],
|
||||||
|
"tags": [],
|
||||||
|
"emojis": [],
|
||||||
|
"updated_at": "2022-03-09T02:13:05"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `POST /api/v1/pleroma/admin/announcements`
|
||||||
|
|
||||||
|
### Create an announcement
|
||||||
|
|
||||||
|
- Params:
|
||||||
|
- `content`: string, required, announcement content
|
||||||
|
- `starts_at`: datetime, optional, default to null, the time when the announcement will become active (displayed to users); if it is null, the announcement will be active immediately
|
||||||
|
- `ends_at`: datetime, optional, default to null, the time when the announcement will become inactive (no longer displayed to users); if it is null, the announcement will be active until an admin deletes it
|
||||||
|
- `all_day`: boolean, optional, default to false, tells the client whether to only display dates for `starts_at` and `ends_at`
|
||||||
|
|
||||||
|
- Response: JSON, created announcement
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "AHDp0GBdRn1EPN5HN2",
|
||||||
|
"content": "some content",
|
||||||
|
"starts_at": null,
|
||||||
|
"ends_at": null,
|
||||||
|
"all_day": false,
|
||||||
|
"published_at": "2022-03-09T02:13:05",
|
||||||
|
"reactions": [],
|
||||||
|
"statuses": [],
|
||||||
|
"tags": [],
|
||||||
|
"emojis": [],
|
||||||
|
"updated_at": "2022-03-09T02:13:05"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `PATCH /api/v1/pleroma/admin/announcements/:id`
|
||||||
|
|
||||||
|
### Change an announcement
|
||||||
|
|
||||||
|
- Params: same as `POST /api/v1/pleroma/admin/announcements`, except no param is required.
|
||||||
|
|
||||||
|
- Updates the announcement according to params. Missing params are kept as-is.
|
||||||
|
|
||||||
|
- Response: JSON, updated announcement
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "AHDp0GBdRn1EPN5HN2",
|
||||||
|
"content": "some content",
|
||||||
|
"starts_at": null,
|
||||||
|
"ends_at": null,
|
||||||
|
"all_day": false,
|
||||||
|
"published_at": "2022-03-09T02:13:05",
|
||||||
|
"reactions": [],
|
||||||
|
"statuses": [],
|
||||||
|
"tags": [],
|
||||||
|
"emojis": [],
|
||||||
|
"updated_at": "2022-03-09T02:13:05"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `DELETE /api/v1/pleroma/admin/announcements/:id`
|
||||||
|
|
||||||
|
### Delete an announcement
|
||||||
|
|
||||||
|
- Response: JSON, empty object
|
||||||
|
|
||||||
|
```json
|
||||||
|
{}
|
||||||
|
```
|
||||||
|
|
|
@ -241,6 +241,7 @@ Additional parameters can be added to the JSON body/Form data:
|
||||||
- `discoverable` - if true, external services (search bots) etc. are allowed to index / list the account (regardless of this setting, user will still appear in regular search results).
|
- `discoverable` - if true, external services (search bots) etc. are allowed to index / list the account (regardless of this setting, user will still appear in regular search results).
|
||||||
- `actor_type` - the type of this account.
|
- `actor_type` - the type of this account.
|
||||||
- `accepts_chat_messages` - if false, this account will reject all chat messages.
|
- `accepts_chat_messages` - if false, this account will reject all chat messages.
|
||||||
|
- `language` - user's preferred language for receiving emails (digest, confirmation, etc.)
|
||||||
|
|
||||||
All images (avatar, banner and background) can be reset to the default by sending an empty string ("") instead of a file.
|
All images (avatar, banner and background) can be reset to the default by sending an empty string ("") instead of a file.
|
||||||
|
|
||||||
|
@ -292,6 +293,7 @@ Has these additional parameters (which are the same as in Pleroma-API):
|
||||||
- `captcha_token`: optional, contains provider-specific captcha token
|
- `captcha_token`: optional, contains provider-specific captcha token
|
||||||
- `captcha_answer_data`: optional, contains provider-specific captcha data
|
- `captcha_answer_data`: optional, contains provider-specific captcha data
|
||||||
- `token`: invite token required when the registrations aren't public.
|
- `token`: invite token required when the registrations aren't public.
|
||||||
|
- `language`: optional, user's preferred language for receiving emails (digest, confirmation, etc.), default to the language set in the `userLanguage` cookies or `Accept-Language` header.
|
||||||
|
|
||||||
## Instance
|
## Instance
|
||||||
|
|
||||||
|
@ -377,12 +379,6 @@ Pleroma is generally compatible with the Mastodon 2.7.2 API, but some newer feat
|
||||||
|
|
||||||
- `GET /api/v1/identity_proofs`: Returns an empty array, `[]`
|
- `GET /api/v1/identity_proofs`: Returns an empty array, `[]`
|
||||||
|
|
||||||
### Endorsements
|
|
||||||
|
|
||||||
*Added in Mastodon 2.5.0*
|
|
||||||
|
|
||||||
- `GET /api/v1/endorsements`: Returns an empty array, `[]`
|
|
||||||
|
|
||||||
### Featured tags
|
### Featured tags
|
||||||
|
|
||||||
*Added in Mastodon 3.0.0*
|
*Added in Mastodon 3.0.0*
|
||||||
|
|
|
@ -37,7 +37,7 @@ The `/api/v1/pleroma/*` path is backwards compatible with `/api/pleroma/*` (`/ap
|
||||||
```
|
```
|
||||||
* Note: Same data as Mastodon API’s `/api/v1/custom_emojis` but in a different format
|
* Note: Same data as Mastodon API’s `/api/v1/custom_emojis` but in a different format
|
||||||
|
|
||||||
## `/api/v1/pleroma/follow_import`
|
## `/api/pleroma/follow_import`
|
||||||
### Imports your follows, for example from a Mastodon CSV file.
|
### Imports your follows, for example from a Mastodon CSV file.
|
||||||
* Method: `POST`
|
* Method: `POST`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
|
@ -46,7 +46,7 @@ The `/api/v1/pleroma/*` path is backwards compatible with `/api/pleroma/*` (`/ap
|
||||||
* Response: HTTP 200 on success, 500 on error
|
* Response: HTTP 200 on success, 500 on error
|
||||||
* Note: Users that can't be followed are silently skipped.
|
* Note: Users that can't be followed are silently skipped.
|
||||||
|
|
||||||
## `/api/v1/pleroma/blocks_import`
|
## `/api/pleroma/blocks_import`
|
||||||
### Imports your blocks.
|
### Imports your blocks.
|
||||||
* Method: `POST`
|
* Method: `POST`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
|
@ -54,7 +54,7 @@ The `/api/v1/pleroma/*` path is backwards compatible with `/api/pleroma/*` (`/ap
|
||||||
* `list`: STRING or FILE containing a whitespace-separated list of accounts to block
|
* `list`: STRING or FILE containing a whitespace-separated list of accounts to block
|
||||||
* Response: HTTP 200 on success, 500 on error
|
* Response: HTTP 200 on success, 500 on error
|
||||||
|
|
||||||
## `/api/v1/pleroma/mutes_import`
|
## `/api/pleroma/mutes_import`
|
||||||
### Imports your mutes.
|
### Imports your mutes.
|
||||||
* Method: `POST`
|
* Method: `POST`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
|
@ -70,7 +70,7 @@ The `/api/v1/pleroma/*` path is backwards compatible with `/api/pleroma/*` (`/ap
|
||||||
* Response: Provider specific JSON, the only guaranteed parameter is `type`
|
* Response: Provider specific JSON, the only guaranteed parameter is `type`
|
||||||
* Example response: `{"type": "kocaptcha", "token": "whatever", "url": "https://captcha.kotobank.ch/endpoint", "seconds_valid": 300}`
|
* Example response: `{"type": "kocaptcha", "token": "whatever", "url": "https://captcha.kotobank.ch/endpoint", "seconds_valid": 300}`
|
||||||
|
|
||||||
## `/api/v1/pleroma/delete_account`
|
## `/api/pleroma/delete_account`
|
||||||
### Delete an account
|
### Delete an account
|
||||||
* Method `POST`
|
* Method `POST`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
|
@ -79,7 +79,7 @@ The `/api/v1/pleroma/*` path is backwards compatible with `/api/pleroma/*` (`/ap
|
||||||
* Response: JSON. Returns `{"status": "success"}` if the deletion was successful, `{"error": "[error message]"}` otherwise
|
* Response: JSON. Returns `{"status": "success"}` if the deletion was successful, `{"error": "[error message]"}` otherwise
|
||||||
* Example response: `{"error": "Invalid password."}`
|
* Example response: `{"error": "Invalid password."}`
|
||||||
|
|
||||||
## `/api/v1/pleroma/disable_account`
|
## `/api/pleroma/disable_account`
|
||||||
### Disable an account
|
### Disable an account
|
||||||
* Method `POST`
|
* Method `POST`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
|
@ -88,21 +88,22 @@ The `/api/v1/pleroma/*` path is backwards compatible with `/api/pleroma/*` (`/ap
|
||||||
* Response: JSON. Returns `{"status": "success"}` if the account was successfully disabled, `{"error": "[error message]"}` otherwise
|
* Response: JSON. Returns `{"status": "success"}` if the account was successfully disabled, `{"error": "[error message]"}` otherwise
|
||||||
* Example response: `{"error": "Invalid password."}`
|
* Example response: `{"error": "Invalid password."}`
|
||||||
|
|
||||||
## `/api/v1/pleroma/accounts/mfa`
|
## `/api/pleroma/accounts/mfa`
|
||||||
#### Gets current MFA settings
|
#### Gets current MFA settings
|
||||||
* method: `GET`
|
* method: `GET`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
* OAuth scope: `read:security`
|
* OAuth scope: `read:security`
|
||||||
* Response: JSON. Returns `{"enabled": "false", "totp": false }`
|
* Response: JSON. Returns `{"settings": {"enabled": "false", "totp": false }}`
|
||||||
|
* Note: `enabled` is whether multi-factor auth is enabled for the user in general, while `totp` is one type of MFA.
|
||||||
|
|
||||||
## `/api/v1/pleroma/accounts/mfa/setup/totp`
|
## `/api/pleroma/accounts/mfa/setup/totp`
|
||||||
#### Pre-setup the MFA/TOTP method
|
#### Pre-setup the MFA/TOTP method
|
||||||
* method: `GET`
|
* method: `GET`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
* OAuth scope: `write:security`
|
* OAuth scope: `write:security`
|
||||||
* Response: JSON. Returns `{"key": [secret_key], "provisioning_uri": "[qr code uri]" }` when successful, otherwise returns HTTP 422 `{"error": "error_msg"}`
|
* Response: JSON. Returns `{"key": [secret_key], "provisioning_uri": "[qr code uri]" }` when successful, otherwise returns HTTP 422 `{"error": "error_msg"}`
|
||||||
|
|
||||||
## `/api/v1/pleroma/accounts/mfa/confirm/totp`
|
## `/api/pleroma/accounts/mfa/confirm/totp`
|
||||||
#### Confirms & enables MFA/TOTP support for user account.
|
#### Confirms & enables MFA/TOTP support for user account.
|
||||||
* method: `POST`
|
* method: `POST`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
|
@ -113,7 +114,7 @@ The `/api/v1/pleroma/*` path is backwards compatible with `/api/pleroma/*` (`/ap
|
||||||
* Response: JSON. Returns `{}` if the enable was successful, HTTP 422 `{"error": "[error message]"}` otherwise
|
* Response: JSON. Returns `{}` if the enable was successful, HTTP 422 `{"error": "[error message]"}` otherwise
|
||||||
|
|
||||||
|
|
||||||
## `/api/v1/pleroma/accounts/mfa/totp`
|
## `/api/pleroma/accounts/mfa/totp`
|
||||||
#### Disables MFA/TOTP method for user account.
|
#### Disables MFA/TOTP method for user account.
|
||||||
* method: `DELETE`
|
* method: `DELETE`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
|
@ -123,7 +124,7 @@ The `/api/v1/pleroma/*` path is backwards compatible with `/api/pleroma/*` (`/ap
|
||||||
* Response: JSON. Returns `{}` if the disable was successful, HTTP 422 `{"error": "[error message]"}` otherwise
|
* Response: JSON. Returns `{}` if the disable was successful, HTTP 422 `{"error": "[error message]"}` otherwise
|
||||||
* Example response: `{"error": "Invalid password."}`
|
* Example response: `{"error": "Invalid password."}`
|
||||||
|
|
||||||
## `/api/v1/pleroma/accounts/mfa/backup_codes`
|
## `/api/pleroma/accounts/mfa/backup_codes`
|
||||||
#### Generstes backup codes MFA for user account.
|
#### Generstes backup codes MFA for user account.
|
||||||
* method: `GET`
|
* method: `GET`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
|
@ -331,7 +332,7 @@ See [Admin-API](admin_api.md)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## `/api/v1/pleroma/change_email`
|
## `/api/pleroma/change_email`
|
||||||
### Change account email
|
### Change account email
|
||||||
* Method `POST`
|
* Method `POST`
|
||||||
* Authentication: required
|
* Authentication: required
|
||||||
|
@ -689,3 +690,38 @@ Emoji reactions work a lot like favourites do. They make it possible to react to
|
||||||
"url": "https://example.com/media/backups/archive-foobar-20200910T161803-QUhx6VYDRQ2wfV0SdA2Pfj_2CLM_ATUlw-D5l5TJf4Q.zip"
|
"url": "https://example.com/media/backups/archive-foobar-20200910T161803-QUhx6VYDRQ2wfV0SdA2Pfj_2CLM_ATUlw-D5l5TJf4Q.zip"
|
||||||
}]
|
}]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `GET /api/oauth_tokens`
|
||||||
|
### Retrieve a list of active sessions for the user
|
||||||
|
* Method: `GET`
|
||||||
|
* Authentication: required
|
||||||
|
* Params: none
|
||||||
|
* Response: JSON
|
||||||
|
* Example response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"app_name": "Pleroma FE",
|
||||||
|
"id": 9275,
|
||||||
|
"valid_until": "2121-11-24T15:51:08.234234"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"app_name": "Patron",
|
||||||
|
"id": 8805,
|
||||||
|
"valid_until": "2121-10-26T18:09:59.857150"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"app_name": "Soapbox FE",
|
||||||
|
"id": 9727,
|
||||||
|
"valid_until": "2121-12-25T16:52:39.692877"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## `DELETE /api/oauth_tokens/:id`
|
||||||
|
### Revoke a user session by its ID
|
||||||
|
* Method: `DELETE`
|
||||||
|
* Authentication: required
|
||||||
|
* Params: none
|
||||||
|
* Response: HTTP 200 on success, 500 on error
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Setting up a Gitlab-runner
|
||||||
|
|
||||||
|
When you push changes, a pipeline will start some automated jobs. These are done with so called [runners](https://docs.gitlab.com/runner/), services that run somewhere on a server and run these automated jobs. These jobs typically run tests and should pass. If not, you probably need to fix something.
|
||||||
|
|
||||||
|
Generally, Pleroma provides a runner, so you don't need to set up your own. However, if for whatever reason you want to set up your own, here's some high level instructions.
|
||||||
|
|
||||||
|
1. We use docker to run the jobs, so you should install that. For Debian, you need to allow non-free packages in the [source list](https://wiki.debian.org/SourcesList). Then you can install docker with `apt install docker-compose`.
|
||||||
|
2. You can [install](https://docs.gitlab.com/runner/install/index.html) and [configure](https://docs.gitlab.com/runner/register/index.html) a Gitlab-runner. It's probably easiest to install from the packages, but there are other options as well.
|
||||||
|
3. When registering the runner, you'll need some values. You can find them in the project under your own name. Choose "Settings", "CI/CD", and then expand "Runners". For executor you can choose "docker". For default image, you can use the image used in <https://git.pleroma.social/pleroma/pleroma/-/blob/develop/.gitlab-ci.yml#L1> (although it shouldn't matter much).
|
|
@ -29,4 +29,5 @@ It is required for the following Pleroma features:
|
||||||
`exiftool` is media files metadata reader/writer.
|
`exiftool` is media files metadata reader/writer.
|
||||||
|
|
||||||
It is required for the following Pleroma features:
|
It is required for the following Pleroma features:
|
||||||
* `Pleroma.Upload.Filters.Exiftool` upload filter (related config: `Plaroma.Upload/filters` in `config/config.exs`)
|
* `Pleroma.Upload.Filters.Exiftool.StripLocation` upload filter (related config: `Plaroma.Upload/filters` in `config/config.exs`)
|
||||||
|
* `Pleroma.Upload.Filters.Exiftool.ReadDescription` upload filter (related config: `Plaroma.Upload/filters` in `config/config.exs`)
|
||||||
|
|
|
@ -5,34 +5,13 @@
|
||||||
# 2. Copy this section into your Caddyfile and restart Caddy.
|
# 2. Copy this section into your Caddyfile and restart Caddy.
|
||||||
|
|
||||||
example.tld {
|
example.tld {
|
||||||
log /var/log/caddy/pleroma_access.log
|
log {
|
||||||
errors /var/log/caddy/pleroma_error.log
|
output file /var/log/caddy/pleroma.log
|
||||||
|
}
|
||||||
|
|
||||||
gzip
|
encode gzip
|
||||||
|
|
||||||
# this is explicitly IPv4 since Pleroma.Web.Endpoint binds on IPv4 only
|
# this is explicitly IPv4 since Pleroma.Web.Endpoint binds on IPv4 only
|
||||||
# and `localhost.` resolves to [::0] on some systems: see issue #930
|
# and `localhost.` resolves to [::0] on some systems: see issue #930
|
||||||
proxy / 127.0.0.1:4000 {
|
reverse_proxy 127.0.0.1:4000
|
||||||
websocket
|
|
||||||
transparent
|
|
||||||
}
|
|
||||||
|
|
||||||
tls {
|
|
||||||
# Remove the rest of the lines in here, if you want to support older devices
|
|
||||||
key_type p256
|
|
||||||
ciphers ECDHE-ECDSA-WITH-CHACHA20-POLY1305 ECDHE-RSA-WITH-CHACHA20-POLY1305 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256
|
|
||||||
}
|
|
||||||
|
|
||||||
# If you do not want to use the mediaproxy function, remove these lines.
|
|
||||||
# To use this directive, you need the http.cache plugin for Caddy.
|
|
||||||
cache {
|
|
||||||
match_path /media
|
|
||||||
default_max_age 720m
|
|
||||||
}
|
|
||||||
|
|
||||||
cache {
|
|
||||||
match_path /proxy
|
|
||||||
default_max_age 720m
|
|
||||||
}
|
|
||||||
# Stop removing lines here.
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,19 @@ server {
|
||||||
proxy_pass http://phoenix;
|
proxy_pass http://phoenix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Uncomment this if you want notice compatibility routes for frontends like Soapbox.
|
||||||
|
# location ~ ^/@[^/]+/([^/]+)$ {
|
||||||
|
# proxy_pass http://phoenix/notice/$1;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# location ~ ^/@[^/]+/posts/([^/]+)$ {
|
||||||
|
# proxy_pass http://phoenix/notice/$1;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# location ~ ^/[^/]+/status/([^/]+)$ {
|
||||||
|
# proxy_pass http://phoenix/notice/$1;
|
||||||
|
# }
|
||||||
|
|
||||||
location ~ ^/(media|proxy) {
|
location ~ ^/(media|proxy) {
|
||||||
proxy_cache pleroma_media_cache;
|
proxy_cache pleroma_media_cache;
|
||||||
slice 1m;
|
slice 1m;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Pleroma do
|
defmodule Mix.Pleroma do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.App do
|
defmodule Mix.Tasks.Pleroma.App do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Benchmark do
|
defmodule Mix.Tasks.Pleroma.Benchmark do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Config do
|
defmodule Mix.Tasks.Pleroma.Config do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.CountStatuses do
|
defmodule Mix.Tasks.Pleroma.CountStatuses do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Database do
|
defmodule Mix.Tasks.Pleroma.Database do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Digest do
|
defmodule Mix.Tasks.Pleroma.Digest do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Docs do
|
defmodule Mix.Tasks.Pleroma.Docs do
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-onl
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Ecto do
|
defmodule Mix.Tasks.Pleroma.Ecto do
|
||||||
@doc """
|
@doc """
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-onl
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Ecto.Migrate do
|
defmodule Mix.Tasks.Pleroma.Ecto.Migrate do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-onl
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Ecto.Rollback do
|
defmodule Mix.Tasks.Pleroma.Ecto.Rollback do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Email do
|
defmodule Mix.Tasks.Pleroma.Email do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Emoji do
|
defmodule Mix.Tasks.Pleroma.Emoji do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Frontend do
|
defmodule Mix.Tasks.Pleroma.Frontend do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Instance do
|
defmodule Mix.Tasks.Pleroma.Instance do
|
||||||
|
@ -34,7 +34,8 @@ def run(["gen" | rest]) do
|
||||||
static_dir: :string,
|
static_dir: :string,
|
||||||
listen_ip: :string,
|
listen_ip: :string,
|
||||||
listen_port: :string,
|
listen_port: :string,
|
||||||
strip_uploads: :string,
|
strip_uploads_location: :string,
|
||||||
|
read_uploads_description: :string,
|
||||||
anonymize_uploads: :string,
|
anonymize_uploads: :string,
|
||||||
dedupe_uploads: :string
|
dedupe_uploads: :string
|
||||||
],
|
],
|
||||||
|
@ -161,7 +162,7 @@ def run(["gen" | rest]) do
|
||||||
)
|
)
|
||||||
|> Path.expand()
|
|> Path.expand()
|
||||||
|
|
||||||
{strip_uploads_message, strip_uploads_default} =
|
{strip_uploads_location_message, strip_uploads_location_default} =
|
||||||
if Pleroma.Utils.command_available?("exiftool") do
|
if Pleroma.Utils.command_available?("exiftool") do
|
||||||
{"Do you want to strip location (GPS) data from uploaded images? This requires exiftool, it was detected as installed. (y/n)",
|
{"Do you want to strip location (GPS) data from uploaded images? This requires exiftool, it was detected as installed. (y/n)",
|
||||||
"y"}
|
"y"}
|
||||||
|
@ -170,12 +171,29 @@ def run(["gen" | rest]) do
|
||||||
"n"}
|
"n"}
|
||||||
end
|
end
|
||||||
|
|
||||||
strip_uploads =
|
strip_uploads_location =
|
||||||
get_option(
|
get_option(
|
||||||
options,
|
options,
|
||||||
:strip_uploads,
|
:strip_uploads_location,
|
||||||
strip_uploads_message,
|
strip_uploads_location_message,
|
||||||
strip_uploads_default
|
strip_uploads_location_default
|
||||||
|
) === "y"
|
||||||
|
|
||||||
|
{read_uploads_description_message, read_uploads_description_default} =
|
||||||
|
if Pleroma.Utils.command_available?("exiftool") do
|
||||||
|
{"Do you want to read data from uploaded files so clients can use it to prefill fields like image description? This requires exiftool, it was detected as installed. (y/n)",
|
||||||
|
"y"}
|
||||||
|
else
|
||||||
|
{"Do you want to read data from uploaded files so clients can use it to prefill fields like image description? This requires exiftool, it was detected as not installed, please install it if you answer yes. (y/n)",
|
||||||
|
"n"}
|
||||||
|
end
|
||||||
|
|
||||||
|
read_uploads_description =
|
||||||
|
get_option(
|
||||||
|
options,
|
||||||
|
:read_uploads_description,
|
||||||
|
read_uploads_description_message,
|
||||||
|
read_uploads_description_default
|
||||||
) === "y"
|
) === "y"
|
||||||
|
|
||||||
anonymize_uploads =
|
anonymize_uploads =
|
||||||
|
@ -229,7 +247,8 @@ def run(["gen" | rest]) do
|
||||||
listen_port: listen_port,
|
listen_port: listen_port,
|
||||||
upload_filters:
|
upload_filters:
|
||||||
upload_filters(%{
|
upload_filters(%{
|
||||||
strip: strip_uploads,
|
strip_location: strip_uploads_location,
|
||||||
|
read_description: read_uploads_description,
|
||||||
anonymize: anonymize_uploads,
|
anonymize: anonymize_uploads,
|
||||||
dedupe: dedupe_uploads
|
dedupe: dedupe_uploads
|
||||||
})
|
})
|
||||||
|
@ -297,12 +316,19 @@ defp write_robots_txt(static_dir, indexable, template_dir) do
|
||||||
|
|
||||||
defp upload_filters(filters) when is_map(filters) do
|
defp upload_filters(filters) when is_map(filters) do
|
||||||
enabled_filters =
|
enabled_filters =
|
||||||
if filters.strip do
|
if filters.strip_location do
|
||||||
[Pleroma.Upload.Filter.Exiftool]
|
[Pleroma.Upload.Filter.Exiftool.StripLocation]
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
enabled_filters =
|
||||||
|
if filters.read_description do
|
||||||
|
enabled_filters ++ [Pleroma.Upload.Filter.Exiftool.ReadDescription]
|
||||||
|
else
|
||||||
|
enabled_filters
|
||||||
|
end
|
||||||
|
|
||||||
enabled_filters =
|
enabled_filters =
|
||||||
if filters.anonymize do
|
if filters.anonymize do
|
||||||
enabled_filters ++ [Pleroma.Upload.Filter.AnonymizeFilename]
|
enabled_filters ++ [Pleroma.Upload.Filter.AnonymizeFilename]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.NotificationSettings do
|
defmodule Mix.Tasks.Pleroma.NotificationSettings do
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.OpenapiSpec do
|
defmodule Mix.Tasks.Pleroma.OpenapiSpec do
|
||||||
def run([path]) do
|
def run([path]) do
|
||||||
# Load Pleroma application to get version info
|
# Load Pleroma application to get version info
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.RefreshCounterCache do
|
defmodule Mix.Tasks.Pleroma.RefreshCounterCache do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Relay do
|
defmodule Mix.Tasks.Pleroma.Relay do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.RobotsTxt do
|
defmodule Mix.Tasks.Pleroma.RobotsTxt do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Uploads do
|
defmodule Mix.Tasks.Pleroma.Uploads do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.User do
|
defmodule Mix.Tasks.Pleroma.User do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Phoenix.Transports.WebSocket.Raw do
|
defmodule Phoenix.Transports.WebSocket.Raw do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Activity do
|
defmodule Pleroma.Activity do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Activity.HTML do
|
defmodule Pleroma.Activity.HTML do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Activity.Ir.Topics do
|
defmodule Pleroma.Activity.Ir.Topics do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Activity.Queries do
|
defmodule Pleroma.Activity.Queries do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Activity.Search do
|
defmodule Pleroma.Activity.Search do
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Announcement do
|
||||||
|
use Ecto.Schema
|
||||||
|
|
||||||
|
import Ecto.Changeset, only: [cast: 3, validate_required: 2]
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
alias Pleroma.AnnouncementReadRelationship
|
||||||
|
alias Pleroma.Repo
|
||||||
|
|
||||||
|
@type t :: %__MODULE__{}
|
||||||
|
@primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
|
||||||
|
|
||||||
|
schema "announcements" do
|
||||||
|
field(:data, :map)
|
||||||
|
field(:starts_at, :utc_datetime)
|
||||||
|
field(:ends_at, :utc_datetime)
|
||||||
|
field(:rendered, :map)
|
||||||
|
|
||||||
|
timestamps(type: :utc_datetime)
|
||||||
|
end
|
||||||
|
|
||||||
|
def change(struct, params \\ %{}) do
|
||||||
|
struct
|
||||||
|
|> cast(validate_params(struct, params), [:data, :starts_at, :ends_at, :rendered])
|
||||||
|
|> validate_required([:data])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp validate_params(struct, params) do
|
||||||
|
base_data =
|
||||||
|
%{
|
||||||
|
"content" => "",
|
||||||
|
"all_day" => false
|
||||||
|
}
|
||||||
|
|> Map.merge((struct && struct.data) || %{})
|
||||||
|
|
||||||
|
merged_data =
|
||||||
|
Map.merge(base_data, params.data)
|
||||||
|
|> Map.take(["content", "all_day"])
|
||||||
|
|
||||||
|
params
|
||||||
|
|> Map.merge(%{data: merged_data})
|
||||||
|
|> add_rendered_properties()
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_rendered_properties(params) do
|
||||||
|
{content_html, _, _} =
|
||||||
|
Pleroma.Web.CommonAPI.Utils.format_input(params.data["content"], "text/plain",
|
||||||
|
mentions_format: :full
|
||||||
|
)
|
||||||
|
|
||||||
|
rendered = %{
|
||||||
|
"content" => content_html
|
||||||
|
}
|
||||||
|
|
||||||
|
params
|
||||||
|
|> Map.put(:rendered, rendered)
|
||||||
|
end
|
||||||
|
|
||||||
|
def add(params) do
|
||||||
|
changeset = change(%__MODULE__{}, params)
|
||||||
|
|
||||||
|
Repo.insert(changeset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(announcement, params) do
|
||||||
|
changeset = change(announcement, params)
|
||||||
|
|
||||||
|
Repo.update(changeset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_all do
|
||||||
|
__MODULE__
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_paginated(%{limit: limited_number, offset: offset_number}) do
|
||||||
|
__MODULE__
|
||||||
|
|> limit(^limited_number)
|
||||||
|
|> offset(^offset_number)
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_by_id(id) do
|
||||||
|
Repo.get_by(__MODULE__, id: id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_by_id(id) do
|
||||||
|
with announcement when not is_nil(announcement) <- get_by_id(id),
|
||||||
|
{:ok, _} <- Repo.delete(announcement) do
|
||||||
|
:ok
|
||||||
|
else
|
||||||
|
_ ->
|
||||||
|
:error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_by?(announcement, user) do
|
||||||
|
AnnouncementReadRelationship.exists?(user, announcement)
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_read_by(announcement, user) do
|
||||||
|
AnnouncementReadRelationship.mark_read(user, announcement)
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_json(announcement, opts \\ []) do
|
||||||
|
extra_params =
|
||||||
|
case Keyword.fetch(opts, :for) do
|
||||||
|
{:ok, user} when not is_nil(user) ->
|
||||||
|
%{read: read_by?(announcement, user)}
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
%{}
|
||||||
|
end
|
||||||
|
|
||||||
|
admin_extra_params =
|
||||||
|
case Keyword.fetch(opts, :admin) do
|
||||||
|
{:ok, true} ->
|
||||||
|
%{pleroma: %{raw_content: announcement.data["content"]}}
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
%{}
|
||||||
|
end
|
||||||
|
|
||||||
|
base = %{
|
||||||
|
id: announcement.id,
|
||||||
|
content: announcement.rendered["content"],
|
||||||
|
starts_at: announcement.starts_at,
|
||||||
|
ends_at: announcement.ends_at,
|
||||||
|
all_day: announcement.data["all_day"],
|
||||||
|
published_at: announcement.inserted_at,
|
||||||
|
updated_at: announcement.updated_at,
|
||||||
|
mentions: [],
|
||||||
|
statuses: [],
|
||||||
|
tags: [],
|
||||||
|
emojis: [],
|
||||||
|
reactions: []
|
||||||
|
}
|
||||||
|
|
||||||
|
base
|
||||||
|
|> Map.merge(extra_params)
|
||||||
|
|> Map.merge(admin_extra_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
# "visible" means:
|
||||||
|
# starts_at < time < ends_at
|
||||||
|
def list_all_visible_when(time) do
|
||||||
|
__MODULE__
|
||||||
|
|> where([a], is_nil(a.starts_at) or a.starts_at < ^time)
|
||||||
|
|> where([a], is_nil(a.ends_at) or a.ends_at > ^time)
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_all_visible do
|
||||||
|
list_all_visible_when(DateTime.now("Etc/UTC") |> elem(1))
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,55 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.AnnouncementReadRelationship do
|
||||||
|
use Ecto.Schema
|
||||||
|
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
alias FlakeId.Ecto.CompatType
|
||||||
|
alias Pleroma.Announcement
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
|
@type t :: %__MODULE__{}
|
||||||
|
|
||||||
|
schema "announcement_read_relationships" do
|
||||||
|
belongs_to(:user, User, type: CompatType)
|
||||||
|
belongs_to(:announcement, Announcement, type: CompatType)
|
||||||
|
|
||||||
|
timestamps(updated_at: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_read(user, announcement) do
|
||||||
|
%__MODULE__{}
|
||||||
|
|> cast(%{user_id: user.id, announcement_id: announcement.id}, [:user_id, :announcement_id])
|
||||||
|
|> validate_required([:user_id, :announcement_id])
|
||||||
|
|> foreign_key_constraint(:user_id)
|
||||||
|
|> foreign_key_constraint(:announcement_id)
|
||||||
|
|> unique_constraint([:user_id, :announcement_id])
|
||||||
|
|> Repo.insert()
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_unread(user, announcement) do
|
||||||
|
with relationship <- get(user, announcement),
|
||||||
|
{:exists, true} <- {:exists, not is_nil(relationship)},
|
||||||
|
{:ok, _} <- Repo.delete(relationship) do
|
||||||
|
:ok
|
||||||
|
else
|
||||||
|
{:exists, false} ->
|
||||||
|
:ok
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
:error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(user, announcement) do
|
||||||
|
Repo.get_by(__MODULE__, user_id: user.id, announcement_id: announcement.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def exists?(user, announcement) do
|
||||||
|
not is_nil(get(user, announcement))
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Application do
|
defmodule Pleroma.Application do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.ApplicationRequirements do
|
defmodule Pleroma.ApplicationRequirements do
|
||||||
|
@ -164,7 +164,8 @@ defp do_check_rum!(setting, migrate) do
|
||||||
|
|
||||||
defp check_system_commands!(:ok) do
|
defp check_system_commands!(:ok) do
|
||||||
filter_commands_statuses = [
|
filter_commands_statuses = [
|
||||||
check_filter(Pleroma.Upload.Filter.Exiftool, "exiftool"),
|
check_filter(Pleroma.Upload.Filter.Exiftool.StripLocation, "exiftool"),
|
||||||
|
check_filter(Pleroma.Upload.Filter.Exiftool.ReadDescription, "exiftool"),
|
||||||
check_filter(Pleroma.Upload.Filter.Mogrify, "mogrify"),
|
check_filter(Pleroma.Upload.Filter.Mogrify, "mogrify"),
|
||||||
check_filter(Pleroma.Upload.Filter.Mogrifun, "mogrify"),
|
check_filter(Pleroma.Upload.Filter.Mogrifun, "mogrify"),
|
||||||
check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "mogrify"),
|
check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "mogrify"),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.BBS.Authenticator do
|
defmodule Pleroma.BBS.Authenticator do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.BBS.Handler do
|
defmodule Pleroma.BBS.Handler do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Bookmark do
|
defmodule Pleroma.Bookmark do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Caching do
|
defmodule Pleroma.Caching do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Captcha do
|
defmodule Pleroma.Captcha do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Captcha.Kocaptcha do
|
defmodule Pleroma.Captcha.Kocaptcha do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Captcha.Native do
|
defmodule Pleroma.Captcha.Native do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Captcha.Service do
|
defmodule Pleroma.Captcha.Service do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Chat do
|
defmodule Pleroma.Chat do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Chat.MessageReference do
|
defmodule Pleroma.Chat.MessageReference do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Clippy do
|
defmodule Pleroma.Clippy do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Config do
|
defmodule Pleroma.Config do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Config.DeprecationWarnings do
|
defmodule Pleroma.Config.DeprecationWarnings do
|
||||||
|
@ -20,6 +20,43 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
||||||
"\n* `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`"}
|
"\n* `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`"}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def check_exiftool_filter do
|
||||||
|
filters = Config.get([Pleroma.Upload]) |> Keyword.get(:filters, [])
|
||||||
|
|
||||||
|
if Pleroma.Upload.Filter.Exiftool in filters do
|
||||||
|
Logger.warn("""
|
||||||
|
!!!DEPRECATION WARNING!!!
|
||||||
|
Your config is using Exiftool as a filter instead of Exiftool.StripLocation. This should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, Pleroma.Upload,
|
||||||
|
filters: [Pleroma.Upload.Filter.Exiftool]
|
||||||
|
```
|
||||||
|
|
||||||
|
Is now
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, Pleroma.Upload,
|
||||||
|
filters: [Pleroma.Upload.Filter.Exiftool.StripLocation]
|
||||||
|
```
|
||||||
|
""")
|
||||||
|
|
||||||
|
new_config =
|
||||||
|
filters
|
||||||
|
|> Enum.map(fn
|
||||||
|
Pleroma.Upload.Filter.Exiftool -> Pleroma.Upload.Filter.Exiftool.StripLocation
|
||||||
|
filter -> filter
|
||||||
|
end)
|
||||||
|
|
||||||
|
Config.put([Pleroma.Upload, :filters], new_config)
|
||||||
|
|
||||||
|
:error
|
||||||
|
else
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def check_simple_policy_tuples do
|
def check_simple_policy_tuples do
|
||||||
has_strings =
|
has_strings =
|
||||||
Config.get([:mrf_simple])
|
Config.get([:mrf_simple])
|
||||||
|
@ -180,7 +217,8 @@ def warn do
|
||||||
check_old_chat_shoutbox(),
|
check_old_chat_shoutbox(),
|
||||||
check_quarantined_instances_tuples(),
|
check_quarantined_instances_tuples(),
|
||||||
check_transparency_exclusions_tuples(),
|
check_transparency_exclusions_tuples(),
|
||||||
check_simple_policy_tuples()
|
check_simple_policy_tuples(),
|
||||||
|
check_exiftool_filter()
|
||||||
]
|
]
|
||||||
|> Enum.reduce(:ok, fn
|
|> Enum.reduce(:ok, fn
|
||||||
:ok, :ok -> :ok
|
:ok, :ok -> :ok
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Config.Getting do
|
defmodule Pleroma.Config.Getting do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Config.Helpers do
|
defmodule Pleroma.Config.Helpers do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Config.Holder do
|
defmodule Pleroma.Config.Holder do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Config.Loader do
|
defmodule Pleroma.Config.Loader do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Config.Oban do
|
defmodule Pleroma.Config.Oban do
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Config.ReleaseRuntimeProvider do
|
defmodule Pleroma.Config.ReleaseRuntimeProvider do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
Imports runtime config and `{env}.exported_from_db.secret.exs` for releases.
|
Imports runtime config and `{env}.exported_from_db.secret.exs` for releases.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Config.TransferTask do
|
defmodule Pleroma.Config.TransferTask do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.ConfigDB do
|
defmodule Pleroma.ConfigDB do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Constants do
|
defmodule Pleroma.Constants do
|
||||||
|
@ -27,4 +27,10 @@ defmodule Pleroma.Constants do
|
||||||
do:
|
do:
|
||||||
~w(index.html robots.txt static static-fe finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc embed.js embed.css)
|
~w(index.html robots.txt static static-fe finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc embed.js embed.css)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# basic regex, just there to weed out potential mistakes
|
||||||
|
# https://datatracker.ietf.org/doc/html/rfc2045#section-5.1
|
||||||
|
const(mime_regex,
|
||||||
|
do: ~r/^[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+\/[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+(; .*)?$/
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Conversation do
|
defmodule Pleroma.Conversation do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Conversation.Participation do
|
defmodule Pleroma.Conversation.Participation do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Conversation.Participation.RecipientShip do
|
defmodule Pleroma.Conversation.Participation.RecipientShip do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.CounterCache do
|
defmodule Pleroma.CounterCache do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.DataMigration do
|
defmodule Pleroma.DataMigration do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Delivery do
|
defmodule Pleroma.Delivery do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Docs.Generator do
|
defmodule Pleroma.Docs.Generator do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Docs.JSON do
|
defmodule Pleroma.Docs.JSON do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Docs.Markdown do
|
defmodule Pleroma.Docs.Markdown do
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Docs.Translator do
|
||||||
|
require Pleroma.Docs.Translator.Compiler
|
||||||
|
require Pleroma.Web.Gettext
|
||||||
|
|
||||||
|
@before_compile Pleroma.Docs.Translator.Compiler
|
||||||
|
end
|
|
@ -0,0 +1,119 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Docs.Translator.Compiler do
|
||||||
|
@external_resource "config/description.exs"
|
||||||
|
@raw_config Pleroma.Config.Loader.read("config/description.exs")
|
||||||
|
@raw_descriptions @raw_config[:pleroma][:config_description]
|
||||||
|
|
||||||
|
defmacro __before_compile__(_env) do
|
||||||
|
strings =
|
||||||
|
__MODULE__.descriptions()
|
||||||
|
|> __MODULE__.extract_strings()
|
||||||
|
|
||||||
|
quote do
|
||||||
|
def placeholder do
|
||||||
|
unquote do
|
||||||
|
Enum.map(
|
||||||
|
strings,
|
||||||
|
fn {path, type, string} ->
|
||||||
|
ctxt = msgctxt_for(path, type)
|
||||||
|
|
||||||
|
quote do
|
||||||
|
Pleroma.Web.Gettext.dpgettext_noop(
|
||||||
|
"config_descriptions",
|
||||||
|
unquote(ctxt),
|
||||||
|
unquote(string)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def descriptions do
|
||||||
|
Pleroma.Web.ActivityPub.MRF.config_descriptions()
|
||||||
|
|> Enum.reduce(@raw_descriptions, fn description, acc -> [description | acc] end)
|
||||||
|
|> Pleroma.Docs.Generator.convert_to_strings()
|
||||||
|
end
|
||||||
|
|
||||||
|
def extract_strings(descriptions) do
|
||||||
|
descriptions
|
||||||
|
|> Enum.reduce(%{strings: [], path: []}, &process_item/2)
|
||||||
|
|> Map.get(:strings)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp process_item(entity, acc) do
|
||||||
|
current_level =
|
||||||
|
acc
|
||||||
|
|> process_desc(entity)
|
||||||
|
|> process_label(entity)
|
||||||
|
|
||||||
|
process_children(entity, current_level)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp process_desc(acc, %{description: desc} = item) do
|
||||||
|
%{
|
||||||
|
strings: [{acc.path ++ [key_for(item)], "description", desc} | acc.strings],
|
||||||
|
path: acc.path
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp process_desc(acc, _) do
|
||||||
|
acc
|
||||||
|
end
|
||||||
|
|
||||||
|
defp process_label(acc, %{label: label} = item) do
|
||||||
|
%{
|
||||||
|
strings: [{acc.path ++ [key_for(item)], "label", label} | acc.strings],
|
||||||
|
path: acc.path
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp process_label(acc, _) do
|
||||||
|
acc
|
||||||
|
end
|
||||||
|
|
||||||
|
defp process_children(%{children: children} = item, acc) do
|
||||||
|
current_level = Map.put(acc, :path, acc.path ++ [key_for(item)])
|
||||||
|
|
||||||
|
children
|
||||||
|
|> Enum.reduce(current_level, &process_item/2)
|
||||||
|
|> Map.put(:path, acc.path)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp process_children(_, acc) do
|
||||||
|
acc
|
||||||
|
end
|
||||||
|
|
||||||
|
def msgctxt_for(path, type) do
|
||||||
|
"config #{type} at #{Enum.join(path, " > ")}"
|
||||||
|
end
|
||||||
|
|
||||||
|
defp convert_group({_, group}) do
|
||||||
|
group
|
||||||
|
end
|
||||||
|
|
||||||
|
defp convert_group(group) do
|
||||||
|
group
|
||||||
|
end
|
||||||
|
|
||||||
|
def key_for(%{group: group, key: key}) do
|
||||||
|
"#{convert_group(group)}-#{key}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def key_for(%{group: group}) do
|
||||||
|
convert_group(group)
|
||||||
|
end
|
||||||
|
|
||||||
|
def key_for(%{key: key}) do
|
||||||
|
key
|
||||||
|
end
|
||||||
|
|
||||||
|
def key_for(_) do
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import EctoEnum
|
import EctoEnum
|
||||||
|
@ -10,7 +10,8 @@
|
||||||
reblog_mute: 3,
|
reblog_mute: 3,
|
||||||
notification_mute: 4,
|
notification_mute: 4,
|
||||||
inverse_subscription: 5,
|
inverse_subscription: 5,
|
||||||
suggestion_dismiss: 6
|
suggestion_dismiss: 6,
|
||||||
|
endorsement: 7
|
||||||
)
|
)
|
||||||
|
|
||||||
defenum(Pleroma.FollowingRelationship.State,
|
defenum(Pleroma.FollowingRelationship.State,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.DateTime do
|
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.DateTime do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.Emoji do
|
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.Emoji do
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.MIME do
|
||||||
|
use Ecto.Type
|
||||||
|
|
||||||
|
require Pleroma.Constants
|
||||||
|
|
||||||
|
def type, do: :string
|
||||||
|
|
||||||
|
def cast(mime) when is_binary(mime) do
|
||||||
|
if mime =~ Pleroma.Constants.mime_regex() do
|
||||||
|
{:ok, mime}
|
||||||
|
else
|
||||||
|
{:ok, "application/octet-stream"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def cast(_), do: :error
|
||||||
|
|
||||||
|
def dump(data), do: {:ok, data}
|
||||||
|
|
||||||
|
def load(data), do: {:ok, data}
|
||||||
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ObjectID do
|
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ObjectID do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients do
|
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.SafeText do
|
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.SafeText do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.Uri do
|
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.Uri do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.EctoType.Config.Atom do
|
defmodule Pleroma.EctoType.Config.Atom do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.EctoType.Config.BinaryValue do
|
defmodule Pleroma.EctoType.Config.BinaryValue do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Emails.AdminEmail do
|
defmodule Pleroma.Emails.AdminEmail do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Emails.Mailer do
|
defmodule Pleroma.Emails.Mailer do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Emails.NewUsersDigestEmail do
|
defmodule Pleroma.Emails.NewUsersDigestEmail do
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Emails.UserEmail do
|
defmodule Pleroma.Emails.UserEmail do
|
||||||
@moduledoc "User emails"
|
@moduledoc "User emails"
|
||||||
|
|
||||||
|
require Pleroma.Web.Gettext
|
||||||
|
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.Endpoint
|
alias Pleroma.Web.Endpoint
|
||||||
|
alias Pleroma.Web.Gettext
|
||||||
alias Pleroma.Web.Router
|
alias Pleroma.Web.Router
|
||||||
|
|
||||||
import Swoosh.Email
|
import Swoosh.Email
|
||||||
|
@ -27,30 +30,76 @@ defp recipient(%User{} = user), do: recipient(user.email, user.name)
|
||||||
|
|
||||||
@spec welcome(User.t(), map()) :: Swoosh.Email.t()
|
@spec welcome(User.t(), map()) :: Swoosh.Email.t()
|
||||||
def welcome(user, opts \\ %{}) do
|
def welcome(user, opts \\ %{}) do
|
||||||
|
Gettext.with_locale_or_default user.language do
|
||||||
new()
|
new()
|
||||||
|> to(recipient(user))
|
|> to(recipient(user))
|
||||||
|> from(Map.get(opts, :sender, sender()))
|
|> from(Map.get(opts, :sender, sender()))
|
||||||
|> subject(Map.get(opts, :subject, "Welcome to #{instance_name()}!"))
|
|> subject(
|
||||||
|> html_body(Map.get(opts, :html, "Welcome to #{instance_name()}!"))
|
Map.get(
|
||||||
|> text_body(Map.get(opts, :text, "Welcome to #{instance_name()}!"))
|
opts,
|
||||||
|
:subject,
|
||||||
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"welcome email subject",
|
||||||
|
"Welcome to %{instance_name}!",
|
||||||
|
instance_name: instance_name()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|> html_body(
|
||||||
|
Map.get(
|
||||||
|
opts,
|
||||||
|
:html,
|
||||||
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"welcome email html body",
|
||||||
|
"Welcome to %{instance_name}!",
|
||||||
|
instance_name: instance_name()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|> text_body(
|
||||||
|
Map.get(
|
||||||
|
opts,
|
||||||
|
:text,
|
||||||
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"welcome email text body",
|
||||||
|
"Welcome to %{instance_name}!",
|
||||||
|
instance_name: instance_name()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def password_reset_email(user, token) when is_binary(token) do
|
def password_reset_email(user, token) when is_binary(token) do
|
||||||
|
Gettext.with_locale_or_default user.language do
|
||||||
password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token)
|
password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token)
|
||||||
|
|
||||||
html_body = """
|
html_body =
|
||||||
<h3>Reset your password at #{instance_name()}</h3>
|
Gettext.dpgettext(
|
||||||
<p>Someone has requested password change for your account at #{instance_name()}.</p>
|
"static_pages",
|
||||||
<p>If it was you, visit the following link to proceed: <a href="#{password_reset_url}">reset password</a>.</p>
|
"password reset email body",
|
||||||
<p>If it was someone else, nothing to worry about: your data is secure and your password has not been changed.</p>
|
|
||||||
"""
|
"""
|
||||||
|
<h3>Reset your password at %{instance_name}</h3>
|
||||||
|
<p>Someone has requested password change for your account at %{instance_name}.</p>
|
||||||
|
<p>If it was you, visit the following link to proceed: <a href="%{password_reset_url}">reset password</a>.</p>
|
||||||
|
<p>If it was someone else, nothing to worry about: your data is secure and your password has not been changed.</p>
|
||||||
|
""",
|
||||||
|
instance_name: instance_name(),
|
||||||
|
password_reset_url: password_reset_url
|
||||||
|
)
|
||||||
|
|
||||||
new()
|
new()
|
||||||
|> to(recipient(user))
|
|> to(recipient(user))
|
||||||
|> from(sender())
|
|> from(sender())
|
||||||
|> subject("Password reset")
|
|> subject(
|
||||||
|
Gettext.dpgettext("static_pages", "password reset email subject", "Password reset")
|
||||||
|
)
|
||||||
|> html_body(html_body)
|
|> html_body(html_body)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def user_invitation_email(
|
def user_invitation_email(
|
||||||
user,
|
user,
|
||||||
|
@ -58,6 +107,7 @@ def user_invitation_email(
|
||||||
to_email,
|
to_email,
|
||||||
to_name \\ nil
|
to_name \\ nil
|
||||||
) do
|
) do
|
||||||
|
Gettext.with_locale_or_default user.language do
|
||||||
registration_url =
|
registration_url =
|
||||||
Router.Helpers.redirect_url(
|
Router.Helpers.redirect_url(
|
||||||
Endpoint,
|
Endpoint,
|
||||||
|
@ -65,20 +115,37 @@ def user_invitation_email(
|
||||||
user_invite_token.token
|
user_invite_token.token
|
||||||
)
|
)
|
||||||
|
|
||||||
html_body = """
|
html_body =
|
||||||
<h3>You are invited to #{instance_name()}</h3>
|
Gettext.dpgettext(
|
||||||
<p>#{user.name} invites you to join #{instance_name()}, an instance of Pleroma federated social networking platform.</p>
|
"static_pages",
|
||||||
<p>Click the following link to register: <a href="#{registration_url}">accept invitation</a>.</p>
|
"user invitation email body",
|
||||||
"""
|
"""
|
||||||
|
<h3>You are invited to %{instance_name}</h3>
|
||||||
|
<p>%{inviter_name} invites you to join %{instance_name}, an instance of Pleroma federated social networking platform.</p>
|
||||||
|
<p>Click the following link to register: <a href="%{registration_url}">accept invitation</a>.</p>
|
||||||
|
""",
|
||||||
|
instance_name: instance_name(),
|
||||||
|
inviter_name: user.name,
|
||||||
|
registration_url: registration_url
|
||||||
|
)
|
||||||
|
|
||||||
new()
|
new()
|
||||||
|> to(recipient(to_email, to_name))
|
|> to(recipient(to_email, to_name))
|
||||||
|> from(sender())
|
|> from(sender())
|
||||||
|> subject("Invitation to #{instance_name()}")
|
|> subject(
|
||||||
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"user invitation email subject",
|
||||||
|
"Invitation to %{instance_name}",
|
||||||
|
instance_name: instance_name()
|
||||||
|
)
|
||||||
|
)
|
||||||
|> html_body(html_body)
|
|> html_body(html_body)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def account_confirmation_email(user) do
|
def account_confirmation_email(user) do
|
||||||
|
Gettext.with_locale_or_default user.language do
|
||||||
confirmation_url =
|
confirmation_url =
|
||||||
Router.Helpers.confirm_email_url(
|
Router.Helpers.confirm_email_url(
|
||||||
Endpoint,
|
Endpoint,
|
||||||
|
@ -87,45 +154,90 @@ def account_confirmation_email(user) do
|
||||||
to_string(user.confirmation_token)
|
to_string(user.confirmation_token)
|
||||||
)
|
)
|
||||||
|
|
||||||
html_body = """
|
html_body =
|
||||||
<h3>Thank you for registering on #{instance_name()}</h3>
|
Gettext.dpgettext(
|
||||||
<p>Email confirmation is required to activate the account.</p>
|
"static_pages",
|
||||||
<p>Please click the following link to <a href="#{confirmation_url}">activate your account</a>.</p>
|
"confirmation email body",
|
||||||
"""
|
"""
|
||||||
|
<h3>Thank you for registering on %{instance_name}</h3>
|
||||||
|
<p>Email confirmation is required to activate the account.</p>
|
||||||
|
<p>Please click the following link to <a href="%{confirmation_url}">activate your account</a>.</p>
|
||||||
|
""",
|
||||||
|
instance_name: instance_name(),
|
||||||
|
confirmation_url: confirmation_url
|
||||||
|
)
|
||||||
|
|
||||||
new()
|
new()
|
||||||
|> to(recipient(user))
|
|> to(recipient(user))
|
||||||
|> from(sender())
|
|> from(sender())
|
||||||
|> subject("#{instance_name()} account confirmation")
|
|> subject(
|
||||||
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"confirmation email subject",
|
||||||
|
"%{instance_name} account confirmation",
|
||||||
|
instance_name: instance_name()
|
||||||
|
)
|
||||||
|
)
|
||||||
|> html_body(html_body)
|
|> html_body(html_body)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def approval_pending_email(user) do
|
def approval_pending_email(user) do
|
||||||
html_body = """
|
Gettext.with_locale_or_default user.language do
|
||||||
<h3>Awaiting Approval</h3>
|
html_body =
|
||||||
<p>Your account at #{instance_name()} is being reviewed by staff. You will receive another email once your account is approved.</p>
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"approval pending email body",
|
||||||
"""
|
"""
|
||||||
|
<h3>Awaiting Approval</h3>
|
||||||
|
<p>Your account at %{instance_name} is being reviewed by staff. You will receive another email once your account is approved.</p>
|
||||||
|
""",
|
||||||
|
instance_name: instance_name()
|
||||||
|
)
|
||||||
|
|
||||||
new()
|
new()
|
||||||
|> to(recipient(user))
|
|> to(recipient(user))
|
||||||
|> from(sender())
|
|> from(sender())
|
||||||
|> subject("Your account is awaiting approval")
|
|> subject(
|
||||||
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"approval pending email subject",
|
||||||
|
"Your account is awaiting approval"
|
||||||
|
)
|
||||||
|
)
|
||||||
|> html_body(html_body)
|
|> html_body(html_body)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def successful_registration_email(user) do
|
def successful_registration_email(user) do
|
||||||
html_body = """
|
Gettext.with_locale_or_default user.language do
|
||||||
<h3>Hello @#{user.nickname},</h3>
|
html_body =
|
||||||
<p>Your account at #{instance_name()} has been registered successfully.</p>
|
Gettext.dpgettext(
|
||||||
<p>No further action is required to activate your account.</p>
|
"static_pages",
|
||||||
|
"successful registration email body",
|
||||||
"""
|
"""
|
||||||
|
<h3>Hello @%{nickname},</h3>
|
||||||
|
<p>Your account at %{instance_name} has been registered successfully.</p>
|
||||||
|
<p>No further action is required to activate your account.</p>
|
||||||
|
""",
|
||||||
|
nickname: user.nickname,
|
||||||
|
instance_name: instance_name()
|
||||||
|
)
|
||||||
|
|
||||||
new()
|
new()
|
||||||
|> to(recipient(user))
|
|> to(recipient(user))
|
||||||
|> from(sender())
|
|> from(sender())
|
||||||
|> subject("Account registered on #{instance_name()}")
|
|> subject(
|
||||||
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"successful registration email subject",
|
||||||
|
"Account registered on %{instance_name}",
|
||||||
|
instance_name: instance_name()
|
||||||
|
)
|
||||||
|
)
|
||||||
|> html_body(html_body)
|
|> html_body(html_body)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Email used in digest email notifications
|
Email used in digest email notifications
|
||||||
|
@ -134,6 +246,7 @@ def successful_registration_email(user) do
|
||||||
"""
|
"""
|
||||||
@spec digest_email(User.t()) :: Swoosh.Email.t() | nil
|
@spec digest_email(User.t()) :: Swoosh.Email.t() | nil
|
||||||
def digest_email(user) do
|
def digest_email(user) do
|
||||||
|
Gettext.with_locale_or_default user.language do
|
||||||
notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
|
notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
|
||||||
|
|
||||||
mentions =
|
mentions =
|
||||||
|
@ -193,12 +306,20 @@ def digest_email(user) do
|
||||||
new()
|
new()
|
||||||
|> to(recipient(user))
|
|> to(recipient(user))
|
||||||
|> from(sender())
|
|> from(sender())
|
||||||
|> subject("Your digest from #{instance_name()}")
|
|> subject(
|
||||||
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"digest email subject",
|
||||||
|
"Your digest from %{instance_name}",
|
||||||
|
instance_name: instance_name()
|
||||||
|
)
|
||||||
|
)
|
||||||
|> put_layout(false)
|
|> put_layout(false)
|
||||||
|> render_body("digest.html", html_data)
|
|> render_body("digest.html", html_data)
|
||||||
|> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.svg", type: :inline))
|
|> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.svg", type: :inline))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp format_links(str) do
|
defp format_links(str) do
|
||||||
re = ~r/<a.+href=['"].*>/iU
|
re = ~r/<a.+href=['"].*>/iU
|
||||||
|
@ -226,27 +347,47 @@ def unsubscribe_url(user, notifications_type) do
|
||||||
|
|
||||||
def backup_is_ready_email(backup, admin_user_id \\ nil) do
|
def backup_is_ready_email(backup, admin_user_id \\ nil) do
|
||||||
%{user: user} = Pleroma.Repo.preload(backup, :user)
|
%{user: user} = Pleroma.Repo.preload(backup, :user)
|
||||||
|
|
||||||
|
Gettext.with_locale_or_default user.language do
|
||||||
download_url = Pleroma.Web.PleromaAPI.BackupView.download_url(backup)
|
download_url = Pleroma.Web.PleromaAPI.BackupView.download_url(backup)
|
||||||
|
|
||||||
html_body =
|
html_body =
|
||||||
if is_nil(admin_user_id) do
|
if is_nil(admin_user_id) do
|
||||||
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"account archive email body - self-requested",
|
||||||
"""
|
"""
|
||||||
<p>You requested a full backup of your Pleroma account. It's ready for download:</p>
|
<p>You requested a full backup of your Pleroma account. It's ready for download:</p>
|
||||||
<p><a href="#{download_url}">#{download_url}</a></p>
|
<p><a href="%{download_url}">%{download_url}</a></p>
|
||||||
"""
|
""",
|
||||||
|
download_url: download_url
|
||||||
|
)
|
||||||
else
|
else
|
||||||
admin = Pleroma.Repo.get(User, admin_user_id)
|
admin = Pleroma.Repo.get(User, admin_user_id)
|
||||||
|
|
||||||
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"account archive email body - admin requested",
|
||||||
"""
|
"""
|
||||||
<p>Admin @#{admin.nickname} requested a full backup of your Pleroma account. It's ready for download:</p>
|
<p>Admin @%{admin_nickname} requested a full backup of your Pleroma account. It's ready for download:</p>
|
||||||
<p><a href="#{download_url}">#{download_url}</a></p>
|
<p><a href="%{download_url}">%{download_url}</a></p>
|
||||||
"""
|
""",
|
||||||
|
admin_nickname: admin.nickname,
|
||||||
|
download_url: download_url
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
new()
|
new()
|
||||||
|> to(recipient(user))
|
|> to(recipient(user))
|
||||||
|> from(sender())
|
|> from(sender())
|
||||||
|> subject("Your account archive is ready")
|
|> subject(
|
||||||
|
Gettext.dpgettext(
|
||||||
|
"static_pages",
|
||||||
|
"account archive email subject",
|
||||||
|
"Your account archive is ready"
|
||||||
|
)
|
||||||
|
)
|
||||||
|> html_body(html_body)
|
|> html_body(html_body)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
# emoji-test.txt
|
# emoji-test.txt
|
||||||
# Date: 2020-09-12, 22:19:50 GMT
|
# Date: 2021-08-26, 17:22:23 GMT
|
||||||
# © 2020 Unicode®, Inc.
|
# © 2021 Unicode®, Inc.
|
||||||
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
|
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
|
||||||
# For terms of use, see http://www.unicode.org/terms_of_use.html
|
# For terms of use, see http://www.unicode.org/terms_of_use.html
|
||||||
#
|
#
|
||||||
# Emoji Keyboard/Display Test Data for UTS #51
|
# Emoji Keyboard/Display Test Data for UTS #51
|
||||||
# Version: 13.1
|
# Version: 14.0
|
||||||
#
|
#
|
||||||
# For documentation and usage, see http://www.unicode.org/reports/tr51
|
# For documentation and usage, see http://www.unicode.org/reports/tr51
|
||||||
#
|
#
|
||||||
|
@ -43,6 +43,7 @@
|
||||||
1F602 ; fully-qualified # 😂 E0.6 face with tears of joy
|
1F602 ; fully-qualified # 😂 E0.6 face with tears of joy
|
||||||
1F642 ; fully-qualified # 🙂 E1.0 slightly smiling face
|
1F642 ; fully-qualified # 🙂 E1.0 slightly smiling face
|
||||||
1F643 ; fully-qualified # 🙃 E1.0 upside-down face
|
1F643 ; fully-qualified # 🙃 E1.0 upside-down face
|
||||||
|
1FAE0 ; fully-qualified # 🫠 E14.0 melting face
|
||||||
1F609 ; fully-qualified # 😉 E0.6 winking face
|
1F609 ; fully-qualified # 😉 E0.6 winking face
|
||||||
1F60A ; fully-qualified # 😊 E0.6 smiling face with smiling eyes
|
1F60A ; fully-qualified # 😊 E0.6 smiling face with smiling eyes
|
||||||
1F607 ; fully-qualified # 😇 E1.0 smiling face with halo
|
1F607 ; fully-qualified # 😇 E1.0 smiling face with halo
|
||||||
|
@ -68,10 +69,13 @@
|
||||||
1F911 ; fully-qualified # 🤑 E1.0 money-mouth face
|
1F911 ; fully-qualified # 🤑 E1.0 money-mouth face
|
||||||
|
|
||||||
# subgroup: face-hand
|
# subgroup: face-hand
|
||||||
1F917 ; fully-qualified # 🤗 E1.0 hugging face
|
1F917 ; fully-qualified # 🤗 E1.0 smiling face with open hands
|
||||||
1F92D ; fully-qualified # 🤭 E5.0 face with hand over mouth
|
1F92D ; fully-qualified # 🤭 E5.0 face with hand over mouth
|
||||||
|
1FAE2 ; fully-qualified # 🫢 E14.0 face with open eyes and hand over mouth
|
||||||
|
1FAE3 ; fully-qualified # 🫣 E14.0 face with peeking eye
|
||||||
1F92B ; fully-qualified # 🤫 E5.0 shushing face
|
1F92B ; fully-qualified # 🤫 E5.0 shushing face
|
||||||
1F914 ; fully-qualified # 🤔 E1.0 thinking face
|
1F914 ; fully-qualified # 🤔 E1.0 thinking face
|
||||||
|
1FAE1 ; fully-qualified # 🫡 E14.0 saluting face
|
||||||
|
|
||||||
# subgroup: face-neutral-skeptical
|
# subgroup: face-neutral-skeptical
|
||||||
1F910 ; fully-qualified # 🤐 E1.0 zipper-mouth face
|
1F910 ; fully-qualified # 🤐 E1.0 zipper-mouth face
|
||||||
|
@ -79,6 +83,7 @@
|
||||||
1F610 ; fully-qualified # 😐 E0.7 neutral face
|
1F610 ; fully-qualified # 😐 E0.7 neutral face
|
||||||
1F611 ; fully-qualified # 😑 E1.0 expressionless face
|
1F611 ; fully-qualified # 😑 E1.0 expressionless face
|
||||||
1F636 ; fully-qualified # 😶 E1.0 face without mouth
|
1F636 ; fully-qualified # 😶 E1.0 face without mouth
|
||||||
|
1FAE5 ; fully-qualified # 🫥 E14.0 dotted line face
|
||||||
1F636 200D 1F32B FE0F ; fully-qualified # 😶🌫️ E13.1 face in clouds
|
1F636 200D 1F32B FE0F ; fully-qualified # 😶🌫️ E13.1 face in clouds
|
||||||
1F636 200D 1F32B ; minimally-qualified # 😶🌫 E13.1 face in clouds
|
1F636 200D 1F32B ; minimally-qualified # 😶🌫 E13.1 face in clouds
|
||||||
1F60F ; fully-qualified # 😏 E0.6 smirking face
|
1F60F ; fully-qualified # 😏 E0.6 smirking face
|
||||||
|
@ -105,7 +110,7 @@
|
||||||
1F975 ; fully-qualified # 🥵 E11.0 hot face
|
1F975 ; fully-qualified # 🥵 E11.0 hot face
|
||||||
1F976 ; fully-qualified # 🥶 E11.0 cold face
|
1F976 ; fully-qualified # 🥶 E11.0 cold face
|
||||||
1F974 ; fully-qualified # 🥴 E11.0 woozy face
|
1F974 ; fully-qualified # 🥴 E11.0 woozy face
|
||||||
1F635 ; fully-qualified # 😵 E0.6 knocked-out face
|
1F635 ; fully-qualified # 😵 E0.6 face with crossed-out eyes
|
||||||
1F635 200D 1F4AB ; fully-qualified # 😵💫 E13.1 face with spiral eyes
|
1F635 200D 1F4AB ; fully-qualified # 😵💫 E13.1 face with spiral eyes
|
||||||
1F92F ; fully-qualified # 🤯 E5.0 exploding head
|
1F92F ; fully-qualified # 🤯 E5.0 exploding head
|
||||||
|
|
||||||
|
@ -121,6 +126,7 @@
|
||||||
|
|
||||||
# subgroup: face-concerned
|
# subgroup: face-concerned
|
||||||
1F615 ; fully-qualified # 😕 E1.0 confused face
|
1F615 ; fully-qualified # 😕 E1.0 confused face
|
||||||
|
1FAE4 ; fully-qualified # 🫤 E14.0 face with diagonal mouth
|
||||||
1F61F ; fully-qualified # 😟 E1.0 worried face
|
1F61F ; fully-qualified # 😟 E1.0 worried face
|
||||||
1F641 ; fully-qualified # 🙁 E1.0 slightly frowning face
|
1F641 ; fully-qualified # 🙁 E1.0 slightly frowning face
|
||||||
2639 FE0F ; fully-qualified # ☹️ E0.7 frowning face
|
2639 FE0F ; fully-qualified # ☹️ E0.7 frowning face
|
||||||
|
@ -130,6 +136,7 @@
|
||||||
1F632 ; fully-qualified # 😲 E0.6 astonished face
|
1F632 ; fully-qualified # 😲 E0.6 astonished face
|
||||||
1F633 ; fully-qualified # 😳 E0.6 flushed face
|
1F633 ; fully-qualified # 😳 E0.6 flushed face
|
||||||
1F97A ; fully-qualified # 🥺 E11.0 pleading face
|
1F97A ; fully-qualified # 🥺 E11.0 pleading face
|
||||||
|
1F979 ; fully-qualified # 🥹 E14.0 face holding back tears
|
||||||
1F626 ; fully-qualified # 😦 E1.0 frowning face with open mouth
|
1F626 ; fully-qualified # 😦 E1.0 frowning face with open mouth
|
||||||
1F627 ; fully-qualified # 😧 E1.0 anguished face
|
1F627 ; fully-qualified # 😧 E1.0 anguished face
|
||||||
1F628 ; fully-qualified # 😨 E0.6 fearful face
|
1F628 ; fully-qualified # 😨 E0.6 fearful face
|
||||||
|
@ -232,8 +239,8 @@
|
||||||
1F4AD ; fully-qualified # 💭 E1.0 thought balloon
|
1F4AD ; fully-qualified # 💭 E1.0 thought balloon
|
||||||
1F4A4 ; fully-qualified # 💤 E0.6 zzz
|
1F4A4 ; fully-qualified # 💤 E0.6 zzz
|
||||||
|
|
||||||
# Smileys & Emotion subtotal: 170
|
# Smileys & Emotion subtotal: 177
|
||||||
# Smileys & Emotion subtotal: 170 w/o modifiers
|
# Smileys & Emotion subtotal: 177 w/o modifiers
|
||||||
|
|
||||||
# group: People & Body
|
# group: People & Body
|
||||||
|
|
||||||
|
@ -269,6 +276,30 @@
|
||||||
1F596 1F3FD ; fully-qualified # 🖖🏽 E1.0 vulcan salute: medium skin tone
|
1F596 1F3FD ; fully-qualified # 🖖🏽 E1.0 vulcan salute: medium skin tone
|
||||||
1F596 1F3FE ; fully-qualified # 🖖🏾 E1.0 vulcan salute: medium-dark skin tone
|
1F596 1F3FE ; fully-qualified # 🖖🏾 E1.0 vulcan salute: medium-dark skin tone
|
||||||
1F596 1F3FF ; fully-qualified # 🖖🏿 E1.0 vulcan salute: dark skin tone
|
1F596 1F3FF ; fully-qualified # 🖖🏿 E1.0 vulcan salute: dark skin tone
|
||||||
|
1FAF1 ; fully-qualified # 🫱 E14.0 rightwards hand
|
||||||
|
1FAF1 1F3FB ; fully-qualified # 🫱🏻 E14.0 rightwards hand: light skin tone
|
||||||
|
1FAF1 1F3FC ; fully-qualified # 🫱🏼 E14.0 rightwards hand: medium-light skin tone
|
||||||
|
1FAF1 1F3FD ; fully-qualified # 🫱🏽 E14.0 rightwards hand: medium skin tone
|
||||||
|
1FAF1 1F3FE ; fully-qualified # 🫱🏾 E14.0 rightwards hand: medium-dark skin tone
|
||||||
|
1FAF1 1F3FF ; fully-qualified # 🫱🏿 E14.0 rightwards hand: dark skin tone
|
||||||
|
1FAF2 ; fully-qualified # 🫲 E14.0 leftwards hand
|
||||||
|
1FAF2 1F3FB ; fully-qualified # 🫲🏻 E14.0 leftwards hand: light skin tone
|
||||||
|
1FAF2 1F3FC ; fully-qualified # 🫲🏼 E14.0 leftwards hand: medium-light skin tone
|
||||||
|
1FAF2 1F3FD ; fully-qualified # 🫲🏽 E14.0 leftwards hand: medium skin tone
|
||||||
|
1FAF2 1F3FE ; fully-qualified # 🫲🏾 E14.0 leftwards hand: medium-dark skin tone
|
||||||
|
1FAF2 1F3FF ; fully-qualified # 🫲🏿 E14.0 leftwards hand: dark skin tone
|
||||||
|
1FAF3 ; fully-qualified # 🫳 E14.0 palm down hand
|
||||||
|
1FAF3 1F3FB ; fully-qualified # 🫳🏻 E14.0 palm down hand: light skin tone
|
||||||
|
1FAF3 1F3FC ; fully-qualified # 🫳🏼 E14.0 palm down hand: medium-light skin tone
|
||||||
|
1FAF3 1F3FD ; fully-qualified # 🫳🏽 E14.0 palm down hand: medium skin tone
|
||||||
|
1FAF3 1F3FE ; fully-qualified # 🫳🏾 E14.0 palm down hand: medium-dark skin tone
|
||||||
|
1FAF3 1F3FF ; fully-qualified # 🫳🏿 E14.0 palm down hand: dark skin tone
|
||||||
|
1FAF4 ; fully-qualified # 🫴 E14.0 palm up hand
|
||||||
|
1FAF4 1F3FB ; fully-qualified # 🫴🏻 E14.0 palm up hand: light skin tone
|
||||||
|
1FAF4 1F3FC ; fully-qualified # 🫴🏼 E14.0 palm up hand: medium-light skin tone
|
||||||
|
1FAF4 1F3FD ; fully-qualified # 🫴🏽 E14.0 palm up hand: medium skin tone
|
||||||
|
1FAF4 1F3FE ; fully-qualified # 🫴🏾 E14.0 palm up hand: medium-dark skin tone
|
||||||
|
1FAF4 1F3FF ; fully-qualified # 🫴🏿 E14.0 palm up hand: dark skin tone
|
||||||
|
|
||||||
# subgroup: hand-fingers-partial
|
# subgroup: hand-fingers-partial
|
||||||
1F44C ; fully-qualified # 👌 E0.6 OK hand
|
1F44C ; fully-qualified # 👌 E0.6 OK hand
|
||||||
|
@ -302,6 +333,12 @@
|
||||||
1F91E 1F3FD ; fully-qualified # 🤞🏽 E3.0 crossed fingers: medium skin tone
|
1F91E 1F3FD ; fully-qualified # 🤞🏽 E3.0 crossed fingers: medium skin tone
|
||||||
1F91E 1F3FE ; fully-qualified # 🤞🏾 E3.0 crossed fingers: medium-dark skin tone
|
1F91E 1F3FE ; fully-qualified # 🤞🏾 E3.0 crossed fingers: medium-dark skin tone
|
||||||
1F91E 1F3FF ; fully-qualified # 🤞🏿 E3.0 crossed fingers: dark skin tone
|
1F91E 1F3FF ; fully-qualified # 🤞🏿 E3.0 crossed fingers: dark skin tone
|
||||||
|
1FAF0 ; fully-qualified # 🫰 E14.0 hand with index finger and thumb crossed
|
||||||
|
1FAF0 1F3FB ; fully-qualified # 🫰🏻 E14.0 hand with index finger and thumb crossed: light skin tone
|
||||||
|
1FAF0 1F3FC ; fully-qualified # 🫰🏼 E14.0 hand with index finger and thumb crossed: medium-light skin tone
|
||||||
|
1FAF0 1F3FD ; fully-qualified # 🫰🏽 E14.0 hand with index finger and thumb crossed: medium skin tone
|
||||||
|
1FAF0 1F3FE ; fully-qualified # 🫰🏾 E14.0 hand with index finger and thumb crossed: medium-dark skin tone
|
||||||
|
1FAF0 1F3FF ; fully-qualified # 🫰🏿 E14.0 hand with index finger and thumb crossed: dark skin tone
|
||||||
1F91F ; fully-qualified # 🤟 E5.0 love-you gesture
|
1F91F ; fully-qualified # 🤟 E5.0 love-you gesture
|
||||||
1F91F 1F3FB ; fully-qualified # 🤟🏻 E5.0 love-you gesture: light skin tone
|
1F91F 1F3FB ; fully-qualified # 🤟🏻 E5.0 love-you gesture: light skin tone
|
||||||
1F91F 1F3FC ; fully-qualified # 🤟🏼 E5.0 love-you gesture: medium-light skin tone
|
1F91F 1F3FC ; fully-qualified # 🤟🏼 E5.0 love-you gesture: medium-light skin tone
|
||||||
|
@ -359,6 +396,12 @@
|
||||||
261D 1F3FD ; fully-qualified # ☝🏽 E1.0 index pointing up: medium skin tone
|
261D 1F3FD ; fully-qualified # ☝🏽 E1.0 index pointing up: medium skin tone
|
||||||
261D 1F3FE ; fully-qualified # ☝🏾 E1.0 index pointing up: medium-dark skin tone
|
261D 1F3FE ; fully-qualified # ☝🏾 E1.0 index pointing up: medium-dark skin tone
|
||||||
261D 1F3FF ; fully-qualified # ☝🏿 E1.0 index pointing up: dark skin tone
|
261D 1F3FF ; fully-qualified # ☝🏿 E1.0 index pointing up: dark skin tone
|
||||||
|
1FAF5 ; fully-qualified # 🫵 E14.0 index pointing at the viewer
|
||||||
|
1FAF5 1F3FB ; fully-qualified # 🫵🏻 E14.0 index pointing at the viewer: light skin tone
|
||||||
|
1FAF5 1F3FC ; fully-qualified # 🫵🏼 E14.0 index pointing at the viewer: medium-light skin tone
|
||||||
|
1FAF5 1F3FD ; fully-qualified # 🫵🏽 E14.0 index pointing at the viewer: medium skin tone
|
||||||
|
1FAF5 1F3FE ; fully-qualified # 🫵🏾 E14.0 index pointing at the viewer: medium-dark skin tone
|
||||||
|
1FAF5 1F3FF ; fully-qualified # 🫵🏿 E14.0 index pointing at the viewer: dark skin tone
|
||||||
|
|
||||||
# subgroup: hand-fingers-closed
|
# subgroup: hand-fingers-closed
|
||||||
1F44D ; fully-qualified # 👍 E0.6 thumbs up
|
1F44D ; fully-qualified # 👍 E0.6 thumbs up
|
||||||
|
@ -411,6 +454,12 @@
|
||||||
1F64C 1F3FD ; fully-qualified # 🙌🏽 E1.0 raising hands: medium skin tone
|
1F64C 1F3FD ; fully-qualified # 🙌🏽 E1.0 raising hands: medium skin tone
|
||||||
1F64C 1F3FE ; fully-qualified # 🙌🏾 E1.0 raising hands: medium-dark skin tone
|
1F64C 1F3FE ; fully-qualified # 🙌🏾 E1.0 raising hands: medium-dark skin tone
|
||||||
1F64C 1F3FF ; fully-qualified # 🙌🏿 E1.0 raising hands: dark skin tone
|
1F64C 1F3FF ; fully-qualified # 🙌🏿 E1.0 raising hands: dark skin tone
|
||||||
|
1FAF6 ; fully-qualified # 🫶 E14.0 heart hands
|
||||||
|
1FAF6 1F3FB ; fully-qualified # 🫶🏻 E14.0 heart hands: light skin tone
|
||||||
|
1FAF6 1F3FC ; fully-qualified # 🫶🏼 E14.0 heart hands: medium-light skin tone
|
||||||
|
1FAF6 1F3FD ; fully-qualified # 🫶🏽 E14.0 heart hands: medium skin tone
|
||||||
|
1FAF6 1F3FE ; fully-qualified # 🫶🏾 E14.0 heart hands: medium-dark skin tone
|
||||||
|
1FAF6 1F3FF ; fully-qualified # 🫶🏿 E14.0 heart hands: dark skin tone
|
||||||
1F450 ; fully-qualified # 👐 E0.6 open hands
|
1F450 ; fully-qualified # 👐 E0.6 open hands
|
||||||
1F450 1F3FB ; fully-qualified # 👐🏻 E1.0 open hands: light skin tone
|
1F450 1F3FB ; fully-qualified # 👐🏻 E1.0 open hands: light skin tone
|
||||||
1F450 1F3FC ; fully-qualified # 👐🏼 E1.0 open hands: medium-light skin tone
|
1F450 1F3FC ; fully-qualified # 👐🏼 E1.0 open hands: medium-light skin tone
|
||||||
|
@ -424,6 +473,31 @@
|
||||||
1F932 1F3FE ; fully-qualified # 🤲🏾 E5.0 palms up together: medium-dark skin tone
|
1F932 1F3FE ; fully-qualified # 🤲🏾 E5.0 palms up together: medium-dark skin tone
|
||||||
1F932 1F3FF ; fully-qualified # 🤲🏿 E5.0 palms up together: dark skin tone
|
1F932 1F3FF ; fully-qualified # 🤲🏿 E5.0 palms up together: dark skin tone
|
||||||
1F91D ; fully-qualified # 🤝 E3.0 handshake
|
1F91D ; fully-qualified # 🤝 E3.0 handshake
|
||||||
|
1F91D 1F3FB ; fully-qualified # 🤝🏻 E3.0 handshake: light skin tone
|
||||||
|
1F91D 1F3FC ; fully-qualified # 🤝🏼 E3.0 handshake: medium-light skin tone
|
||||||
|
1F91D 1F3FD ; fully-qualified # 🤝🏽 E3.0 handshake: medium skin tone
|
||||||
|
1F91D 1F3FE ; fully-qualified # 🤝🏾 E3.0 handshake: medium-dark skin tone
|
||||||
|
1F91D 1F3FF ; fully-qualified # 🤝🏿 E3.0 handshake: dark skin tone
|
||||||
|
1FAF1 1F3FB 200D 1FAF2 1F3FC ; fully-qualified # 🫱🏻🫲🏼 E14.0 handshake: light skin tone, medium-light skin tone
|
||||||
|
1FAF1 1F3FB 200D 1FAF2 1F3FD ; fully-qualified # 🫱🏻🫲🏽 E14.0 handshake: light skin tone, medium skin tone
|
||||||
|
1FAF1 1F3FB 200D 1FAF2 1F3FE ; fully-qualified # 🫱🏻🫲🏾 E14.0 handshake: light skin tone, medium-dark skin tone
|
||||||
|
1FAF1 1F3FB 200D 1FAF2 1F3FF ; fully-qualified # 🫱🏻🫲🏿 E14.0 handshake: light skin tone, dark skin tone
|
||||||
|
1FAF1 1F3FC 200D 1FAF2 1F3FB ; fully-qualified # 🫱🏼🫲🏻 E14.0 handshake: medium-light skin tone, light skin tone
|
||||||
|
1FAF1 1F3FC 200D 1FAF2 1F3FD ; fully-qualified # 🫱🏼🫲🏽 E14.0 handshake: medium-light skin tone, medium skin tone
|
||||||
|
1FAF1 1F3FC 200D 1FAF2 1F3FE ; fully-qualified # 🫱🏼🫲🏾 E14.0 handshake: medium-light skin tone, medium-dark skin tone
|
||||||
|
1FAF1 1F3FC 200D 1FAF2 1F3FF ; fully-qualified # 🫱🏼🫲🏿 E14.0 handshake: medium-light skin tone, dark skin tone
|
||||||
|
1FAF1 1F3FD 200D 1FAF2 1F3FB ; fully-qualified # 🫱🏽🫲🏻 E14.0 handshake: medium skin tone, light skin tone
|
||||||
|
1FAF1 1F3FD 200D 1FAF2 1F3FC ; fully-qualified # 🫱🏽🫲🏼 E14.0 handshake: medium skin tone, medium-light skin tone
|
||||||
|
1FAF1 1F3FD 200D 1FAF2 1F3FE ; fully-qualified # 🫱🏽🫲🏾 E14.0 handshake: medium skin tone, medium-dark skin tone
|
||||||
|
1FAF1 1F3FD 200D 1FAF2 1F3FF ; fully-qualified # 🫱🏽🫲🏿 E14.0 handshake: medium skin tone, dark skin tone
|
||||||
|
1FAF1 1F3FE 200D 1FAF2 1F3FB ; fully-qualified # 🫱🏾🫲🏻 E14.0 handshake: medium-dark skin tone, light skin tone
|
||||||
|
1FAF1 1F3FE 200D 1FAF2 1F3FC ; fully-qualified # 🫱🏾🫲🏼 E14.0 handshake: medium-dark skin tone, medium-light skin tone
|
||||||
|
1FAF1 1F3FE 200D 1FAF2 1F3FD ; fully-qualified # 🫱🏾🫲🏽 E14.0 handshake: medium-dark skin tone, medium skin tone
|
||||||
|
1FAF1 1F3FE 200D 1FAF2 1F3FF ; fully-qualified # 🫱🏾🫲🏿 E14.0 handshake: medium-dark skin tone, dark skin tone
|
||||||
|
1FAF1 1F3FF 200D 1FAF2 1F3FB ; fully-qualified # 🫱🏿🫲🏻 E14.0 handshake: dark skin tone, light skin tone
|
||||||
|
1FAF1 1F3FF 200D 1FAF2 1F3FC ; fully-qualified # 🫱🏿🫲🏼 E14.0 handshake: dark skin tone, medium-light skin tone
|
||||||
|
1FAF1 1F3FF 200D 1FAF2 1F3FD ; fully-qualified # 🫱🏿🫲🏽 E14.0 handshake: dark skin tone, medium skin tone
|
||||||
|
1FAF1 1F3FF 200D 1FAF2 1F3FE ; fully-qualified # 🫱🏿🫲🏾 E14.0 handshake: dark skin tone, medium-dark skin tone
|
||||||
1F64F ; fully-qualified # 🙏 E0.6 folded hands
|
1F64F ; fully-qualified # 🙏 E0.6 folded hands
|
||||||
1F64F 1F3FB ; fully-qualified # 🙏🏻 E1.0 folded hands: light skin tone
|
1F64F 1F3FB ; fully-qualified # 🙏🏻 E1.0 folded hands: light skin tone
|
||||||
1F64F 1F3FC ; fully-qualified # 🙏🏼 E1.0 folded hands: medium-light skin tone
|
1F64F 1F3FC ; fully-qualified # 🙏🏼 E1.0 folded hands: medium-light skin tone
|
||||||
|
@ -501,6 +575,7 @@
|
||||||
1F441 ; unqualified # 👁 E0.7 eye
|
1F441 ; unqualified # 👁 E0.7 eye
|
||||||
1F445 ; fully-qualified # 👅 E0.6 tongue
|
1F445 ; fully-qualified # 👅 E0.6 tongue
|
||||||
1F444 ; fully-qualified # 👄 E0.6 mouth
|
1F444 ; fully-qualified # 👄 E0.6 mouth
|
||||||
|
1FAE6 ; fully-qualified # 🫦 E14.0 biting lip
|
||||||
|
|
||||||
# subgroup: person
|
# subgroup: person
|
||||||
1F476 ; fully-qualified # 👶 E0.6 baby
|
1F476 ; fully-qualified # 👶 E0.6 baby
|
||||||
|
@ -1472,6 +1547,12 @@
|
||||||
1F477 1F3FE 200D 2640 ; minimally-qualified # 👷🏾♀ E4.0 woman construction worker: medium-dark skin tone
|
1F477 1F3FE 200D 2640 ; minimally-qualified # 👷🏾♀ E4.0 woman construction worker: medium-dark skin tone
|
||||||
1F477 1F3FF 200D 2640 FE0F ; fully-qualified # 👷🏿♀️ E4.0 woman construction worker: dark skin tone
|
1F477 1F3FF 200D 2640 FE0F ; fully-qualified # 👷🏿♀️ E4.0 woman construction worker: dark skin tone
|
||||||
1F477 1F3FF 200D 2640 ; minimally-qualified # 👷🏿♀ E4.0 woman construction worker: dark skin tone
|
1F477 1F3FF 200D 2640 ; minimally-qualified # 👷🏿♀ E4.0 woman construction worker: dark skin tone
|
||||||
|
1FAC5 ; fully-qualified # 🫅 E14.0 person with crown
|
||||||
|
1FAC5 1F3FB ; fully-qualified # 🫅🏻 E14.0 person with crown: light skin tone
|
||||||
|
1FAC5 1F3FC ; fully-qualified # 🫅🏼 E14.0 person with crown: medium-light skin tone
|
||||||
|
1FAC5 1F3FD ; fully-qualified # 🫅🏽 E14.0 person with crown: medium skin tone
|
||||||
|
1FAC5 1F3FE ; fully-qualified # 🫅🏾 E14.0 person with crown: medium-dark skin tone
|
||||||
|
1FAC5 1F3FF ; fully-qualified # 🫅🏿 E14.0 person with crown: dark skin tone
|
||||||
1F934 ; fully-qualified # 🤴 E3.0 prince
|
1F934 ; fully-qualified # 🤴 E3.0 prince
|
||||||
1F934 1F3FB ; fully-qualified # 🤴🏻 E3.0 prince: light skin tone
|
1F934 1F3FB ; fully-qualified # 🤴🏻 E3.0 prince: light skin tone
|
||||||
1F934 1F3FC ; fully-qualified # 🤴🏼 E3.0 prince: medium-light skin tone
|
1F934 1F3FC ; fully-qualified # 🤴🏼 E3.0 prince: medium-light skin tone
|
||||||
|
@ -1592,6 +1673,18 @@
|
||||||
1F930 1F3FD ; fully-qualified # 🤰🏽 E3.0 pregnant woman: medium skin tone
|
1F930 1F3FD ; fully-qualified # 🤰🏽 E3.0 pregnant woman: medium skin tone
|
||||||
1F930 1F3FE ; fully-qualified # 🤰🏾 E3.0 pregnant woman: medium-dark skin tone
|
1F930 1F3FE ; fully-qualified # 🤰🏾 E3.0 pregnant woman: medium-dark skin tone
|
||||||
1F930 1F3FF ; fully-qualified # 🤰🏿 E3.0 pregnant woman: dark skin tone
|
1F930 1F3FF ; fully-qualified # 🤰🏿 E3.0 pregnant woman: dark skin tone
|
||||||
|
1FAC3 ; fully-qualified # 🫃 E14.0 pregnant man
|
||||||
|
1FAC3 1F3FB ; fully-qualified # 🫃🏻 E14.0 pregnant man: light skin tone
|
||||||
|
1FAC3 1F3FC ; fully-qualified # 🫃🏼 E14.0 pregnant man: medium-light skin tone
|
||||||
|
1FAC3 1F3FD ; fully-qualified # 🫃🏽 E14.0 pregnant man: medium skin tone
|
||||||
|
1FAC3 1F3FE ; fully-qualified # 🫃🏾 E14.0 pregnant man: medium-dark skin tone
|
||||||
|
1FAC3 1F3FF ; fully-qualified # 🫃🏿 E14.0 pregnant man: dark skin tone
|
||||||
|
1FAC4 ; fully-qualified # 🫄 E14.0 pregnant person
|
||||||
|
1FAC4 1F3FB ; fully-qualified # 🫄🏻 E14.0 pregnant person: light skin tone
|
||||||
|
1FAC4 1F3FC ; fully-qualified # 🫄🏼 E14.0 pregnant person: medium-light skin tone
|
||||||
|
1FAC4 1F3FD ; fully-qualified # 🫄🏽 E14.0 pregnant person: medium skin tone
|
||||||
|
1FAC4 1F3FE ; fully-qualified # 🫄🏾 E14.0 pregnant person: medium-dark skin tone
|
||||||
|
1FAC4 1F3FF ; fully-qualified # 🫄🏿 E14.0 pregnant person: dark skin tone
|
||||||
1F931 ; fully-qualified # 🤱 E5.0 breast-feeding
|
1F931 ; fully-qualified # 🤱 E5.0 breast-feeding
|
||||||
1F931 1F3FB ; fully-qualified # 🤱🏻 E5.0 breast-feeding: light skin tone
|
1F931 1F3FB ; fully-qualified # 🤱🏻 E5.0 breast-feeding: light skin tone
|
||||||
1F931 1F3FC ; fully-qualified # 🤱🏼 E5.0 breast-feeding: medium-light skin tone
|
1F931 1F3FC ; fully-qualified # 🤱🏼 E5.0 breast-feeding: medium-light skin tone
|
||||||
|
@ -1862,6 +1955,7 @@
|
||||||
1F9DF 200D 2642 ; minimally-qualified # 🧟♂ E5.0 man zombie
|
1F9DF 200D 2642 ; minimally-qualified # 🧟♂ E5.0 man zombie
|
||||||
1F9DF 200D 2640 FE0F ; fully-qualified # 🧟♀️ E5.0 woman zombie
|
1F9DF 200D 2640 FE0F ; fully-qualified # 🧟♀️ E5.0 woman zombie
|
||||||
1F9DF 200D 2640 ; minimally-qualified # 🧟♀ E5.0 woman zombie
|
1F9DF 200D 2640 ; minimally-qualified # 🧟♀ E5.0 woman zombie
|
||||||
|
1F9CC ; fully-qualified # 🧌 E14.0 troll
|
||||||
|
|
||||||
# subgroup: person-activity
|
# subgroup: person-activity
|
||||||
1F486 ; fully-qualified # 💆 E0.6 person getting massage
|
1F486 ; fully-qualified # 💆 E0.6 person getting massage
|
||||||
|
@ -3168,8 +3262,8 @@
|
||||||
1FAC2 ; fully-qualified # 🫂 E13.0 people hugging
|
1FAC2 ; fully-qualified # 🫂 E13.0 people hugging
|
||||||
1F463 ; fully-qualified # 👣 E0.6 footprints
|
1F463 ; fully-qualified # 👣 E0.6 footprints
|
||||||
|
|
||||||
# People & Body subtotal: 2899
|
# People & Body subtotal: 2986
|
||||||
# People & Body subtotal: 494 w/o modifiers
|
# People & Body subtotal: 506 w/o modifiers
|
||||||
|
|
||||||
# group: Component
|
# group: Component
|
||||||
|
|
||||||
|
@ -3304,6 +3398,7 @@
|
||||||
1F988 ; fully-qualified # 🦈 E3.0 shark
|
1F988 ; fully-qualified # 🦈 E3.0 shark
|
||||||
1F419 ; fully-qualified # 🐙 E0.6 octopus
|
1F419 ; fully-qualified # 🐙 E0.6 octopus
|
||||||
1F41A ; fully-qualified # 🐚 E0.6 spiral shell
|
1F41A ; fully-qualified # 🐚 E0.6 spiral shell
|
||||||
|
1FAB8 ; fully-qualified # 🪸 E14.0 coral
|
||||||
|
|
||||||
# subgroup: animal-bug
|
# subgroup: animal-bug
|
||||||
1F40C ; fully-qualified # 🐌 E0.6 snail
|
1F40C ; fully-qualified # 🐌 E0.6 snail
|
||||||
|
@ -3329,6 +3424,7 @@
|
||||||
1F490 ; fully-qualified # 💐 E0.6 bouquet
|
1F490 ; fully-qualified # 💐 E0.6 bouquet
|
||||||
1F338 ; fully-qualified # 🌸 E0.6 cherry blossom
|
1F338 ; fully-qualified # 🌸 E0.6 cherry blossom
|
||||||
1F4AE ; fully-qualified # 💮 E0.6 white flower
|
1F4AE ; fully-qualified # 💮 E0.6 white flower
|
||||||
|
1FAB7 ; fully-qualified # 🪷 E14.0 lotus
|
||||||
1F3F5 FE0F ; fully-qualified # 🏵️ E0.7 rosette
|
1F3F5 FE0F ; fully-qualified # 🏵️ E0.7 rosette
|
||||||
1F3F5 ; unqualified # 🏵 E0.7 rosette
|
1F3F5 ; unqualified # 🏵 E0.7 rosette
|
||||||
1F339 ; fully-qualified # 🌹 E0.6 rose
|
1F339 ; fully-qualified # 🌹 E0.6 rose
|
||||||
|
@ -3353,9 +3449,11 @@
|
||||||
1F341 ; fully-qualified # 🍁 E0.6 maple leaf
|
1F341 ; fully-qualified # 🍁 E0.6 maple leaf
|
||||||
1F342 ; fully-qualified # 🍂 E0.6 fallen leaf
|
1F342 ; fully-qualified # 🍂 E0.6 fallen leaf
|
||||||
1F343 ; fully-qualified # 🍃 E0.6 leaf fluttering in wind
|
1F343 ; fully-qualified # 🍃 E0.6 leaf fluttering in wind
|
||||||
|
1FAB9 ; fully-qualified # 🪹 E14.0 empty nest
|
||||||
|
1FABA ; fully-qualified # 🪺 E14.0 nest with eggs
|
||||||
|
|
||||||
# Animals & Nature subtotal: 147
|
# Animals & Nature subtotal: 151
|
||||||
# Animals & Nature subtotal: 147 w/o modifiers
|
# Animals & Nature subtotal: 151 w/o modifiers
|
||||||
|
|
||||||
# group: Food & Drink
|
# group: Food & Drink
|
||||||
|
|
||||||
|
@ -3396,6 +3494,7 @@
|
||||||
1F9C5 ; fully-qualified # 🧅 E12.0 onion
|
1F9C5 ; fully-qualified # 🧅 E12.0 onion
|
||||||
1F344 ; fully-qualified # 🍄 E0.6 mushroom
|
1F344 ; fully-qualified # 🍄 E0.6 mushroom
|
||||||
1F95C ; fully-qualified # 🥜 E3.0 peanuts
|
1F95C ; fully-qualified # 🥜 E3.0 peanuts
|
||||||
|
1FAD8 ; fully-qualified # 🫘 E14.0 beans
|
||||||
1F330 ; fully-qualified # 🌰 E0.6 chestnut
|
1F330 ; fully-qualified # 🌰 E0.6 chestnut
|
||||||
|
|
||||||
# subgroup: food-prepared
|
# subgroup: food-prepared
|
||||||
|
@ -3491,6 +3590,7 @@
|
||||||
1F37B ; fully-qualified # 🍻 E0.6 clinking beer mugs
|
1F37B ; fully-qualified # 🍻 E0.6 clinking beer mugs
|
||||||
1F942 ; fully-qualified # 🥂 E3.0 clinking glasses
|
1F942 ; fully-qualified # 🥂 E3.0 clinking glasses
|
||||||
1F943 ; fully-qualified # 🥃 E3.0 tumbler glass
|
1F943 ; fully-qualified # 🥃 E3.0 tumbler glass
|
||||||
|
1FAD7 ; fully-qualified # 🫗 E14.0 pouring liquid
|
||||||
1F964 ; fully-qualified # 🥤 E5.0 cup with straw
|
1F964 ; fully-qualified # 🥤 E5.0 cup with straw
|
||||||
1F9CB ; fully-qualified # 🧋 E13.0 bubble tea
|
1F9CB ; fully-qualified # 🧋 E13.0 bubble tea
|
||||||
1F9C3 ; fully-qualified # 🧃 E12.0 beverage box
|
1F9C3 ; fully-qualified # 🧃 E12.0 beverage box
|
||||||
|
@ -3504,10 +3604,11 @@
|
||||||
1F374 ; fully-qualified # 🍴 E0.6 fork and knife
|
1F374 ; fully-qualified # 🍴 E0.6 fork and knife
|
||||||
1F944 ; fully-qualified # 🥄 E3.0 spoon
|
1F944 ; fully-qualified # 🥄 E3.0 spoon
|
||||||
1F52A ; fully-qualified # 🔪 E0.6 kitchen knife
|
1F52A ; fully-qualified # 🔪 E0.6 kitchen knife
|
||||||
|
1FAD9 ; fully-qualified # 🫙 E14.0 jar
|
||||||
1F3FA ; fully-qualified # 🏺 E1.0 amphora
|
1F3FA ; fully-qualified # 🏺 E1.0 amphora
|
||||||
|
|
||||||
# Food & Drink subtotal: 131
|
# Food & Drink subtotal: 134
|
||||||
# Food & Drink subtotal: 131 w/o modifiers
|
# Food & Drink subtotal: 134 w/o modifiers
|
||||||
|
|
||||||
# group: Travel & Places
|
# group: Travel & Places
|
||||||
|
|
||||||
|
@ -3597,6 +3698,7 @@
|
||||||
2668 FE0F ; fully-qualified # ♨️ E0.6 hot springs
|
2668 FE0F ; fully-qualified # ♨️ E0.6 hot springs
|
||||||
2668 ; unqualified # ♨ E0.6 hot springs
|
2668 ; unqualified # ♨ E0.6 hot springs
|
||||||
1F3A0 ; fully-qualified # 🎠 E0.6 carousel horse
|
1F3A0 ; fully-qualified # 🎠 E0.6 carousel horse
|
||||||
|
1F6DD ; fully-qualified # 🛝 E14.0 playground slide
|
||||||
1F3A1 ; fully-qualified # 🎡 E0.6 ferris wheel
|
1F3A1 ; fully-qualified # 🎡 E0.6 ferris wheel
|
||||||
1F3A2 ; fully-qualified # 🎢 E0.6 roller coaster
|
1F3A2 ; fully-qualified # 🎢 E0.6 roller coaster
|
||||||
1F488 ; fully-qualified # 💈 E0.6 barber pole
|
1F488 ; fully-qualified # 💈 E0.6 barber pole
|
||||||
|
@ -3652,6 +3754,7 @@
|
||||||
1F6E2 FE0F ; fully-qualified # 🛢️ E0.7 oil drum
|
1F6E2 FE0F ; fully-qualified # 🛢️ E0.7 oil drum
|
||||||
1F6E2 ; unqualified # 🛢 E0.7 oil drum
|
1F6E2 ; unqualified # 🛢 E0.7 oil drum
|
||||||
26FD ; fully-qualified # ⛽ E0.6 fuel pump
|
26FD ; fully-qualified # ⛽ E0.6 fuel pump
|
||||||
|
1F6DE ; fully-qualified # 🛞 E14.0 wheel
|
||||||
1F6A8 ; fully-qualified # 🚨 E0.6 police car light
|
1F6A8 ; fully-qualified # 🚨 E0.6 police car light
|
||||||
1F6A5 ; fully-qualified # 🚥 E0.6 horizontal traffic light
|
1F6A5 ; fully-qualified # 🚥 E0.6 horizontal traffic light
|
||||||
1F6A6 ; fully-qualified # 🚦 E1.0 vertical traffic light
|
1F6A6 ; fully-qualified # 🚦 E1.0 vertical traffic light
|
||||||
|
@ -3660,6 +3763,7 @@
|
||||||
|
|
||||||
# subgroup: transport-water
|
# subgroup: transport-water
|
||||||
2693 ; fully-qualified # ⚓ E0.6 anchor
|
2693 ; fully-qualified # ⚓ E0.6 anchor
|
||||||
|
1F6DF ; fully-qualified # 🛟 E14.0 ring buoy
|
||||||
26F5 ; fully-qualified # ⛵ E0.6 sailboat
|
26F5 ; fully-qualified # ⛵ E0.6 sailboat
|
||||||
1F6F6 ; fully-qualified # 🛶 E3.0 canoe
|
1F6F6 ; fully-qualified # 🛶 E3.0 canoe
|
||||||
1F6A4 ; fully-qualified # 🚤 E0.6 speedboat
|
1F6A4 ; fully-qualified # 🚤 E0.6 speedboat
|
||||||
|
@ -3797,8 +3901,8 @@
|
||||||
1F4A7 ; fully-qualified # 💧 E0.6 droplet
|
1F4A7 ; fully-qualified # 💧 E0.6 droplet
|
||||||
1F30A ; fully-qualified # 🌊 E0.6 water wave
|
1F30A ; fully-qualified # 🌊 E0.6 water wave
|
||||||
|
|
||||||
# Travel & Places subtotal: 264
|
# Travel & Places subtotal: 267
|
||||||
# Travel & Places subtotal: 264 w/o modifiers
|
# Travel & Places subtotal: 267 w/o modifiers
|
||||||
|
|
||||||
# group: Activities
|
# group: Activities
|
||||||
|
|
||||||
|
@ -3874,6 +3978,7 @@
|
||||||
1F52E ; fully-qualified # 🔮 E0.6 crystal ball
|
1F52E ; fully-qualified # 🔮 E0.6 crystal ball
|
||||||
1FA84 ; fully-qualified # 🪄 E13.0 magic wand
|
1FA84 ; fully-qualified # 🪄 E13.0 magic wand
|
||||||
1F9FF ; fully-qualified # 🧿 E11.0 nazar amulet
|
1F9FF ; fully-qualified # 🧿 E11.0 nazar amulet
|
||||||
|
1FAAC ; fully-qualified # 🪬 E14.0 hamsa
|
||||||
1F3AE ; fully-qualified # 🎮 E0.6 video game
|
1F3AE ; fully-qualified # 🎮 E0.6 video game
|
||||||
1F579 FE0F ; fully-qualified # 🕹️ E0.7 joystick
|
1F579 FE0F ; fully-qualified # 🕹️ E0.7 joystick
|
||||||
1F579 ; unqualified # 🕹 E0.7 joystick
|
1F579 ; unqualified # 🕹 E0.7 joystick
|
||||||
|
@ -3882,6 +3987,7 @@
|
||||||
1F9E9 ; fully-qualified # 🧩 E11.0 puzzle piece
|
1F9E9 ; fully-qualified # 🧩 E11.0 puzzle piece
|
||||||
1F9F8 ; fully-qualified # 🧸 E11.0 teddy bear
|
1F9F8 ; fully-qualified # 🧸 E11.0 teddy bear
|
||||||
1FA85 ; fully-qualified # 🪅 E13.0 piñata
|
1FA85 ; fully-qualified # 🪅 E13.0 piñata
|
||||||
|
1FAA9 ; fully-qualified # 🪩 E14.0 mirror ball
|
||||||
1FA86 ; fully-qualified # 🪆 E13.0 nesting dolls
|
1FA86 ; fully-qualified # 🪆 E13.0 nesting dolls
|
||||||
2660 FE0F ; fully-qualified # ♠️ E0.6 spade suit
|
2660 FE0F ; fully-qualified # ♠️ E0.6 spade suit
|
||||||
2660 ; unqualified # ♠ E0.6 spade suit
|
2660 ; unqualified # ♠ E0.6 spade suit
|
||||||
|
@ -3907,8 +4013,8 @@
|
||||||
1F9F6 ; fully-qualified # 🧶 E11.0 yarn
|
1F9F6 ; fully-qualified # 🧶 E11.0 yarn
|
||||||
1FAA2 ; fully-qualified # 🪢 E13.0 knot
|
1FAA2 ; fully-qualified # 🪢 E13.0 knot
|
||||||
|
|
||||||
# Activities subtotal: 95
|
# Activities subtotal: 97
|
||||||
# Activities subtotal: 95 w/o modifiers
|
# Activities subtotal: 97 w/o modifiers
|
||||||
|
|
||||||
# group: Objects
|
# group: Objects
|
||||||
|
|
||||||
|
@ -4009,6 +4115,7 @@
|
||||||
|
|
||||||
# subgroup: computer
|
# subgroup: computer
|
||||||
1F50B ; fully-qualified # 🔋 E0.6 battery
|
1F50B ; fully-qualified # 🔋 E0.6 battery
|
||||||
|
1FAAB ; fully-qualified # 🪫 E14.0 low battery
|
||||||
1F50C ; fully-qualified # 🔌 E0.6 electric plug
|
1F50C ; fully-qualified # 🔌 E0.6 electric plug
|
||||||
1F4BB ; fully-qualified # 💻 E0.6 laptop
|
1F4BB ; fully-qualified # 💻 E0.6 laptop
|
||||||
1F5A5 FE0F ; fully-qualified # 🖥️ E0.7 desktop computer
|
1F5A5 FE0F ; fully-qualified # 🖥️ E0.7 desktop computer
|
||||||
|
@ -4207,7 +4314,9 @@
|
||||||
1FA78 ; fully-qualified # 🩸 E12.0 drop of blood
|
1FA78 ; fully-qualified # 🩸 E12.0 drop of blood
|
||||||
1F48A ; fully-qualified # 💊 E0.6 pill
|
1F48A ; fully-qualified # 💊 E0.6 pill
|
||||||
1FA79 ; fully-qualified # 🩹 E12.0 adhesive bandage
|
1FA79 ; fully-qualified # 🩹 E12.0 adhesive bandage
|
||||||
|
1FA7C ; fully-qualified # 🩼 E14.0 crutch
|
||||||
1FA7A ; fully-qualified # 🩺 E12.0 stethoscope
|
1FA7A ; fully-qualified # 🩺 E12.0 stethoscope
|
||||||
|
1FA7B ; fully-qualified # 🩻 E14.0 x-ray
|
||||||
|
|
||||||
# subgroup: household
|
# subgroup: household
|
||||||
1F6AA ; fully-qualified # 🚪 E0.6 door
|
1F6AA ; fully-qualified # 🚪 E0.6 door
|
||||||
|
@ -4232,6 +4341,7 @@
|
||||||
1F9FB ; fully-qualified # 🧻 E11.0 roll of paper
|
1F9FB ; fully-qualified # 🧻 E11.0 roll of paper
|
||||||
1FAA3 ; fully-qualified # 🪣 E13.0 bucket
|
1FAA3 ; fully-qualified # 🪣 E13.0 bucket
|
||||||
1F9FC ; fully-qualified # 🧼 E11.0 soap
|
1F9FC ; fully-qualified # 🧼 E11.0 soap
|
||||||
|
1FAE7 ; fully-qualified # 🫧 E14.0 bubbles
|
||||||
1FAA5 ; fully-qualified # 🪥 E13.0 toothbrush
|
1FAA5 ; fully-qualified # 🪥 E13.0 toothbrush
|
||||||
1F9FD ; fully-qualified # 🧽 E11.0 sponge
|
1F9FD ; fully-qualified # 🧽 E11.0 sponge
|
||||||
1F9EF ; fully-qualified # 🧯 E11.0 fire extinguisher
|
1F9EF ; fully-qualified # 🧯 E11.0 fire extinguisher
|
||||||
|
@ -4246,9 +4356,10 @@
|
||||||
26B1 ; unqualified # ⚱ E1.0 funeral urn
|
26B1 ; unqualified # ⚱ E1.0 funeral urn
|
||||||
1F5FF ; fully-qualified # 🗿 E0.6 moai
|
1F5FF ; fully-qualified # 🗿 E0.6 moai
|
||||||
1FAA7 ; fully-qualified # 🪧 E13.0 placard
|
1FAA7 ; fully-qualified # 🪧 E13.0 placard
|
||||||
|
1FAAA ; fully-qualified # 🪪 E14.0 identification card
|
||||||
|
|
||||||
# Objects subtotal: 299
|
# Objects subtotal: 304
|
||||||
# Objects subtotal: 299 w/o modifiers
|
# Objects subtotal: 304 w/o modifiers
|
||||||
|
|
||||||
# group: Symbols
|
# group: Symbols
|
||||||
|
|
||||||
|
@ -4409,6 +4520,7 @@
|
||||||
2795 ; fully-qualified # ➕ E0.6 plus
|
2795 ; fully-qualified # ➕ E0.6 plus
|
||||||
2796 ; fully-qualified # ➖ E0.6 minus
|
2796 ; fully-qualified # ➖ E0.6 minus
|
||||||
2797 ; fully-qualified # ➗ E0.6 divide
|
2797 ; fully-qualified # ➗ E0.6 divide
|
||||||
|
1F7F0 ; fully-qualified # 🟰 E14.0 heavy equals sign
|
||||||
267E FE0F ; fully-qualified # ♾️ E11.0 infinity
|
267E FE0F ; fully-qualified # ♾️ E11.0 infinity
|
||||||
267E ; unqualified # ♾ E11.0 infinity
|
267E ; unqualified # ♾ E11.0 infinity
|
||||||
|
|
||||||
|
@ -4581,8 +4693,8 @@
|
||||||
1F533 ; fully-qualified # 🔳 E0.6 white square button
|
1F533 ; fully-qualified # 🔳 E0.6 white square button
|
||||||
1F532 ; fully-qualified # 🔲 E0.6 black square button
|
1F532 ; fully-qualified # 🔲 E0.6 black square button
|
||||||
|
|
||||||
# Symbols subtotal: 301
|
# Symbols subtotal: 302
|
||||||
# Symbols subtotal: 301 w/o modifiers
|
# Symbols subtotal: 302 w/o modifiers
|
||||||
|
|
||||||
# group: Flags
|
# group: Flags
|
||||||
|
|
||||||
|
@ -4871,7 +4983,7 @@
|
||||||
# Flags subtotal: 275 w/o modifiers
|
# Flags subtotal: 275 w/o modifiers
|
||||||
|
|
||||||
# Status Counts
|
# Status Counts
|
||||||
# fully-qualified : 3512
|
# fully-qualified : 3624
|
||||||
# minimally-qualified : 817
|
# minimally-qualified : 817
|
||||||
# unqualified : 252
|
# unqualified : 252
|
||||||
# component : 9
|
# component : 9
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Pleroma: A lightweight social networking server
|
# Pleroma: A lightweight social networking server
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Emoji do
|
defmodule Pleroma.Emoji do
|
||||||
|
@ -9,6 +9,7 @@ defmodule Pleroma.Emoji do
|
||||||
"""
|
"""
|
||||||
use GenServer
|
use GenServer
|
||||||
|
|
||||||
|
alias Pleroma.Emoji.Combinations
|
||||||
alias Pleroma.Emoji.Loader
|
alias Pleroma.Emoji.Loader
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
@ -137,4 +138,17 @@ def is_unicode_emoji?(unquote(emoji)), do: true
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_unicode_emoji?(_), do: false
|
def is_unicode_emoji?(_), do: false
|
||||||
|
|
||||||
|
emoji_qualification_map =
|
||||||
|
emojis
|
||||||
|
|> Enum.filter(&String.contains?(&1, "\uFE0F"))
|
||||||
|
|> Combinations.variate_emoji_qualification()
|
||||||
|
|
||||||
|
for {qualified, unqualified_list} <- emoji_qualification_map do
|
||||||
|
for unqualified <- unqualified_list do
|
||||||
|
def fully_qualify_emoji(unquote(unqualified)), do: unquote(qualified)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fully_qualify_emoji(emoji), do: emoji
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Emoji.Combinations do
|
||||||
|
# FE0F is the emoji variation sequence. It is used for fully-qualifying
|
||||||
|
# emoji, and that includes emoji combinations.
|
||||||
|
# This code generates combinations per emoji: for each FE0F, all possible
|
||||||
|
# combinations of the character being removed or staying will be generated.
|
||||||
|
# This is made as an attempt to find all partially-qualified and unqualified
|
||||||
|
# versions of a fully-qualified emoji.
|
||||||
|
# I have found *no cases* for which this would be a problem, after browsing
|
||||||
|
# the entire emoji list in emoji-test.txt. This is safe, and, sadly, most
|
||||||
|
# likely sane too.
|
||||||
|
|
||||||
|
defp qualification_combinations(codepoints) do
|
||||||
|
qualification_combinations([[]], codepoints)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp qualification_combinations(acc, []), do: acc
|
||||||
|
|
||||||
|
defp qualification_combinations(acc, ["\uFE0F" | tail]) do
|
||||||
|
acc
|
||||||
|
|> Enum.flat_map(fn x -> [x, x ++ ["\uFE0F"]] end)
|
||||||
|
|> qualification_combinations(tail)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp qualification_combinations(acc, [codepoint | tail]) do
|
||||||
|
acc
|
||||||
|
|> Enum.map(&Kernel.++(&1, [codepoint]))
|
||||||
|
|> qualification_combinations(tail)
|
||||||
|
end
|
||||||
|
|
||||||
|
def variate_emoji_qualification(emoji) when is_binary(emoji) do
|
||||||
|
emoji
|
||||||
|
|> String.codepoints()
|
||||||
|
|> qualification_combinations()
|
||||||
|
|> Enum.map(&List.to_string/1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def variate_emoji_qualification(emoji) when is_list(emoji) do
|
||||||
|
emoji
|
||||||
|
|> Enum.map(fn emoji -> {emoji, variate_emoji_qualification(emoji)} end)
|
||||||
|
end
|
||||||
|
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue