summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml295
-rw-r--r--.gitlab/merge_request_templates/Default.md10
-rw-r--r--CHANGELOG.md4
-rw-r--r--Dockerfile3
-rw-r--r--changelog.d/3739.skip0
-rw-r--r--changelog.d/3848.add1
-rw-r--r--changelog.d/3870.skip0
-rw-r--r--changelog.d/3872.remove1
-rw-r--r--changelog.d/3873.fix1
-rw-r--r--changelog.d/3876.skip0
-rw-r--r--changelog.d/3877.skip0
-rw-r--r--changelog.d/3878.skip0
-rw-r--r--changelog.d/3882.add1
-rw-r--r--changelog.d/3893.skip0
-rw-r--r--changelog.d/changelog-improve.skip0
-rw-r--r--config/config.exs3
-rw-r--r--config/description.exs39
-rw-r--r--docs/clients.md15
-rw-r--r--docs/configuration/cheatsheet.md17
-rw-r--r--docs/development/API/admin_api.md2
-rw-r--r--lib/mix/tasks/pleroma/openapi_spec.ex67
-rw-r--r--lib/pleroma/bbs/authenticator.ex20
-rw-r--r--lib/pleroma/bbs/handler.ex246
-rw-r--r--lib/pleroma/emoji.ex53
-rw-r--r--lib/pleroma/object.ex26
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex2
-rw-r--r--lib/pleroma/web/activity_pub/builder.ex81
-rw-r--r--lib/pleroma/web/activity_pub/object_validator.ex15
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex (renamed from lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex)15
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex47
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/tag_validator.ex6
-rw-r--r--lib/pleroma/web/activity_pub/side_effects.ex2
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex2
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex79
-rw-r--r--lib/pleroma/web/admin_api/controllers/frontend_controller.ex25
-rw-r--r--lib/pleroma/web/admin_api/views/frontend_view.ex3
-rw-r--r--lib/pleroma/web/api_spec.ex24
-rw-r--r--lib/pleroma/web/api_spec/operations/account_operation.ex4
-rw-r--r--lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex10
-rw-r--r--lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex5
-rw-r--r--lib/pleroma/web/api_spec/operations/admin/status_operation.ex8
-rw-r--r--lib/pleroma/web/api_spec/operations/announcement_operation.ex4
-rw-r--r--lib/pleroma/web/api_spec/operations/directory_operation.ex2
-rw-r--r--lib/pleroma/web/api_spec/operations/instance_operation.ex4
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex6
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex28
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex2
-rw-r--r--lib/pleroma/web/api_spec/operations/status_operation.ex6
-rw-r--r--lib/pleroma/web/api_spec/operations/twitter_util_operation.ex25
-rw-r--r--lib/pleroma/web/api_spec/schemas/status.ex12
-rw-r--r--lib/pleroma/web/api_spec/scopes/compiler.ex82
-rw-r--r--lib/pleroma/web/api_spec/scopes/translator.ex10
-rw-r--r--lib/pleroma/web/common_api/utils.ex15
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex20
-rw-r--r--lib/pleroma/web/mastodon_api/views/instance_view.ex1
-rw-r--r--lib/pleroma/web/mastodon_api/views/notification_view.ex5
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex16
-rw-r--r--lib/pleroma/web/metadata/providers/rel_me.ex14
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex24
-rw-r--r--lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex17
-rw-r--r--lib/pleroma/web/plugs/uploaded_media.ex4
-rw-r--r--lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex2
-rw-r--r--mix.exs14
-rw-r--r--mix.lock91
-rw-r--r--priv/gettext/config_descriptions.pot48
-rw-r--r--priv/gettext/en/LC_MESSAGES/oauth_scopes.po264
-rw-r--r--priv/gettext/errors.pot15
-rw-r--r--priv/gettext/oauth_scopes.pot261
-rw-r--r--priv/scrubbers/default.ex81
-rw-r--r--test/fixtures/custom-emoji-reaction.json28
-rw-r--r--test/fixtures/fep-e232.json31
-rw-r--r--test/fixtures/hubzilla-actor.json1
-rw-r--r--test/fixtures/hubzilla-create-image.json1
-rw-r--r--test/mix/tasks/pleroma/openapi_spec_test.exs62
-rw-r--r--test/pleroma/bbs/handler_test.exs89
-rw-r--r--test/pleroma/object_test.exs38
-rw-r--r--test/pleroma/user/import_test.exs1
-rw-r--r--test/pleroma/user_search_test.exs1
-rw-r--r--test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs60
-rw-r--r--test/pleroma/web/activity_pub/side_effects_test.exs2
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs53
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/image_handling_test.exs50
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs2
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier_test.exs14
-rw-r--r--test/pleroma/web/activity_pub/utils_test.exs27
-rw-r--r--test/pleroma/web/admin_api/controllers/config_controller_test.exs9
-rw-r--r--test/pleroma/web/admin_api/controllers/frontend_controller_test.exs1
-rw-r--r--test/pleroma/web/api_spec/scopes/compiler_test.exs56
-rw-r--r--test/pleroma/web/common_api_test.exs11
-rw-r--r--test/pleroma/web/mastodon_api/controllers/account_controller_test.exs33
-rw-r--r--test/pleroma/web/mastodon_api/controllers/status_controller_test.exs33
-rw-r--r--test/pleroma/web/mastodon_api/update_credentials_test.exs4
-rw-r--r--test/pleroma/web/mastodon_api/views/notification_view_test.exs42
-rw-r--r--test/pleroma/web/mastodon_api/views/status_view_test.exs63
-rw-r--r--test/pleroma/web/metadata/providers/rel_me_test.exs17
-rw-r--r--test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs191
-rw-r--r--test/pleroma/web/plugs/uploaded_media_plug_test.exs4
-rw-r--r--test/test_helper.exs2
-rw-r--r--tools/check-changelog18
99 files changed, 2346 insertions, 803 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8b0381d11..8daa9f434 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -8,6 +8,13 @@ variables: &global_variables
DB_PORT: 5432
MIX_ENV: test
+workflow:
+ rules:
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+ - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
+ when: never
+ - if: $CI_COMMIT_BRANCH
+
cache: &global_cache_policy
key:
files:
@@ -17,12 +24,14 @@ cache: &global_cache_policy
- _build
stages:
+ - check-changelog
- build
- test
- benchmark
- deploy
- release
- docker
+ - docker-combine
before_script:
- echo $MIX_ENV
@@ -32,24 +41,43 @@ before_script:
after_script:
- rm -rf _build/*/lib/pleroma
+check-changelog:
+ stage: check-changelog
+ image: alpine
+ rules:
+ - if: $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == 'pleroma/pleroma' && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == 'weblate-extract'
+ when: never
+ - if: $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == 'pleroma/pleroma' && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == 'weblate'
+ when: never
+ - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop"
+ before_script: ''
+ after_script: ''
+ cache: {}
+ script:
+ - apk add git
+ - sh ./tools/check-changelog
+
+.build_changes_policy:
+ rules:
+ - changes:
+ - ".gitlab-ci.yml"
+ - "**/*.ex"
+ - "**/*.exs"
+ - "mix.lock"
+
build:
+ extends: .build_changes_policy
stage: build
- only:
- changes: &build_changes_policy
- - ".gitlab-ci.yml"
- - "**/*.ex"
- - "**/*.exs"
- - "mix.lock"
script:
- mix compile --force
spec-build:
stage: test
- only:
- changes:
- - ".gitlab-ci.yml"
- - "lib/pleroma/web/api_spec/**/*.ex"
- - "lib/pleroma/web/api_spec.ex"
+ rules:
+ - changes:
+ - ".gitlab-ci.yml"
+ - "lib/pleroma/web/api_spec/**/*.ex"
+ - "lib/pleroma/web/api_spec.ex"
artifacts:
paths:
- spec.json
@@ -71,9 +99,8 @@ benchmark:
- mix pleroma.load_testing
unit-testing:
+ extends: .build_changes_policy
stage: test
- only:
- changes: *build_changes_policy
cache: &testing_cache_policy
<<: *global_cache_policy
policy: pull
@@ -94,11 +121,10 @@ unit-testing:
path: coverage.xml
unit-testing-erratic:
+ extends: .build_changes_policy
stage: test
retry: 2
allow_failure: true
- only:
- changes: *build_changes_policy
cache: &testing_cache_policy
<<: *global_cache_policy
policy: pull
@@ -129,9 +155,8 @@ unit-testing-erratic:
# - mix test --trace --only federated
unit-testing-rum:
+ extends: .build_changes_policy
stage: test
- only:
- changes: *build_changes_policy
cache: *testing_cache_policy
services:
- name: minibikini/postgres-with-rum:12
@@ -147,10 +172,9 @@ unit-testing-rum:
- mix test --preload-modules
lint:
+ extends: .build_changes_policy
image: &current_elixir elixir:1.12-alpine
stage: test
- only:
- changes: *build_changes_policy
cache: *testing_cache_policy
before_script: &current_bfr_script
- apk update
@@ -162,18 +186,16 @@ lint:
- mix format --check-formatted
analysis:
+ extends: .build_changes_policy
stage: test
- only:
- changes: *build_changes_policy
cache: *testing_cache_policy
script:
- mix credo --strict --only=warnings,todo,fixme,consistency,readability
cycles:
+ extends: .build_changes_policy
image: *current_elixir
stage: test
- only:
- changes: *build_changes_policy
cache: {}
before_script: *current_bfr_script
script:
@@ -354,104 +376,167 @@ arm64-musl:
before_script: *before-release-musl
script: *release
-docker:
+.kaniko:
stage: docker
- image: docker:latest
+ image:
+ name: gcr.io/kaniko-project/executor:debug
+ entrypoint: [""]
cache: {}
dependencies: []
- variables: &docker-variables
- DOCKER_DRIVER: overlay2
- DOCKER_HOST: unix:///var/run/docker.sock
- IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
- IMAGE_TAG_SLUG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
- IMAGE_TAG_LATEST: $CI_REGISTRY_IMAGE:latest
- IMAGE_TAG_LATEST_STABLE: $CI_REGISTRY_IMAGE:latest-stable
- DOCKER_BUILDX_URL: https://github.com/docker/buildx/releases/download/v0.6.3/buildx-v0.6.3.linux-amd64
- DOCKER_BUILDX_HASH: 980e6b9655f971991fbbb5fd6cd19f1672386195
- before_script: &before-docker
- - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- - docker pull $IMAGE_TAG_SLUG || true
+ before_script: &before-kaniko
- export CI_JOB_TIMESTAMP=$(date --utc -Iseconds)
- export CI_VCS_REF=$CI_COMMIT_SHORT_SHA
- allow_failure: true
- script:
- - mkdir -p /root/.docker/cli-plugins
- - wget "${DOCKER_BUILDX_URL}" -O ~/.docker/cli-plugins/docker-buildx
- - echo "${DOCKER_BUILDX_HASH} /root/.docker/cli-plugins/docker-buildx" | sha1sum -c
- - chmod +x ~/.docker/cli-plugins/docker-buildx
- - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- - docker buildx create --name mbuilder --driver docker-container --use
- - docker buildx inspect --bootstrap
- - docker buildx build --platform linux/amd64,linux/arm/v7,linux/arm64/v8 --push --cache-from $IMAGE_TAG_SLUG --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP -t $IMAGE_TAG -t $IMAGE_TAG_SLUG -t $IMAGE_TAG_LATEST .
- tags:
- - dind
+ - export IMAGE_TAG=$CI_REGISTRY_IMAGE/$BUILD_ARCH_IMG_SUFFIX:$CI_COMMIT_SHORT_SHA
+ - export IMAGE_TAG_SLUG=$CI_REGISTRY_IMAGE/$BUILD_ARCH_IMG_SUFFIX:$CI_COMMIT_REF_SLUG
+ - export IMAGE_TAG_LATEST=$CI_REGISTRY_IMAGE/$BUILD_ARCH_IMG_SUFFIX:latest
+ - export IMAGE_TAG_LATEST_STABLE=$CI_REGISTRY_IMAGE/$BUILD_ARCH_IMG_SUFFIX:latest-stable
+ - mkdir -p /kaniko/.docker
+ - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
+
+.kaniko-latest:
+ extends: .kaniko
only:
- develop@pleroma/pleroma
-
-docker-stable:
- stage: docker
- image: docker:latest
- cache: {}
- dependencies: []
- variables: *docker-variables
- before_script: *before-docker
- allow_failure: true
script:
- - mkdir -p /root/.docker/cli-plugins
- - wget "${DOCKER_BUILDX_URL}" -O ~/.docker/cli-plugins/docker-buildx
- - echo "${DOCKER_BUILDX_HASH} /root/.docker/cli-plugins/docker-buildx" | sha1sum -c
- - chmod +x ~/.docker/cli-plugins/docker-buildx
- - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- - docker buildx create --name mbuilder --driver docker-container --use
- - docker buildx inspect --bootstrap
- - docker buildx build --platform linux/amd64,linux/arm/v7,linux/arm64/v8 --push --cache-from $IMAGE_TAG_SLUG --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP -t $IMAGE_TAG -t $IMAGE_TAG_SLUG -t $IMAGE_TAG_LATEST_STABLE .
- tags:
- - dind
+ - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --custom-platform=$BUILD_ARCH --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP --build-arg ELIXIR_IMG=$ELIXIR_IMG --destination $IMAGE_TAG --destination $IMAGE_TAG_SLUG --destination $IMAGE_TAG_LATEST
+
+.kaniko-stable:
+ extends: .kaniko
only:
- stable@pleroma/pleroma
+ script:
+ - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --custom-platform=$BUILD_ARCH --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP --build-arg ELIXIR_IMG=$ELIXIR_IMG --destination $IMAGE_TAG --destination $IMAGE_TAG_SLUG --destination $IMAGE_TAG_LATEST_STABLE
-docker-release:
- stage: docker
- image: docker:latest
- cache: {}
- dependencies: []
- variables: *docker-variables
- before_script: *before-docker
- allow_failure: true
+.kaniko-release:
+ extends: .kaniko
+ only:
+ - /^release/.*$/@pleroma/pleroma
script:
+ - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --custom-platform=$BUILD_ARCH --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP --build-arg ELIXIR_IMG=$ELIXIR_IMG --destination $IMAGE_TAG --destination $IMAGE_TAG_SLUG
+
+.kaniko-adhoc:
+ extends: .kaniko
+ only:
+ - /^build-docker/.*$/@pleroma/pleroma
script:
- - mkdir -p /root/.docker/cli-plugins
- - wget "${DOCKER_BUILDX_URL}" -O ~/.docker/cli-plugins/docker-buildx
- - echo "${DOCKER_BUILDX_HASH} /root/.docker/cli-plugins/docker-buildx" | sha1sum -c
- - chmod +x ~/.docker/cli-plugins/docker-buildx
- - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- - docker buildx create --name mbuilder --driver docker-container --use
- - docker buildx inspect --bootstrap
- - docker buildx build --platform linux/amd64,linux/arm/v7,linux/arm64/v8 --push --cache-from $IMAGE_TAG_SLUG --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP -t $IMAGE_TAG -t $IMAGE_TAG_SLUG .
+ - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --custom-platform=$BUILD_ARCH --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP --build-arg ELIXIR_IMG=$ELIXIR_IMG --destination $IMAGE_TAG --destination $IMAGE_TAG_SLUG
+
+.kaniko:linux/amd64:
+ variables:
+ BUILD_ARCH: linux/amd64
+ BUILD_ARCH_IMG_SUFFIX: linux-amd64
+ ELIXIR_IMG: hexpm/elixir
tags:
- - dind
- only:
- - /^release/.*$/@pleroma/pleroma
+ - amd64
-docker-adhoc:
- stage: docker
- image: docker:latest
+.kaniko:linux/arm64:
+ variables:
+ BUILD_ARCH: linux/arm64/v8
+ BUILD_ARCH_IMG_SUFFIX: linux-arm64-v8
+ ELIXIR_IMG: hexpm/elixir
+ tags:
+ - arm
+
+.kaniko:linux/arm:
+ variables:
+ BUILD_ARCH: linux/arm/v7
+ BUILD_ARCH_IMG_SUFFIX: linux-arm-v7
+ ELIXIR_IMG: git.pleroma.social:5050/pleroma/ci-image/elixir-linux-arm-v7
+ tags:
+ - arm32-specified
+
+kaniko-latest:linux/amd64:
+ extends:
+ - .kaniko-latest
+ - .kaniko:linux/amd64
+
+kaniko-latest:linux/arm64:
+ extends:
+ - .kaniko-latest
+ - .kaniko:linux/arm64
+
+kaniko-latest:linux/arm:
+ extends:
+ - .kaniko-latest
+ - .kaniko:linux/arm
+
+kaniko-stable:linux/amd64:
+ extends:
+ - .kaniko-stable
+ - .kaniko:linux/amd64
+
+kaniko-stable:linux/arm64:
+ extends:
+ - .kaniko-stable
+ - .kaniko:linux/arm64
+
+kaniko-stable:linux/arm:
+ extends:
+ - .kaniko-stable
+ - .kaniko:linux/arm
+
+kaniko-release:linux/amd64:
+ extends:
+ - .kaniko-release
+ - .kaniko:linux/amd64
+
+kaniko-release:linux/arm64:
+ extends:
+ - .kaniko-release
+ - .kaniko:linux/arm64
+
+kaniko-release:linux/arm:
+ extends:
+ - .kaniko-release
+ - .kaniko:linux/arm
+
+.docker-combine:
+ stage: docker-combine
+ image: docker:cli
cache: {}
- dependencies: []
- variables: *docker-variables
- before_script: *before-docker
- allow_failure: true
+ before_script:
+ - 'BUILD_ARCHES="linux-amd64 linux-arm64-v8 linux-arm-v7"'
+ - export IMAGE_TAG=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
+ - export IMAGE_TAG_SLUG=$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
+ - export IMAGE_TAG_LATEST=$CI_REGISTRY_IMAGE:latest
+ - export IMAGE_TAG_LATEST_STABLE=$CI_REGISTRY_IMAGE:latest-stable
+ - 'IMAGES=; for arch in $BUILD_ARCHES; do IMAGES="$IMAGES $CI_REGISTRY_IMAGE/$arch:$CI_COMMIT_SHORT_SHA"; done'
+ - 'IMAGES_SLUG=; for arch in $BUILD_ARCHES; do IMAGES_SLUG="$IMAGES_SLUG $CI_REGISTRY_IMAGE/$arch:$CI_COMMIT_REF_SLUG"; done'
+ - 'IMAGES_LATEST=; for arch in $BUILD_ARCHES; do IMAGES_LATEST="$IMAGES_LATEST $CI_REGISTRY_IMAGE/$arch:latest"; done'
+ - 'IMAGES_LATEST_STABLE=; for arch in $BUILD_ARCHES; do IMAGES_LATEST_STABLE="$IMAGES_LATEST_STABLE $CI_REGISTRY_IMAGE/$arch:latest"; done'
+ - mkdir -p ~/.docker
+ - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
+
+docker-combine:latest:
+ extends: .docker-combine
+ only:
+ - develop@pleroma/pleroma
script:
+ - 'docker manifest create $IMAGE_TAG $IMAGES'
+ - 'docker manifest push $IMAGE_TAG'
+ - 'docker manifest create $IMAGE_TAG_SLUG $IMAGES_SLUG'
+ - 'docker manifest push $IMAGE_TAG_SLUG'
+ - 'docker manifest create $IMAGE_TAG_LATEST $IMAGES_LATEST'
+ - 'docker manifest push $IMAGE_TAG_LATEST'
+
+docker-combine:stable:
+ extends: .docker-combine
+ only:
+ - stable@pleroma/pleroma
script:
- - mkdir -p /root/.docker/cli-plugins
- - wget "${DOCKER_BUILDX_URL}" -O ~/.docker/cli-plugins/docker-buildx
- - echo "${DOCKER_BUILDX_HASH} /root/.docker/cli-plugins/docker-buildx" | sha1sum -c
- - chmod +x ~/.docker/cli-plugins/docker-buildx
- - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- - docker buildx create --name mbuilder --driver docker-container --use
- - docker buildx inspect --bootstrap
- - docker buildx build --platform linux/amd64,linux/arm/v7,linux/arm64/v8 --push --cache-from $IMAGE_TAG_SLUG --build-arg VCS_REF=$CI_VCS_REF --build-arg BUILD_DATE=$CI_JOB_TIMESTAMP -t $IMAGE_TAG -t $IMAGE_TAG_SLUG .
- tags:
- - dind
+ - 'docker manifest create $IMAGE_TAG $IMAGES'
+ - 'docker manifest push $IMAGE_TAG'
+ - 'docker manifest create $IMAGE_TAG_SLUG $IMAGES_SLUG'
+ - 'docker manifest push $IMAGE_TAG_SLUG'
+ - 'docker manifest create $IMAGE_TAG_LATEST_STABLE $IMAGES_LATEST_STABLE'
+ - 'docker manifest push $IMAGE_TAG_LATEST_STABLE'
+
+docker-combine:release:
+ extends: .docker-combine
only:
- - /^build-docker/.*$/@pleroma/pleroma
+ - /^release/.*$/@pleroma/pleroma
+ script:
+ - 'docker manifest create $IMAGE_TAG $IMAGES'
+ - 'docker manifest push $IMAGE_TAG'
+ - 'docker manifest create $IMAGE_TAG_SLUG $IMAGES_SLUG'
+ - 'docker manifest push $IMAGE_TAG_SLUG'
diff --git a/.gitlab/merge_request_templates/Default.md b/.gitlab/merge_request_templates/Default.md
new file mode 100644
index 000000000..fdf219f99
--- /dev/null
+++ b/.gitlab/merge_request_templates/Default.md
@@ -0,0 +1,10 @@
+### Checklist
+- [ ] Adding a changelog: In the `changelog.d` directory, create a file named `<code>.<type>`.
+
+ `<code>` can be anything, but we recommend using a more or less unique identifier to avoid collisions, such as the branch name.
+
+ `<type>` can be `add`, `remove`, `fix`, `security` or `skip`. `skip` is only used if there is no user-visible change in the MR (for example, only editing comments in the code). Otherwise, choose a type that corresponds to your change.
+
+ In the file, write the changelog entry. For example, if an MR adds group functionality, we can create a file named `group.add` and write `Add group functionality` in it.
+
+ If one changelog entry is not enough, you may add more. But that might mean you can split it into two MRs. Only use more than one changelog entry if you really need to (for example, when one change in the code fix two different bugs, or when refactoring).
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6fc6aaee..42a1bbb8f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,10 +9,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
### Added
+- Support for Image activities, namely from Hubzilla
### Fixed
+- rel="me" was missing its cache
+
### Removed
+- BREAKING: Support for passwords generated with `crypt(3)` (Gnu Social migration artifact)
## 2.5.2
diff --git a/Dockerfile b/Dockerfile
index 8c3ff3ac5..310d18104 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,8 +1,9 @@
+ARG ELIXIR_IMG=hexpm/elixir
ARG ELIXIR_VER=1.11.4
ARG ERLANG_VER=24.2.1
ARG ALPINE_VER=3.17.0
-FROM hexpm/elixir:${ELIXIR_VER}-erlang-${ERLANG_VER}-alpine-${ALPINE_VER} as build
+FROM ${ELIXIR_IMG}:${ELIXIR_VER}-erlang-${ERLANG_VER}-alpine-${ALPINE_VER} as build
COPY . .
diff --git a/changelog.d/3739.skip b/changelog.d/3739.skip
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/changelog.d/3739.skip
diff --git a/changelog.d/3848.add b/changelog.d/3848.add
new file mode 100644
index 000000000..d7b1b0a84
--- /dev/null
+++ b/changelog.d/3848.add
@@ -0,0 +1 @@
+Add OAuth scope descriptions
diff --git a/changelog.d/3870.skip b/changelog.d/3870.skip
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/changelog.d/3870.skip
diff --git a/changelog.d/3872.remove b/changelog.d/3872.remove
new file mode 100644
index 000000000..54cbb660e
--- /dev/null
+++ b/changelog.d/3872.remove
@@ -0,0 +1 @@
+remove BBS/SSH feature, replaced by an external bridge. \ No newline at end of file
diff --git a/changelog.d/3873.fix b/changelog.d/3873.fix
new file mode 100644
index 000000000..4699f7b58
--- /dev/null
+++ b/changelog.d/3873.fix
@@ -0,0 +1 @@
+UploadedMedia: Add missing disposition_type to Content-Disposition \ No newline at end of file
diff --git a/changelog.d/3876.skip b/changelog.d/3876.skip
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/changelog.d/3876.skip
diff --git a/changelog.d/3877.skip b/changelog.d/3877.skip
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/changelog.d/3877.skip
diff --git a/changelog.d/3878.skip b/changelog.d/3878.skip
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/changelog.d/3878.skip
diff --git a/changelog.d/3882.add b/changelog.d/3882.add
new file mode 100644
index 000000000..4712de1dc
--- /dev/null
+++ b/changelog.d/3882.add
@@ -0,0 +1 @@
+Allow lang attribute in status text
diff --git a/changelog.d/3893.skip b/changelog.d/3893.skip
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/changelog.d/3893.skip
diff --git a/changelog.d/changelog-improve.skip b/changelog.d/changelog-improve.skip
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/changelog.d/changelog-improve.skip
diff --git a/config/config.exs b/config/config.exs
index e41ec2f91..178b6be99 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -617,9 +617,6 @@ config :pleroma, :ldap,
base: System.get_env("LDAP_BASE") || "dc=example,dc=com",
uid: System.get_env("LDAP_UID") || "cn"
-config :esshd,
- enabled: false
-
oauth_consumer_strategies =
System.get_env("OAUTH_CONSUMER_STRATEGIES")
|> to_string()
diff --git a/config/description.exs b/config/description.exs
index 78dc8770d..5f8add8a4 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -2629,45 +2629,6 @@ config :pleroma, :config_description, [
]
},
%{
- group: :esshd,
- label: "ESSHD",
- type: :group,
- description:
- "Before enabling this you must add :esshd to mix.exs as one of the extra_applications " <>
- "and generate host keys in your priv dir with ssh-keygen -m PEM -N \"\" -b 2048 -t rsa -f ssh_host_rsa_key",
- children: [
- %{
- key: :enabled,
- type: :boolean,
- description: "Enables SSH"
- },
- %{
- key: :priv_dir,
- type: :string,
- description: "Dir with SSH keys",
- suggestions: ["/some/path/ssh_keys"]
- },
- %{
- key: :handler,
- type: :string,
- description: "Handler module",
- suggestions: ["Pleroma.BBS.Handler"]
- },
- %{
- key: :port,
- type: :integer,
- description: "Port to connect",
- suggestions: [10_022]
- },
- %{
- key: :password_authenticator,
- type: :string,
- description: "Authenticator module",
- suggestions: ["Pleroma.BBS.Authenticator"]
- }
- ]
- },
- %{
group: :mime,
label: "Mime Types",
type: :group,
diff --git a/docs/clients.md b/docs/clients.md
index 31d2d27c3..ad7eb7807 100644
--- a/docs/clients.md
+++ b/docs/clients.md
@@ -3,12 +3,6 @@ Note: Additional clients may be working but theses are officially supporting Ple
Feel free to contact us to be added to this list!
## Desktop
-### Roma for Desktop
-- Homepage: <https://www.pleroma.com/#desktopApp>
-- Source Code: <https://github.com/roma-apps/roma-desktop>
-- Platforms: Windows, Mac, Linux
-- Features: MastoAPI, Streaming Ready
-
### Social
- Source Code: <https://gitlab.gnome.org/World/Social>
- Contact: [@brainblasted@social.libre.fi](https://social.libre.fi/users/brainblasted)
@@ -19,7 +13,14 @@ Feel free to contact us to be added to this list!
### Whalebird
- Homepage: <https://whalebird.social/>
- Source Code: <https://github.com/h3poteto/whalebird-desktop>
-- Contact: [@h3poteto@pleroma.io](https://pleroma.io/users/h3poteto)
+- Contact: [@whalebird@pleroma.io](https://pleroma.io/users/whalebird)
+- Platforms: Windows, Mac, Linux
+- Features: MastoAPI, Streaming Ready
+
+### Fedistar
+- Homepage: <https://fedistar.net>
+- Source Code: <https://github.com/h3poteto/fedistar>
+- Contact: [@fedistar@pleroma.io](https://pleroma.io/users/fedistar)
- Platforms: Windows, Mac, Linux
- Features: MastoAPI, Streaming Ready
diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md
index bbdf30a0f..70abe3e0c 100644
--- a/docs/configuration/cheatsheet.md
+++ b/docs/configuration/cheatsheet.md
@@ -873,21 +873,8 @@ This will probably take a long time.
### BBS / SSH access
-To enable simple command line interface accessible over ssh, add a setting like this to your configuration file:
-
-```exs
-app_dir = File.cwd!
-priv_dir = Path.join([app_dir, "priv/ssh_keys"])
-
-config :esshd,
- enabled: true,
- priv_dir: priv_dir,
- handler: "Pleroma.BBS.Handler",
- port: 10_022,
- password_authenticator: "Pleroma.BBS.Authenticator"
-```
-
-Feel free to adjust the priv_dir and port number. Then you will have to create the key for the keys (in the example `priv/ssh_keys`) and create the host keys with `ssh-keygen -m PEM -N "" -b 2048 -t rsa -f ssh_host_rsa_key`. After restarting, you should be able to connect to your Pleroma instance with `ssh username@server -p $PORT`
+This feature has been removed from Pleroma core.
+However, a client has been made and is available at https://git.pleroma.social/Duponin/sshocial.
### :gopher
* `enabled`: Enables the gopher interface
diff --git a/docs/development/API/admin_api.md b/docs/development/API/admin_api.md
index f6e9f7d2a..7d31ee262 100644
--- a/docs/development/API/admin_api.md
+++ b/docs/development/API/admin_api.md
@@ -1585,6 +1585,7 @@ Returns the content of the document
"build_url": "https://git.pleroma.social/pleroma/fedi-fe/-/jobs/artifacts/${ref}/download?job=build",
"git": "https://git.pleroma.social/pleroma/fedi-fe",
"installed": true,
+ "installed_refs": ["master"],
"name": "fedi-fe",
"ref": "master"
},
@@ -1592,6 +1593,7 @@ Returns the content of the document
"build_url": "https://git.pleroma.social/lambadalambda/kenoma/-/jobs/artifacts/${ref}/download?job=build",
"git": "https://git.pleroma.social/lambadalambda/kenoma",
"installed": false,
+ "installed_refs": [],
"name": "kenoma",
"ref": "master"
}
diff --git a/lib/mix/tasks/pleroma/openapi_spec.ex b/lib/mix/tasks/pleroma/openapi_spec.ex
index 884f931f8..1ea468476 100644
--- a/lib/mix/tasks/pleroma/openapi_spec.ex
+++ b/lib/mix/tasks/pleroma/openapi_spec.ex
@@ -6,7 +6,70 @@ defmodule Mix.Tasks.Pleroma.OpenapiSpec do
def run([path]) do
# Load Pleroma application to get version info
Application.load(:pleroma)
- spec = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
- File.write(path, spec)
+
+ spec_json = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
+ # to get rid of the structs
+ spec_regened = spec_json |> Jason.decode!()
+
+ check_specs!(spec_regened)
+
+ File.write(path, spec_json)
+ end
+
+ defp check_specs!(spec) do
+ with :ok <- check_specs(spec) do
+ :ok
+ else
+ {_, errors} ->
+ IO.puts(IO.ANSI.format([:red, :bright, "Spec check failed, errors:"]))
+ Enum.map(errors, &IO.puts/1)
+
+ raise "Spec check failed"
+ end
+ end
+
+ def check_specs(spec) do
+ errors =
+ spec["paths"]
+ |> Enum.flat_map(fn {path, %{} = endpoints} ->
+ Enum.map(
+ endpoints,
+ fn {method, endpoint} ->
+ with :ok <- check_endpoint(spec, endpoint) do
+ :ok
+ else
+ error ->
+ "#{endpoint["operationId"]} (#{method} #{path}): #{error}"
+ end
+ end
+ )
+ |> Enum.reject(fn res -> res == :ok end)
+ end)
+
+ if errors == [] do
+ :ok
+ else
+ {:error, errors}
+ end
+ end
+
+ defp check_endpoint(spec, endpoint) do
+ valid_tags = available_tags(spec)
+
+ with {_, [_ | _] = tags} <- {:tags, endpoint["tags"]},
+ {_, []} <- {:unavailable, Enum.reject(tags, &(&1 in valid_tags))} do
+ :ok
+ else
+ {:tags, _} ->
+ "No tags specified"
+
+ {:unavailable, tags} ->
+ "Tags #{inspect(tags)} not available. Please add it in \"x-tagGroups\" in Pleroma.Web.ApiSpec"
+ end
+ end
+
+ defp available_tags(spec) do
+ spec["x-tagGroups"]
+ |> Enum.flat_map(fn %{"tags" => tags} -> tags end)
end
end
diff --git a/lib/pleroma/bbs/authenticator.ex b/lib/pleroma/bbs/authenticator.ex
deleted file mode 100644
index 0f7543ff5..000000000
--- a/lib/pleroma/bbs/authenticator.ex
+++ /dev/null
@@ -1,20 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.BBS.Authenticator do
- use Sshd.PasswordAuthenticator
- alias Pleroma.User
- alias Pleroma.Web.Plugs.AuthenticationPlug
-
- def authenticate(username, password) do
- username = to_string(username)
- password = to_string(password)
-
- with %User{} = user <- User.get_by_nickname(username) do
- AuthenticationPlug.checkpw(password, user.password_hash)
- else
- _e -> false
- end
- end
-end
diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex
deleted file mode 100644
index 27799338f..000000000
--- a/lib/pleroma/bbs/handler.ex
+++ /dev/null
@@ -1,246 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.BBS.Handler do
- use Sshd.ShellHandler
- alias Pleroma.Activity
- alias Pleroma.HTML
- alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.CommonAPI
-
- def on_shell(username, _pubkey, _ip, _port) do
- :ok = IO.puts("Welcome to #{Pleroma.Config.get([:instance, :name])}!")
- user = Pleroma.User.get_cached_by_nickname(to_string(username))
- Logger.debug("#{inspect(user)}")
- loop(run_state(user: user))
- end
-
- def on_connect(username, ip, port, method) do
- Logger.debug(fn ->
- """
- Incoming SSH shell #{inspect(self())} requested for #{username} from #{inspect(ip)}:#{inspect(port)} using #{inspect(method)}
- """
- end)
- end
-
- def on_disconnect(username, ip, port) do
- Logger.debug(fn ->
- "Disconnecting SSH shell for #{username} from #{inspect(ip)}:#{inspect(port)}"
- end)
- end
-
- defp loop(state) do
- self_pid = self()
- counter = state.counter
- prefix = state.prefix
- user = state.user
-
- input = spawn(fn -> io_get(self_pid, prefix, counter, user.nickname) end)
- wait_input(state, input)
- end
-
- def puts_activity(activity) do
- status = Pleroma.Web.MastodonAPI.StatusView.render("show.json", %{activity: activity})
-
- IO.puts("-- #{status.id} by #{status.account.display_name} (#{status.account.acct})")
-
- status.content
- |> String.split("<br/>")
- |> Enum.map(&HTML.strip_tags/1)
- |> Enum.map(&HtmlEntities.decode/1)
- |> Enum.map(&IO.puts/1)
- end
-
- def puts_notification(activity, user) do
- notification =
- Pleroma.Web.MastodonAPI.NotificationView.render("show.json", %{
- notification: activity,
- for: user
- })
-
- IO.puts(
- "== (#{notification.type}) #{notification.status.id} by #{notification.account.display_name} (#{notification.account.acct})"
- )
-
- notification.status.content
- |> String.split("<br/>")
- |> Enum.map(&HTML.strip_tags/1)
- |> Enum.map(&HtmlEntities.decode/1)
- |> (fn x ->
- case x do
- [content] ->
- "> " <> content
-
- [head | _tail] ->
- # "> " <> hd <> "..."
- head
- |> String.slice(1, 80)
- |> (fn x -> "> " <> x <> "..." end).()
- end
- end).()
- |> IO.puts()
-
- IO.puts("")
- end
-
- def handle_command(state, "help") do
- IO.puts("Available commands:")
- IO.puts("help - This help")
- IO.puts("home - Show the home timeline")
- IO.puts("p <text> - Post the given text")
- IO.puts("r <id> <text> - Reply to the post with the given id")
- IO.puts("t <id> - Show a thread from the given id")
- IO.puts("n - Show notifications")
- IO.puts("n read - Mark all notifactions as read")
- IO.puts("f <id> - Favourites the post with the given id")
- IO.puts("R <id> - Repeat the post with the given id")
- IO.puts("quit - Quit")
-
- state
- end
-
- def handle_command(%{user: user} = state, "r " <> text) do
- text = String.trim(text)
- [activity_id, rest] = String.split(text, " ", parts: 2)
-
- with %Activity{} <- Activity.get_by_id(activity_id),
- {:ok, _activity} <-
- CommonAPI.post(user, %{status: rest, in_reply_to_status_id: activity_id}) do
- IO.puts("Replied!")
- else
- _e -> IO.puts("Could not reply...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "t " <> activity_id) do
- with %Activity{} = activity <- Activity.get_by_id(activity_id) do
- activities =
- ActivityPub.fetch_activities_for_context(activity.data["context"], %{
- blocking_user: user,
- user: user,
- exclude_id: activity.id
- })
-
- case activities do
- [] ->
- activity_id
- |> Activity.get_by_id()
- |> puts_activity()
-
- _ ->
- activities
- |> Enum.reverse()
- |> Enum.each(&puts_activity/1)
- end
- else
- _e -> IO.puts("Could not show this thread...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "n read") do
- Pleroma.Notification.clear(user)
- IO.puts("All notifications were marked as read")
-
- state
- end
-
- def handle_command(%{user: user} = state, "n") do
- user
- |> Pleroma.Web.MastodonAPI.MastodonAPI.get_notifications(%{})
- |> Enum.each(&puts_notification(&1, user))
-
- state
- end
-
- def handle_command(%{user: user} = state, "p " <> text) do
- text = String.trim(text)
-
- with {:ok, activity} <- CommonAPI.post(user, %{status: text}) do
- IO.puts("Posted! ID: #{activity.id}")
- else
- _e -> IO.puts("Could not post...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "f " <> id) do
- id = String.trim(id)
-
- with %Activity{} = activity <- Activity.get_by_id(id),
- {:ok, _activity} <- CommonAPI.favorite(user, activity) do
- IO.puts("Favourited!")
- else
- _e -> IO.puts("Could not Favourite...")
- end
-
- state
- end
-
- def handle_command(state, "home") do
- user = state.user
-
- params =
- %{}
- |> Map.put(:type, ["Create"])
- |> Map.put(:blocking_user, user)
- |> Map.put(:muting_user, user)
- |> Map.put(:user, user)
-
- activities =
- [user.ap_id | Pleroma.User.following(user)]
- |> ActivityPub.fetch_activities(params)
-
- Enum.each(activities, fn activity ->
- puts_activity(activity)
- end)
-
- state
- end
-
- def handle_command(state, command) do
- IO.puts("Unknown command '#{command}'")
- state
- end
-
- defp wait_input(state, input) do
- receive do
- {:input, ^input, "quit\n"} ->
- IO.puts("Exiting...")
-
- {:input, ^input, code} when is_binary(code) ->
- code = String.trim(code)
-
- state = handle_command(state, code)
-
- loop(%{state | counter: state.counter + 1})
-
- {:input, ^input, {:error, :interrupted}} ->
- IO.puts("Caught Ctrl+C...")
- loop(%{state | counter: state.counter + 1})
-
- {:input, ^input, msg} ->
- :ok = Logger.warn("received unknown message: #{inspect(msg)}")
- loop(%{state | counter: state.counter + 1})
- end
- end
-
- defp run_state(opts) do
- %{prefix: "pleroma", counter: 1, user: opts[:user]}
- end
-
- defp io_get(pid, prefix, counter, username) do
- prompt = prompt(prefix, counter, username)
- send(pid, {:input, self(), IO.gets(:stdio, prompt)})
- end
-
- defp prompt(prefix, counter, username) do
- prompt = "#{username}@#{prefix}:#{counter}>"
- prompt <> " "
- end
-end
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
index dd65d56ae..43a3447c3 100644
--- a/lib/pleroma/emoji.ex
+++ b/lib/pleroma/emoji.ex
@@ -51,6 +51,8 @@ defmodule Pleroma.Emoji do
@doc "Returns the path of the emoji `name`."
@spec get(String.t()) :: String.t() | nil
def get(name) do
+ name = maybe_strip_name(name)
+
case :ets.lookup(@ets, name) do
[{_, path}] -> path
_ -> nil
@@ -139,6 +141,57 @@ defmodule Pleroma.Emoji do
def is_unicode_emoji?(_), do: false
+ @emoji_regex ~r/:[A-Za-z0-9_-]+(@.+)?:/
+
+ def is_custom_emoji?(s) when is_binary(s), do: Regex.match?(@emoji_regex, s)
+
+ def is_custom_emoji?(_), do: false
+
+ def maybe_strip_name(name) when is_binary(name), do: String.trim(name, ":")
+
+ def maybe_strip_name(name), do: name
+
+ def maybe_quote(name) when is_binary(name) do
+ if is_unicode_emoji?(name) do
+ name
+ else
+ if String.starts_with?(name, ":") do
+ name
+ else
+ ":#{name}:"
+ end
+ end
+ end
+
+ def maybe_quote(name), do: name
+
+ def emoji_url(%{"type" => "EmojiReact", "content" => _, "tag" => []}), do: nil
+
+ def emoji_url(%{"type" => "EmojiReact", "content" => emoji, "tag" => tags}) do
+ emoji = maybe_strip_name(emoji)
+
+ tag =
+ tags
+ |> Enum.find(fn tag ->
+ tag["type"] == "Emoji" && !is_nil(tag["name"]) && tag["name"] == emoji
+ end)
+
+ if is_nil(tag) do
+ nil
+ else
+ tag
+ |> Map.get("icon")
+ |> Map.get("url")
+ end
+ end
+
+ def emoji_url(_), do: nil
+
+ def emoji_name_with_instance(name, url) do
+ url = url |> URI.parse() |> Map.get(:host)
+ "#{name}@#{url}"
+ end
+
emoji_qualification_map =
emojis
|> Enum.filter(&String.contains?(&1, "\uFE0F"))
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 38accae5d..aa137d250 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -425,4 +425,30 @@ defmodule Pleroma.Object do
end
def object_data_hashtags(_), do: []
+
+ def get_emoji_reactions(object) do
+ reactions = object.data["reactions"]
+
+ if is_list(reactions) or is_map(reactions) do
+ reactions
+ |> Enum.map(fn
+ [_emoji, users, _maybe_url] = item when is_list(users) ->
+ item
+
+ [emoji, users] when is_list(users) ->
+ [emoji, users, nil]
+
+ # This case is here to process the Map situation, which will happen
+ # only with the legacy two-value format.
+ {emoji, users} when is_list(users) ->
+ [emoji, users, nil]
+
+ _ ->
+ nil
+ end)
+ |> Enum.reject(&is_nil/1)
+ else
+ []
+ end
+ end
end
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 1ab2db94a..f22756015 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -96,7 +96,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp increase_replies_count_if_reply(_create_data), do: :noop
- @object_types ~w[ChatMessage Question Answer Audio Video Event Article Note Page]
+ @object_types ~w[ChatMessage Question Answer Audio Video Image Event Article Note Page]
@impl true
def persist(%{"type" => type} = object, meta) when type in @object_types do
with {:ok, object} <- Object.create(object) do
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
index 532047599..8eab3a241 100644
--- a/lib/pleroma/web/activity_pub/builder.ex
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -16,6 +16,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI.ActivityDraft
+ alias Pleroma.Web.Endpoint
require Pleroma.Constants
@@ -54,13 +55,87 @@ defmodule Pleroma.Web.ActivityPub.Builder do
{:ok, data, []}
end
+ defp unicode_emoji_react(_object, data, emoji) do
+ data
+ |> Map.put("content", emoji)
+ |> Map.put("type", "EmojiReact")
+ end
+
+ defp add_emoji_content(data, emoji, url) do
+ tag = [
+ %{
+ "id" => url,
+ "type" => "Emoji",
+ "name" => Emoji.maybe_quote(emoji),
+ "icon" => %{
+ "type" => "Image",
+ "url" => url
+ }
+ }
+ ]
+
+ data
+ |> Map.put("content", Emoji.maybe_quote(emoji))
+ |> Map.put("type", "EmojiReact")
+ |> Map.put("tag", tag)
+ end
+
+ defp remote_custom_emoji_react(
+ %{data: %{"reactions" => existing_reactions}},
+ data,
+ emoji
+ ) do
+ [emoji_code, instance] = String.split(Emoji.maybe_strip_name(emoji), "@")
+
+ matching_reaction =
+ Enum.find(
+ existing_reactions,
+ fn [name, _, url] ->
+ if url != nil do
+ url = URI.parse(url)
+ url.host == instance && name == emoji_code
+ end
+ end
+ )
+
+ if matching_reaction do
+ [name, _, url] = matching_reaction
+ add_emoji_content(data, name, url)
+ else
+ {:error, "Could not react"}
+ end
+ end
+
+ defp remote_custom_emoji_react(_object, _data, _emoji) do
+ {:error, "Could not react"}
+ end
+
+ defp local_custom_emoji_react(data, emoji) do
+ with %{file: path} = emojo <- Emoji.get(emoji) do
+ url = "#{Endpoint.url()}#{path}"
+ add_emoji_content(data, emojo.code, url)
+ else
+ _ -> {:error, "Emoji does not exist"}
+ end
+ end
+
+ defp custom_emoji_react(object, data, emoji) do
+ if String.contains?(emoji, "@") do
+ remote_custom_emoji_react(object, data, emoji)
+ else
+ local_custom_emoji_react(data, emoji)
+ end
+ end
+
@spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
def emoji_react(actor, object, emoji) do
with {:ok, data, meta} <- object_action(actor, object) do
data =
- data
- |> Map.put("content", emoji)
- |> Map.put("type", "EmojiReact")
+ if Emoji.is_unicode_emoji?(emoji) do
+ unicode_emoji_react(object, data, emoji)
+ else
+ custom_emoji_react(object, data, emoji)
+ end
{:ok, data, meta}
end
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 5bcd6da46..5e0d1aa8e 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator
- alias Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
@@ -102,7 +102,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
%{"type" => "Create", "object" => %{"type" => objtype} = object} = create_activity,
meta
)
- when objtype in ~w[Question Answer Audio Video Event Article Note Page] do
+ when objtype in ~w[Question Answer Audio Video Image Event Article Note Page] do
with {:ok, object_data} <- cast_and_apply_and_stringify_with_history(object),
meta = Keyword.put(meta, :object_data, object_data),
{:ok, create_activity} <-
@@ -115,13 +115,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
end
def validate(%{"type" => type} = object, meta)
- when type in ~w[Event Question Audio Video Article Note Page] do
+ when type in ~w[Event Question Audio Video Image Article Note Page] do
validator =
case type do
"Event" -> EventValidator
"Question" -> QuestionValidator
- "Audio" -> AudioVideoValidator
- "Video" -> AudioVideoValidator
+ "Audio" -> AudioImageVideoValidator
+ "Video" -> AudioImageVideoValidator
+ "Image" -> AudioImageVideoValidator
"Article" -> ArticleNotePageValidator
"Note" -> ArticleNotePageValidator
"Page" -> ArticleNotePageValidator
@@ -233,8 +234,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
AnswerValidator.cast_and_apply(object)
end
- def cast_and_apply(%{"type" => type} = object) when type in ~w[Audio Video] do
- AudioVideoValidator.cast_and_apply(object)
+ def cast_and_apply(%{"type" => type} = object) when type in ~w[Audio Image Video] do
+ AudioImageVideoValidator.cast_and_apply(object)
end
def cast_and_apply(%{"type" => "Event"} = object) do
diff --git a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
index 671a7ef0c..79ff76104 100644
--- a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
@@ -2,7 +2,7 @@
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator do
use Ecto.Schema
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
@@ -55,9 +55,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
url
|> Enum.concat(mpeg_url["tag"] || [])
|> Enum.find(fn
- %{"mediaType" => mime_type} -> String.starts_with?(mime_type, ["video/", "audio/"])
- %{"mimeType" => mime_type} -> String.starts_with?(mime_type, ["video/", "audio/"])
- _ -> false
+ %{"mediaType" => mime_type} ->
+ String.starts_with?(mime_type, ["video/", "audio/", "image/"])
+
+ %{"mimeType" => mime_type} ->
+ String.starts_with?(mime_type, ["video/", "audio/", "image/"])
+
+ _ ->
+ false
end)
end
@@ -110,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
defp validate_data(data_cng) do
data_cng
- |> validate_inclusion(:type, ["Audio", "Video"])
+ |> validate_inclusion(:type, ~w[Audio Image Video])
|> validate_required([:id, :actor, :attributedTo, :type, :context])
|> CommonValidations.validate_any_presence([:cc, :to])
|> CommonValidations.validate_fields_match([:actor, :attributedTo])
diff --git a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex
index 0858281e5..a0b82b325 100644
--- a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex
@@ -5,8 +5,10 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
use Ecto.Schema
+ alias Pleroma.Emoji
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
+ alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator
import Ecto.Changeset
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
@@ -19,6 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
message_fields()
activity_fields()
+ embeds_many(:tag, TagValidator)
end
end
@@ -43,7 +46,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
def changeset(struct, data) do
struct
- |> cast(data, __schema__(:fields))
+ |> cast(data, __schema__(:fields) -- [:tag])
+ |> cast_embed(:tag)
end
defp fix(data) do
@@ -53,12 +57,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|> CommonFixes.fix_actor()
|> CommonFixes.fix_activity_addressing()
- with %Object{} = object <- Object.normalize(data["object"]) do
- data
- |> CommonFixes.fix_activity_context(object)
- |> CommonFixes.fix_object_action_recipients(object)
- else
- _ -> data
+ data = Map.put_new(data, "tag", [])
+
+ case Object.normalize(data["object"]) do
+ %Object{} = object ->
+ data
+ |> CommonFixes.fix_activity_context(object)
+ |> CommonFixes.fix_object_action_recipients(object)
+
+ _ ->
+ data
end
end
@@ -82,11 +90,31 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
defp validate_emoji(cng) do
content = get_field(cng, :content)
- if Pleroma.Emoji.is_unicode_emoji?(content) do
+ if Emoji.is_unicode_emoji?(content) || Emoji.is_custom_emoji?(content) do
cng
else
cng
- |> add_error(:content, "must be a single character emoji")
+ |> add_error(:content, "is not a valid emoji")
+ end
+ end
+
+ defp maybe_validate_tag_presence(cng) do
+ content = get_field(cng, :content)
+
+ if Emoji.is_unicode_emoji?(content) do
+ cng
+ else
+ tag = get_field(cng, :tag)
+ emoji_name = Emoji.maybe_strip_name(content)
+
+ case tag do
+ [%{name: ^emoji_name, type: "Emoji", icon: %{url: _}}] ->
+ cng
+
+ _ ->
+ cng
+ |> add_error(:tag, "does not contain an Emoji tag")
+ end
end
end
@@ -97,5 +125,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|> validate_actor_presence()
|> validate_object_presence()
|> validate_emoji()
+ |> maybe_validate_tag_presence()
end
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex b/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
index 9f15f1981..cfd510c19 100644
--- a/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
@@ -68,6 +68,12 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do
|> validate_required([:type, :name, :icon])
end
+ def changeset(struct, %{"type" => _} = data) do
+ struct
+ |> cast(data, [])
+ |> Map.put(:action, :ignore)
+ end
+
def icon_changeset(struct, data) do
struct
|> cast(data, [:type, :url])
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
index fc5dec362..098c177c7 100644
--- a/lib/pleroma/web/activity_pub/side_effects.ex
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -496,7 +496,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end
def handle_object_creation(%{"type" => objtype} = object, _activity, meta)
- when objtype in ~w[Audio Video Event Article Note Page] do
+ when objtype in ~w[Audio Video Image Event Article Note Page] do
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
{:ok, object, meta}
end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index e4c04da0d..3141f8437 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -447,7 +447,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => "Create", "object" => %{"type" => objtype, "id" => obj_id}} = data,
options
)
- when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note Page} do
+ when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note Page Image} do
fetch_options = Keyword.put(options, :depth, (options[:depth] || 0) + 1)
object =
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index b898d6fe8..437220077 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -31,7 +31,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"Page",
"Question",
"Answer",
- "Audio"
+ "Audio",
+ "Image"
]
@strip_status_report_states ~w(closed resolved)
@supported_report_states ~w(open closed resolved)
@@ -325,21 +326,29 @@ defmodule Pleroma.Web.ActivityPub.Utils do
{:ok, Object.t()} | {:error, Ecto.Changeset.t()}
def add_emoji_reaction_to_object(
- %Activity{data: %{"content" => emoji, "actor" => actor}},
+ %Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
object
) do
reactions = get_cached_emoji_reactions(object)
+ emoji = Pleroma.Emoji.maybe_strip_name(emoji)
+ url = maybe_emoji_url(emoji, activity)
new_reactions =
- case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
+ case Enum.find_index(reactions, fn [candidate, _, candidate_url] ->
+ if is_nil(candidate_url) do
+ emoji == candidate
+ else
+ url == candidate_url
+ end
+ end) do
nil ->
- reactions ++ [[emoji, [actor]]]
+ reactions ++ [[emoji, [actor], url]]
index ->
List.update_at(
reactions,
index,
- fn [emoji, users] -> [emoji, Enum.uniq([actor | users])] end
+ fn [emoji, users, url] -> [emoji, Enum.uniq([actor | users]), url] end
)
end
@@ -348,18 +357,40 @@ defmodule Pleroma.Web.ActivityPub.Utils do
update_element_in_object("reaction", new_reactions, object, count)
end
+ defp maybe_emoji_url(
+ name,
+ %Activity{
+ data: %{
+ "tag" => [
+ %{"type" => "Emoji", "name" => name, "icon" => %{"url" => url}}
+ ]
+ }
+ }
+ ),
+ do: url
+
+ defp maybe_emoji_url(_, _), do: nil
+
def emoji_count(reactions_list) do
- Enum.reduce(reactions_list, 0, fn [_, users], acc -> acc + length(users) end)
+ Enum.reduce(reactions_list, 0, fn [_, users, _], acc -> acc + length(users) end)
end
def remove_emoji_reaction_from_object(
- %Activity{data: %{"content" => emoji, "actor" => actor}},
+ %Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
object
) do
+ emoji = Pleroma.Emoji.maybe_strip_name(emoji)
reactions = get_cached_emoji_reactions(object)
+ url = maybe_emoji_url(emoji, activity)
new_reactions =
- case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
+ case Enum.find_index(reactions, fn [candidate, _, candidate_url] ->
+ if is_nil(candidate_url) do
+ emoji == candidate
+ else
+ url == candidate_url
+ end
+ end) do
nil ->
reactions
@@ -367,9 +398,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do
List.update_at(
reactions,
index,
- fn [emoji, users] -> [emoji, List.delete(users, actor)] end
+ fn [emoji, users, url] -> [emoji, List.delete(users, actor), url] end
)
- |> Enum.reject(fn [_, users] -> Enum.empty?(users) end)
+ |> Enum.reject(fn [_, users, _] -> Enum.empty?(users) end)
end
count = emoji_count(new_reactions)
@@ -377,11 +408,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
end
def get_cached_emoji_reactions(object) do
- if is_list(object.data["reactions"]) do
- object.data["reactions"]
- else
- []
- end
+ Object.get_emoji_reactions(object)
end
@spec add_like_to_object(Activity.t(), Object.t()) ::
@@ -489,17 +516,37 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def get_latest_reaction(internal_activity_id, %{ap_id: ap_id}, emoji) do
%{data: %{"object" => object_ap_id}} = Activity.get_by_id(internal_activity_id)
+ emoji = Pleroma.Emoji.maybe_quote(emoji)
"EmojiReact"
|> Activity.Queries.by_type()
|> where(actor: ^ap_id)
- |> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
+ |> custom_emoji_discriminator(emoji)
|> Activity.Queries.by_object_id(object_ap_id)
|> order_by([activity], fragment("? desc nulls last", activity.id))
|> limit(1)
|> Repo.one()
end
+ defp custom_emoji_discriminator(query, emoji) do
+ if String.contains?(emoji, "@") do
+ stripped = Pleroma.Emoji.maybe_strip_name(emoji)
+ [name, domain] = String.split(stripped, "@")
+ domain_pattern = "%/" <> domain <> "/%"
+ emoji_pattern = Pleroma.Emoji.maybe_quote(name)
+
+ query
+ |> where([activity], fragment("?->>'content' = ?
+ AND EXISTS (
+ SELECT FROM jsonb_array_elements(?->'tag') elem
+ WHERE elem->>'id' ILIKE ?
+ )", activity.data, ^emoji_pattern, activity.data, ^domain_pattern))
+ else
+ query
+ |> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
+ end
+ end
+
#### Announce-related helpers
@doc """
diff --git a/lib/pleroma/web/admin_api/controllers/frontend_controller.ex b/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
index b4dbb82fe..9e2ed4aac 100644
--- a/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
@@ -18,13 +18,24 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do
def index(conn, _params) do
installed = installed()
+ # FIrst get frontends from config,
+ # then add frontends that are installed but not in the config
frontends =
- [:frontends, :available]
- |> Config.get([])
+ Config.get([:frontends, :available], [])
|> Enum.map(fn {name, desc} ->
- Map.put(desc, "installed", name in installed)
+ desc
+ |> Map.put("installed", name in installed)
+ |> Map.put("installed_refs", installed_refs(name))
end)
+ frontends =
+ frontends ++
+ (installed
+ |> Enum.filter(fn n -> not Enum.any?(frontends, fn f -> f["name"] == n end) end)
+ |> Enum.map(fn name ->
+ %{"name" => name, "installed" => true, "installed_refs" => installed_refs(name)}
+ end))
+
render(conn, "index.json", frontends: frontends)
end
@@ -43,4 +54,12 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do
[]
end
end
+
+ def installed_refs(name) do
+ if name in installed() do
+ File.ls!(Path.join(Pleroma.Frontend.dir(), name))
+ else
+ []
+ end
+ end
end
diff --git a/lib/pleroma/web/admin_api/views/frontend_view.ex b/lib/pleroma/web/admin_api/views/frontend_view.ex
index 0ca3d67cb..ae4016581 100644
--- a/lib/pleroma/web/admin_api/views/frontend_view.ex
+++ b/lib/pleroma/web/admin_api/views/frontend_view.ex
@@ -15,7 +15,8 @@ defmodule Pleroma.Web.AdminAPI.FrontendView do
git: frontend["git"],
build_url: frontend["build_url"],
ref: frontend["ref"],
- installed: frontend["installed"]
+ installed: frontend["installed"],
+ installed_refs: frontend["installed_refs"]
}
end
end
diff --git a/lib/pleroma/web/api_spec.ex b/lib/pleroma/web/api_spec.ex
index cae4241ff..2d56dc643 100644
--- a/lib/pleroma/web/api_spec.ex
+++ b/lib/pleroma/web/api_spec.ex
@@ -95,7 +95,8 @@ defmodule Pleroma.Web.ApiSpec do
"Relays",
"Report managment",
"Status administration",
- "User administration"
+ "User administration",
+ "Announcement management"
]
},
%{"name" => "Applications", "tags" => ["Applications", "Push subscriptions"]},
@@ -110,10 +111,12 @@ defmodule Pleroma.Web.ApiSpec do
"Follow requests",
"Mascot",
"Markers",
- "Notifications"
+ "Notifications",
+ "Filters",
+ "Settings"
]
},
- %{"name" => "Instance", "tags" => ["Custom emojis"]},
+ %{"name" => "Instance", "tags" => ["Custom emojis", "Instance misc"]},
%{"name" => "Messaging", "tags" => ["Chats", "Conversations"]},
%{
"name" => "Statuses",
@@ -125,10 +128,21 @@ defmodule Pleroma.Web.ApiSpec do
"Retrieve status information",
"Scheduled statuses",
"Search",
- "Status actions"
+ "Status actions",
+ "Media attachments"
]
},
- %{"name" => "Miscellaneous", "tags" => ["Emoji packs", "Reports", "Suggestions"]}
+ %{
+ "name" => "Miscellaneous",
+ "tags" => [
+ "Emoji packs",
+ "Reports",
+ "Suggestions",
+ "Announcements",
+ "Remote interaction",
+ "Others"
+ ]
+ }
]
}
}
diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex
index aabe988f7..f2897a3a3 100644
--- a/lib/pleroma/web/api_spec/operations/account_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/account_operation.ex
@@ -452,7 +452,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
operationId: "AccountController.blocks",
description: "View your blocks. See also accounts/:id/{block,unblock}",
security: [%{"oAuth" => ["read:blocks"]}],
- parameters: pagination_params(),
+ parameters: [with_relationships_param() | pagination_params()],
responses: %{
200 => Operation.response("Accounts", "application/json", array_of_accounts())
}
@@ -461,7 +461,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
def lookup_operation do
%Operation{
- tags: ["Account lookup"],
+ tags: ["Retrieve account information"],
summary: "Find a user by nickname",
operationId: "AccountController.lookup",
parameters: [
diff --git a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
index 58a039e72..49850e5d2 100644
--- a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def index_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Retrieve a list of announcements",
operationId: "AdminAPI.AnnouncementController.index",
security: [%{"oAuth" => ["admin:read"]}],
@@ -46,7 +46,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def show_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Display one announcement",
operationId: "AdminAPI.AnnouncementController.show",
security: [%{"oAuth" => ["admin:read"]}],
@@ -69,7 +69,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def delete_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Delete one announcement",
operationId: "AdminAPI.AnnouncementController.delete",
security: [%{"oAuth" => ["admin:write"]}],
@@ -92,7 +92,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def create_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Create one announcement",
operationId: "AdminAPI.AnnouncementController.create",
security: [%{"oAuth" => ["admin:write"]}],
@@ -107,7 +107,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def change_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Change one announcement",
operationId: "AdminAPI.AnnouncementController.change",
security: [%{"oAuth" => ["admin:write"]}],
diff --git a/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex b/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
index 4bfe5ac5a..3e85c44d2 100644
--- a/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
@@ -51,8 +51,9 @@ defmodule Pleroma.Web.ApiSpec.Admin.FrontendOperation do
name: %Schema{type: :string},
git: %Schema{type: :string, format: :uri, nullable: true},
build_url: %Schema{type: :string, format: :uri, nullable: true},
- ref: %Schema{type: :string},
- installed: %Schema{type: :boolean}
+ ref: %Schema{type: :string, nullable: true},
+ installed: %Schema{type: :boolean},
+ installed_refs: %Schema{type: :array, items: %Schema{type: :string}}
}
}
}
diff --git a/lib/pleroma/web/api_spec/operations/admin/status_operation.ex b/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
index 229912dd7..17383f1d0 100644
--- a/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
@@ -70,7 +70,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def show_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Get status",
operationId: "AdminAPI.StatusController.show",
parameters: [id_param() | admin_api_params()],
@@ -84,7 +84,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def update_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Change the scope of a status",
operationId: "AdminAPI.StatusController.update",
parameters: [id_param() | admin_api_params()],
@@ -99,7 +99,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def delete_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Delete status",
operationId: "AdminAPI.StatusController.delete",
parameters: [id_param() | admin_api_params()],
@@ -143,7 +143,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
}
},
tags: %Schema{type: :string},
- is_confirmed: %Schema{type: :string}
+ is_confirmed: %Schema{type: :boolean}
}
}
end
diff --git a/lib/pleroma/web/api_spec/operations/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/announcement_operation.ex
index 71be0002a..6f7031962 100644
--- a/lib/pleroma/web/api_spec/operations/announcement_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/announcement_operation.ex
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do
def index_operation do
%Operation{
- tags: ["Announcement"],
+ tags: ["Announcements"],
summary: "Retrieve a list of announcements",
operationId: "MastodonAPI.AnnouncementController.index",
security: [%{"oAuth" => []}],
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do
def mark_read_operation do
%Operation{
- tags: ["Announcement"],
+ tags: ["Announcements"],
summary: "Mark one announcement as read",
operationId: "MastodonAPI.AnnouncementController.mark_read",
security: [%{"oAuth" => ["write:accounts"]}],
diff --git a/lib/pleroma/web/api_spec/operations/directory_operation.ex b/lib/pleroma/web/api_spec/operations/directory_operation.ex
index 55752fa62..23fa84dff 100644
--- a/lib/pleroma/web/api_spec/operations/directory_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/directory_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.DirectoryOperation do
def index_operation do
%Operation{
- tags: ["Directory"],
+ tags: ["Others"],
summary: "Profile directory",
operationId: "DirectoryController.index",
parameters:
diff --git a/lib/pleroma/web/api_spec/operations/instance_operation.ex b/lib/pleroma/web/api_spec/operations/instance_operation.ex
index 3c4b504fe..a07be7e40 100644
--- a/lib/pleroma/web/api_spec/operations/instance_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/instance_operation.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
def show_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve instance information",
description: "Information about the server",
operationId: "InstanceController.show",
@@ -25,7 +25,7 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
def peers_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve list of known instances",
operationId: "InstanceController.peers",
responses: %{
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
index d09c1c10e..b05bad197 100644
--- a/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
@@ -133,7 +133,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiFileOperation do
defp files_object do
%Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Filename of the emoji",
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
+ },
description: "Object with emoji names as keys and filenames as values"
}
end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
index 6add3ff33..efa36ffdc 100644
--- a/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
@@ -227,13 +227,29 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
defp emoji_packs_response do
Operation.response(
- "Object with pack names as keys and pack contents as values",
+ "Emoji packs and the count",
"application/json",
%Schema{
type: :object,
- additionalProperties: emoji_pack(),
+ properties: %{
+ packs: %Schema{
+ type: :object,
+ description: "Object with pack names as keys and pack contents as values",
+ additionalProperties: %Schema{
+ emoji_pack()
+ | extensions: %{"x-additionalPropertiesName": "Pack name"}
+ }
+ },
+ count: %Schema{
+ type: :integer,
+ description: "Number of emoji packs"
+ }
+ },
example: %{
- "emojos" => emoji_pack().example
+ "packs" => %{
+ "emojos" => emoji_pack().example
+ },
+ "count" => 1
}
}
)
@@ -274,7 +290,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
defp files_object do
%Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Filename",
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
+ },
description: "Object with emoji names as keys and filenames as values"
}
end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
index 82db4e1a8..e9319f3fb 100644
--- a/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaInstancesOperation do
def show_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve federation status",
description: "Information about instances deemed unreachable by the server",
operationId: "PleromaInstances.show",
diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex
index e921128c7..5d6e82f3c 100644
--- a/lib/pleroma/web/api_spec/operations/status_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/status_operation.ex
@@ -440,7 +440,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def show_history_operation do
%Operation{
- tags: ["Retrieve status history"],
+ tags: ["Retrieve status information"],
summary: "Status history",
description: "View history of a status",
operationId: "StatusController.show_history",
@@ -457,7 +457,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def show_source_operation do
%Operation{
- tags: ["Retrieve status source"],
+ tags: ["Retrieve status information"],
summary: "Status source",
description: "View source of a status",
operationId: "StatusController.show_source",
@@ -474,7 +474,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def update_operation do
%Operation{
- tags: ["Update status"],
+ tags: ["Status actions"],
summary: "Update status",
description: "Change the content of a status",
operationId: "StatusController.update",
diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
index 29df03e34..084329ad7 100644
--- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def emoji_operation do
%Operation{
- tags: ["Emojis"],
+ tags: ["Custom emojis"],
summary: "List all custom emojis",
operationId: "UtilController.emoji",
parameters: [],
@@ -30,7 +30,8 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
properties: %{
image_url: %Schema{type: :string},
tags: %Schema{type: :array, items: %Schema{type: :string}}
- }
+ },
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
},
example: %{
"firefox" => %{
@@ -45,7 +46,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def frontend_configurations_operation do
%Operation{
- tags: ["Configuration"],
+ tags: ["Others"],
summary: "Dump frontend configurations",
operationId: "UtilController.frontend_configurations",
parameters: [],
@@ -53,7 +54,12 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
200 =>
Operation.response("List", "application/json", %Schema{
type: :object,
- additionalProperties: %Schema{type: :object}
+ additionalProperties: %Schema{
+ type: :object,
+ description:
+ "Opaque object representing the instance-wide configuration for the frontend",
+ extensions: %{"x-additionalPropertiesName": "Frontend name"}
+ }
})
}
}
@@ -132,7 +138,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def update_notificaton_settings_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Settings"],
summary: "Update Notification Settings",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.update_notificaton_settings",
@@ -207,6 +213,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
%Operation{
summary: "Get a captcha",
operationId: "UtilController.captcha",
+ tags: ["Others"],
parameters: [],
responses: %{
200 => Operation.response("Success", "application/json", %Schema{type: :object})
@@ -356,7 +363,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def healthcheck_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Others"],
summary: "Quick status check on the instance",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.healthcheck",
@@ -371,7 +378,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def remote_subscribe_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Remote Subscribe",
operationId: "UtilController.remote_subscribe",
parameters: [],
@@ -381,7 +388,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def remote_interaction_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Remote interaction",
operationId: "UtilController.remote_interaction",
requestBody: request_body("Parameters", remote_interaction_request(), required: true),
@@ -407,7 +414,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def show_subscribe_form_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Show remote subscribe form",
operationId: "UtilController.show_subscribe_form",
parameters: [],
diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex
index 698f11794..bc29cf4a6 100644
--- a/lib/pleroma/web/api_spec/schemas/status.ex
+++ b/lib/pleroma/web/api_spec/schemas/status.ex
@@ -144,7 +144,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
properties: %{
content: %Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Alternate representation in the MIME type specified",
+ extensions: %{"x-additionalPropertiesName": "MIME type"}
+ },
description:
"A map consisting of alternate representations of the `content` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`"
},
@@ -195,7 +199,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
},
spoiler_text: %Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Alternate representation in the MIME type specified",
+ extensions: %{"x-additionalPropertiesName": "MIME type"}
+ },
description:
"A map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`."
},
diff --git a/lib/pleroma/web/api_spec/scopes/compiler.ex b/lib/pleroma/web/api_spec/scopes/compiler.ex
new file mode 100644
index 000000000..162edc9a3
--- /dev/null
+++ b/lib/pleroma/web/api_spec/scopes/compiler.ex
@@ -0,0 +1,82 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Scopes.Compiler do
+ defmacro __before_compile__(_env) do
+ strings = __MODULE__.extract_all_scopes()
+
+ quote do
+ def placeholder do
+ unquote do
+ Enum.map(
+ strings,
+ fn string ->
+ quote do
+ Pleroma.Web.Gettext.dgettext_noop(
+ "oauth_scopes",
+ unquote(string)
+ )
+ end
+ end
+ )
+ end
+ end
+ end
+ end
+
+ def extract_all_scopes do
+ extract_all_scopes_from(Pleroma.Web.ApiSpec.spec())
+ end
+
+ def extract_all_scopes_from(specs) do
+ specs.paths
+ |> Enum.reduce([], fn
+ {_path, %{} = path_item}, acc ->
+ extract_routes(path_item)
+ |> Enum.flat_map(fn operation -> process_operation(operation) end)
+ |> Kernel.++(acc)
+
+ {_, _}, acc ->
+ acc
+ end)
+ |> Enum.uniq()
+ end
+
+ defp extract_routes(path_item) do
+ path_item
+ |> Map.from_struct()
+ |> Enum.map(fn {_method, path_item} -> path_item end)
+ |> Enum.filter(fn
+ %OpenApiSpex.Operation{} = _operation -> true
+ _ -> false
+ end)
+ end
+
+ defp process_operation(operation) do
+ operation.security
+ |> Kernel.||([])
+ |> Enum.flat_map(fn
+ %{"oAuth" => scopes} -> process_scopes(scopes)
+ _ -> []
+ end)
+ end
+
+ defp process_scopes(scopes) do
+ scopes
+ |> Enum.flat_map(fn scope ->
+ process_scope(scope)
+ end)
+ end
+
+ def process_scope(scope) do
+ hierarchy = String.split(scope, ":")
+
+ {_, list} =
+ Enum.reduce(hierarchy, {"", []}, fn comp, {cur, list} ->
+ {cur <> comp <> ":", [cur <> comp | list]}
+ end)
+
+ list
+ end
+end
diff --git a/lib/pleroma/web/api_spec/scopes/translator.ex b/lib/pleroma/web/api_spec/scopes/translator.ex
new file mode 100644
index 000000000..54eea3593
--- /dev/null
+++ b/lib/pleroma/web/api_spec/scopes/translator.ex
@@ -0,0 +1,10 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Scopes.Translator do
+ require Pleroma.Web.ApiSpec.Scopes.Compiler
+ require Pleroma.Web.Gettext
+
+ @before_compile Pleroma.Web.ApiSpec.Scopes.Compiler
+end
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index ff0814329..a93c97e1e 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -145,6 +145,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
when is_list(options) do
limits = Config.get([:instance, :poll_limits])
+ options = options |> Enum.uniq()
+
with :ok <- validate_poll_expiration(expires_in, limits),
:ok <- validate_poll_options_amount(options, limits),
:ok <- validate_poll_options_length(options, limits) do
@@ -180,10 +182,15 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
defp validate_poll_options_amount(options, %{max_options: max_options}) do
- if Enum.count(options) > max_options do
- {:error, "Poll can't contain more than #{max_options} options"}
- else
- :ok
+ cond do
+ Enum.count(options) < 2 ->
+ {:error, "Poll must contain at least 2 options"}
+
+ Enum.count(options) > max_options ->
+ {:error, "Poll can't contain more than #{max_options} options"}
+
+ true ->
+ :ok
end
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index ea6e593d9..c313a0e97 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -269,14 +269,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
defp normalize_fields_attributes(fields) do
- if Enum.all?(fields, &is_tuple/1) do
- Enum.map(fields, fn {_, v} -> v end)
- else
- Enum.map(fields, fn
- %{} = field -> %{"name" => field.name, "value" => field.value}
- field -> field
- end)
- end
+ if(Enum.all?(fields, &is_tuple/1), do: Enum.map(fields, fn {_, v} -> v end), else: fields)
+ |> Enum.map(fn
+ %{} = field -> %{"name" => field.name, "value" => field.value}
+ field -> field
+ end)
end
@doc "GET /api/v1/accounts/relationships"
@@ -543,7 +540,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
conn
|> add_link_headers(users)
- |> render("index.json", users: users, for: user, as: :user)
+ |> render("index.json",
+ users: users,
+ for: user,
+ as: :user,
+ embed_relationships: embed_relationships?(params)
+ )
end
@doc "GET /api/v1/accounts/lookup"
diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex
index abf7f29ab..efd2a0af6 100644
--- a/lib/pleroma/web/mastodon_api/views/instance_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex
@@ -92,6 +92,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
"safe_dm_mentions"
end,
"pleroma_emoji_reactions",
+ "pleroma_custom_emoji_reactions",
"pleroma_chat_messages",
if Config.get([:instance, :show_reactions]) do
"exposable_reactions"
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
index b5b5b2376..2a51f3755 100644
--- a/lib/pleroma/web/mastodon_api/views/notification_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -17,6 +17,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.StatusView
+ alias Pleroma.Web.MediaProxy
alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView
defp object_id_for(%{data: %{"object" => %{"id" => id}}}) when is_binary(id), do: id
@@ -145,7 +146,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
end
defp put_emoji(response, activity) do
- Map.put(response, :emoji, activity.data["content"])
+ response
+ |> Map.put(:emoji, activity.data["content"])
+ |> Map.put(:emoji_url, MediaProxy.url(Pleroma.Emoji.emoji_url(activity.data)))
end
defp put_chat_message(response, activity, reading_user, opts) do
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 0a8c98b44..dea22f9c2 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -334,14 +334,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
emoji_reactions =
- object.data
- |> Map.get("reactions", [])
+ object
+ |> Object.get_emoji_reactions()
|> EmojiReactionController.filter_allowed_users(
opts[:for],
Map.get(opts, :with_muted, false)
)
- |> Stream.map(fn {emoji, users} ->
- build_emoji_map(emoji, users, opts[:for])
+ |> Stream.map(fn {emoji, users, url} ->
+ build_emoji_map(emoji, users, url, opts[:for])
end)
|> Enum.to_list()
@@ -702,11 +702,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
end
- defp build_emoji_map(emoji, users, current_user) do
+ defp build_emoji_map(emoji, users, url, current_user) do
%{
- name: emoji,
+ name: Pleroma.Web.PleromaAPI.EmojiReactionView.emoji_name(emoji, url),
count: length(users),
- me: !!(current_user && current_user.ap_id in users)
+ url: MediaProxy.url(url),
+ me: !!(current_user && current_user.ap_id in users),
+ account_ids: Enum.map(users, fn user -> User.get_cached_by_ap_id(user).id end)
}
end
diff --git a/lib/pleroma/web/metadata/providers/rel_me.ex b/lib/pleroma/web/metadata/providers/rel_me.ex
index f0bee85c8..eabd8cb00 100644
--- a/lib/pleroma/web/metadata/providers/rel_me.ex
+++ b/lib/pleroma/web/metadata/providers/rel_me.ex
@@ -8,12 +8,20 @@ defmodule Pleroma.Web.Metadata.Providers.RelMe do
@impl Provider
def build_tags(%{user: user}) do
- bio_tree = Floki.parse_fragment!(user.bio)
+ profile_tree =
+ user.bio
+ |> append_fields_tag(user.fields)
+ |> Floki.parse_fragment!()
- (Floki.attribute(bio_tree, "link[rel~=me]", "href") ++
- Floki.attribute(bio_tree, "a[rel~=me]", "href"))
+ (Floki.attribute(profile_tree, "link[rel~=me]", "href") ++
+ Floki.attribute(profile_tree, "a[rel~=me]", "href"))
|> Enum.map(fn link ->
{:link, [rel: "me", href: link], []}
end)
end
+
+ defp append_fields_tag(bio, fields) do
+ fields
+ |> Enum.reduce(bio, fn %{"value" => v}, res -> res <> v end)
+ end
end
diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
index 78fd0b219..662cc15d6 100644
--- a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
@@ -28,8 +28,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
def index(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do
with true <- Pleroma.Config.get([:instance, :show_reactions]),
%Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
- %Object{data: %{"reactions" => reactions}} when is_list(reactions) <-
- Object.normalize(activity, fetch: false) do
+ %Object{} = object <- Object.normalize(activity, fetch: false),
+ reactions <- Object.get_emoji_reactions(object) do
reactions =
reactions
|> filter(params)
@@ -50,29 +50,32 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
if not with_muted, do: User.cached_muted_users_ap_ids(user), else: []
end
- filter_emoji = fn emoji, users ->
+ filter_emoji = fn emoji, users, url ->
case Enum.reject(users, &(&1 in exclude_ap_ids)) do
[] -> nil
- users -> {emoji, users}
+ users -> {emoji, users, url}
end
end
reactions
|> Stream.map(fn
- [emoji, users] when is_list(users) -> filter_emoji.(emoji, users)
- {emoji, users} when is_list(users) -> filter_emoji.(emoji, users)
- _ -> nil
+ [emoji, users, url] when is_list(users) -> filter_emoji.(emoji, users, url)
end)
|> Stream.reject(&is_nil/1)
end
defp filter(reactions, %{emoji: emoji}) when is_binary(emoji) do
- Enum.filter(reactions, fn [e, _] -> e == emoji end)
+ Enum.filter(reactions, fn [e, _, _] -> e == emoji end)
end
defp filter(reactions, _), do: reactions
def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
+ emoji =
+ emoji
+ |> Pleroma.Emoji.fully_qualify_emoji()
+ |> Pleroma.Emoji.maybe_quote()
+
with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji) do
activity = Activity.get_by_id(activity_id)
@@ -83,6 +86,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
end
def delete(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
+ emoji =
+ emoji
+ |> Pleroma.Emoji.fully_qualify_emoji()
+ |> Pleroma.Emoji.maybe_quote()
+
with {:ok, _activity} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji) do
activity = Activity.get_by_id(activity_id)
diff --git a/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex b/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
index 68ebd8292..6df4ab9d0 100644
--- a/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
+++ b/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
@@ -7,17 +7,30 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionView do
alias Pleroma.Web.MastodonAPI.AccountView
+ def emoji_name(emoji, nil), do: emoji
+
+ def emoji_name(emoji, url) do
+ url = URI.parse(url)
+
+ if url.host == Pleroma.Web.Endpoint.host() do
+ emoji
+ else
+ "#{emoji}@#{url.host}"
+ end
+ end
+
def render("index.json", %{emoji_reactions: emoji_reactions} = opts) do
render_many(emoji_reactions, __MODULE__, "show.json", opts)
end
- def render("show.json", %{emoji_reaction: {emoji, user_ap_ids}, user: user}) do
+ def render("show.json", %{emoji_reaction: {emoji, user_ap_ids, url}, user: user}) do
users = fetch_users(user_ap_ids)
%{
- name: emoji,
+ name: emoji_name(emoji, url),
count: length(users),
accounts: render(AccountView, "index.json", users: users, for: user),
+ url: Pleroma.Web.MediaProxy.url(url),
me: !!(user && user.ap_id in user_ap_ids)
}
end
diff --git a/lib/pleroma/web/plugs/uploaded_media.ex b/lib/pleroma/web/plugs/uploaded_media.ex
index ad8143234..8b3bc9acb 100644
--- a/lib/pleroma/web/plugs/uploaded_media.ex
+++ b/lib/pleroma/web/plugs/uploaded_media.ex
@@ -35,9 +35,9 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
conn =
case fetch_query_params(conn) do
%{query_params: %{"name" => name}} = conn ->
- name = String.replace(name, "\"", "\\\"")
+ name = String.replace(name, ~s["], ~s[\\"])
- put_resp_header(conn, "content-disposition", "filename=\"#{name}\"")
+ put_resp_header(conn, "content-disposition", ~s[inline; filename="#{name}"])
conn ->
conn
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
index 73115e92a..7585c4d3e 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
@@ -8,7 +8,7 @@
<%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %>
<%= label @form, :"scope_#{scope}", String.capitalize(scope) %>
<%= if scope in @scopes && scope do %>
- <%= String.capitalize(scope) %>
+ <code><%= scope %></code> <%= :"Elixir.Gettext".dgettext(Gettext, "oauth_scopes", scope) %>
<% end %>
</div>
<% else %>
diff --git a/mix.exs b/mix.exs
index 79fd9c9ef..bb16f0a9c 100644
--- a/mix.exs
+++ b/mix.exs
@@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
def project do
[
app: :pleroma,
- version: version("2.5.2"),
+ version: version("2.5.52"),
elixir: "~> 1.11",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
@@ -78,8 +78,7 @@ defmodule Pleroma.Mixfile do
:comeonin,
:fast_sanitize,
:os_mon,
- :ssl,
- :esshd
+ :ssl
],
included_applications: [:ex_syslogger]
]
@@ -126,7 +125,8 @@ defmodule Pleroma.Mixfile do
{:telemetry_poller, "~> 1.0"},
{:tzdata, "~> 1.0.3"},
{:plug_cowboy, "~> 2.3"},
- {:oban, "~> 2.13"},
+ # oban 2.14 requires Elixir 1.12+
+ {:oban, "~> 2.13.4"},
{:gettext,
git: "https://github.com/tusooa/gettext.git",
ref: "72fb2496b6c5280ed911bdc3756890e7f38a4808",
@@ -148,7 +148,8 @@ defmodule Pleroma.Mixfile do
{:ex_aws, "~> 2.1.6"},
{:ex_aws_s3, "~> 2.0"},
{:sweet_xml, "~> 0.7.2"},
- {:earmark, "~> 1.4.22"},
+ # earmark 1.4.23 requires Elixir 1.12+
+ {:earmark, "1.4.22"},
{:bbcode_pleroma, "~> 0.2.0"},
{:cors_plug, "~> 2.0"},
{:web_push_encryption, "~> 0.3.1"},
@@ -179,7 +180,6 @@ defmodule Pleroma.Mixfile do
{:joken, "~> 2.0"},
{:benchee, "~> 1.0"},
{:pot, "~> 1.0"},
- {:esshd, "~> 0.1.0", runtime: Application.get_env(:esshd, :enabled, false)},
{:ex_const, "~> 0.2"},
{:plug_static_index_html, "~> 1.0.0"},
{:flake_id, "~> 0.1.0"},
@@ -193,7 +193,7 @@ defmodule Pleroma.Mixfile do
{:restarter, path: "./restarter"},
{:majic, "~> 1.0"},
{:eblurhash, "~> 1.2.2"},
- {:open_api_spex, "~> 3.10"},
+ {:open_api_spex, "~> 3.16"},
{:ecto_psql_extras, "~> 0.6"},
# indirect dependency version override
diff --git a/mix.lock b/mix.lock
index 8419dc739..43012a58e 100644
--- a/mix.lock
+++ b/mix.lock
@@ -2,66 +2,65 @@
"accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm", "11b18c220bcc2eab63b5470c038ef10eb6783bcb1fcdb11aa4137defa5ac1bb8"},
"base62": {:hex, :base62, "1.2.2", "85c6627eb609317b70f555294045895ffaaeb1758666ab9ef9ca38865b11e629", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "d41336bda8eaa5be197f1e4592400513ee60518e5b9f4dcf38f4b4dae6f377bb"},
"bbcode_pleroma": {:hex, :bbcode_pleroma, "0.2.0", "d36f5bca6e2f62261c45be30fa9b92725c0655ad45c99025cb1c3e28e25803ef", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "19851074419a5fedb4ef49e1f01b30df504bb5dbb6d6adfc135238063bebd1c3"},
- "bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.0", "6cb662d5c1b0a8858801cf20997bd006e7016aa8c52959c9ef80e0f34fb60b7a", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2c81d61d4f6ed0e5cf7bf27a9109b791ff216a1034b3d541327484f46dd43769"},
- "benchee": {:hex, :benchee, "1.0.1", "66b211f9bfd84bd97e6d1beaddf8fc2312aaabe192f776e8931cb0c16f53a521", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm", "3ad58ae787e9c7c94dd7ceda3b587ec2c64604563e049b2a0e8baafae832addb"},
+ "bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.1", "5114d780459a04f2b4aeef52307de23de961b69e13a5cd98a911e39fda13f420", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "42182d5f46764def15bf9af83739e3bf4ad22661b1c34fc3e88558efced07279"},
+ "benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"},
"bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"},
- "cachex": {:hex, :cachex, "3.3.0", "6f2ebb8f27491fe39121bd207c78badc499214d76c695658b19d6079beeca5c2", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "d90e5ee1dde14cef33f6b187af4335b88748b72b30c038969176cd4e6ccc31a1"},
+ "cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"},
"calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"},
"captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "e0f16822d578866e186a0974d65ad58cddc1e2ab", [ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"]},
- "castore": {:hex, :castore, "0.1.18", "deb5b9ab02400561b6f5708f3e7660fc35ca2d51bfc6a940d2f513f89c2975fc", [:mix], [], "hexpm", "61bbaf6452b782ef80b33cdb45701afbcf0a918a45ebe7e73f1130d661e66a06"},
+ "castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"},
"certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
- "comeonin": {:hex, :comeonin, "5.3.2", "5c2f893d05c56ae3f5e24c1b983c2d5dfb88c6d979c9287a76a7feb1e1d8d646", [:mix], [], "hexpm", "d0993402844c49539aeadb3fe46a3c9bd190f1ecf86b6f9ebd71957534c95f04"},
+ "comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"},
"concurrent_limiter": {:hex, :concurrent_limiter, "0.1.1", "43ae1dc23edda1ab03dd66febc739c4ff710d047bb4d735754909f9a474ae01c", [:mix], [{:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "53968ff238c0fbb4d7ed76ddb1af0be6f3b2f77909f6796e249e737c505a16eb"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cors_plug": {:hex, :cors_plug, "2.0.3", "316f806d10316e6d10f09473f19052d20ba0a0ce2a1d910ddf57d663dac402ae", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ee4ae1418e6ce117fc42c2ba3e6cbdca4e95ecd2fe59a05ec6884ca16d469aea"},
"covertool": {:hex, :covertool, "2.0.4", "54acff6cddd88d28dea663cd2e1fe20dd32fcf5f5d3aff7d59031ce44ce39efa", [:rebar3], [], "hexpm", "5c9568ba4308fda2082172737c80c31d991ea83961eb10791f06106a870d0cdc"},
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
- "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
- "credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"},
+ "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"},
+ "credo": {:hex, :credo, "1.7.0", "6119bee47272e85995598ee04f2ebbed3e947678dee048d10b5feca139435f75", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6839fcf63d1f0d1c0f450abc8564a57c43d644077ab96f2934563e68b8a769d7"},
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
- "db_connection": {:hex, :db_connection, "2.4.2", "f92e79aff2375299a16bcb069a14ee8615c3414863a6fef93156aee8e86c2ff3", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4fe53ca91b99f55ea249693a0229356a08f4d1a7931d8ffa79289b145fe83668"},
+ "db_connection": {:hex, :db_connection, "2.4.3", "3b9aac9f27347ec65b271847e6baeb4443d8474289bd18c1d6f4de655b70c94d", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c127c15b0fa6cfb32eed07465e05da6c815b032508d4ed7c116122871df73c12"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"earmark": {:hex, :earmark, "1.4.22", "ea3e45c6359446dc308be0a64ce82a03260d973de7d0625a762e6d352ff57958", [:mix], [{:earmark_parser, "~> 1.4.23", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "1caf5145665a42fd76d5317286b0c171861fb1c04f86ab103dde76868814fdfb"},
- "earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"},
+ "earmark_parser": {:hex, :earmark_parser, "1.4.31", "a93921cdc6b9b869f519213d5bc79d9e218ba768d7270d46fdcf1c01bacff9e2", [:mix], [], "hexpm", "317d367ee0335ef037a87e46c91a2269fef6306413f731e8ec11fc45a7efd059"},
"eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"},
- "ecto": {:hex, :ecto, "3.9.2", "017db3bc786ff64271108522c01a5d3f6ba0aea5c84912cfb0dd73bf13684108", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "21466d5177e09e55289ac7eade579a642578242c7a3a9f91ad5c6583337a9d15"},
+ "ecto": {:hex, :ecto, "3.9.5", "9f0aa7ae44a1577b651c98791c6988cd1b69b21bc724e3fd67090b97f7604263", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d4f3115d8cbacdc0bfa4b742865459fb1371d0715515842a1fb17fe31920b74c"},
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
- "ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.4", "5d43fd088d39a158c860b17e8d210669587f63ec89ea122a4654861c8c6e2db4", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.15.7", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "311db02f1b772e3d0dc7f56a05044b5e1499d78ed6abf38885e1ca70059449e5"},
- "ecto_sql": {:hex, :ecto_sql, "3.9.0", "2bb21210a2a13317e098a420a8c1cc58b0c3421ab8e3acfa96417dab7817918c", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a8f3f720073b8b1ac4c978be25fa7960ed7fd44997420c304a4a2e200b596453"},
+ "ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.10", "e14d400930f401ca9f541b3349212634e44027d7f919bbb71224d7ac0d0e8acd", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.15.7 or ~> 0.16.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "505e8cd81e4f17c090be0f99e92b1b3f0fd915f98e76965130b8ccfb891e7088"},
+ "ecto_sql": {:hex, :ecto_sql, "3.9.2", "34227501abe92dba10d9c3495ab6770e75e79b836d114c41108a4bf2ce200ad5", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1eb5eeb4358fdbcd42eac11c1fbd87e3affd7904e639d77903c1358b2abd3f70"},
"eimp": {:hex, :eimp, "1.0.14", "fc297f0c7e2700457a95a60c7010a5f1dcb768a083b6d53f49cd94ab95a28f22", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "501133f3112079b92d9e22da8b88bf4f0e13d4d67ae9c15c42c30bd25ceb83b6"},
- "elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"},
+ "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"},
"esbuild": {:hex, :esbuild, "0.5.0", "d5bb08ff049d7880ee3609ed5c4b864bd2f46445ea40b16b4acead724fb4c4a3", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "f183a0b332d963c4cfaf585477695ea59eef9a6f2204fdd0efa00e099694ffe5"},
- "esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
"eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
"ex_aws": {:hex, :ex_aws, "2.1.9", "dc4865ecc20a05190a34a0ac5213e3e5e2b0a75a0c2835e923ae7bfeac5e3c31", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "3e6c776703c9076001fbe1f7c049535f042cb2afa0d2cbd3b47cbc4e92ac0d10"},
- "ex_aws_s3": {:hex, :ex_aws_s3, "2.2.0", "07a09de557070320e264893c0acc8a1d2e7ddf80155736e0aed966486d1988e6", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "15175c613371e29e1f88b78ec8a4327389ca1ec5b34489744b175727496b21bd"},
+ "ex_aws_s3": {:hex, :ex_aws_s3, "2.4.0", "ce8decb6b523381812798396bc0e3aaa62282e1b40520125d1f4eff4abdff0f4", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "85dda6e27754d94582869d39cba3241d9ea60b6aa4167f9c88e309dc687e56bb"},
"ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm", "96fd346610cc992b8f896ed26a98be82ac4efb065a0578f334a32d60a3ba9767"},
- "ex_doc": {:hex, :ex_doc, "0.24.2", "e4c26603830c1a2286dae45f4412a4d1980e1e89dc779fcd0181ed1d5a05c8d9", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "e134e1d9e821b8d9e4244687fb2ace58d479b67b282de5158333b0d57c6fb7da"},
+ "ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"},
"ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
"ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
"fast_html": {:hex, :fast_html, "2.0.5", "c61760340606c1077ff1f196f17834056cb1dd3d5cb92a9f2cabf28bc6221c3c", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "605f4f4829443c14127694ebabb681778712ceecb4470ec32aa31012330e6506"},
- "fast_sanitize": {:hex, :fast_sanitize, "0.2.2", "3cbbaebaea6043865dfb5b4ecb0f1af066ad410a51470e353714b10c42007b81", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "69f204db9250afa94a0d559d9110139850f57de2b081719fbafa1e9a89e94466"},
+ "fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"finch": {:hex, :finch, "0.10.2", "9ad27d68270d879f73f26604bb2e573d40f29bf0e907064a9a337f90a16a0312", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dd8b11b282072cec2ef30852283949c248bd5d2820c88d8acc89402b81db7550"},
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
- "floki": {:hex, :floki, "0.30.1", "75d35526d3a1459920b6e87fdbc2e0b8a3670f965dd0903708d2b267e0904c55", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "e9c03524447d1c4cbfccd672d739b8c18453eee377846b119d4fd71b1a176bb8"},
+ "floki": {:hex, :floki, "0.34.2", "5fad07ef153b3b8ec110b6b155ec3780c4b2c4906297d0b4be1a7162d04a7e02", [:mix], [], "hexpm", "26b9d50f0f01796bc6be611ca815c5e0de034d2128e39cc9702eee6b66a4d1c8"},
"gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"},
"gettext": {:git, "https://github.com/tusooa/gettext.git", "72fb2496b6c5280ed911bdc3756890e7f38a4808", [ref: "72fb2496b6c5280ed911bdc3756890e7f38a4808"]},
- "gun": {:hex, :gun, "2.0.0-rc.2", "7c489a32dedccb77b6e82d1f3c5a7dadfbfa004ec14e322cdb5e579c438632d2", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "6b9d1eae146410d727140dbf8b404b9631302ecc2066d1d12f22097ad7d254fc"},
+ "gun": {:hex, :gun, "2.0.0", "2326bc0fd6d9cf628419708270d6fe8b02b8d002cf992e4165a77d997b1defd0", [:make, :rebar3], [{:cowlib, "2.12.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "6613cb7c62930dc8d58263c44dda72f8556346ba88358fc929dcbc5f76d04569"},
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
"http_signatures": {:hex, :http_signatures, "0.1.1", "ca7ebc1b61542b163644c8c3b1f0e0f41037d35f2395940d3c6c7deceab41fd8", [:mix], [], "hexpm", "cc3b8a007322cc7b624c0c15eec49ee58ac977254ff529a3c482f681465942a3"},
- "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"},
+ "httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
"jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
- "joken": {:hex, :joken, "2.3.0", "62a979c46f2c81dcb8ddc9150453b60d3757d1ac393c72bb20fc50a7b0827dc6", [:mix], [{:jose, "~> 1.10", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "57b263a79c0ec5d536ac02d569c01e6b4de91bd1cb825625fe90eab4feb7bc1e"},
- "jose": {:hex, :jose, "1.11.1", "59da64010c69aad6cde2f5b9248b896b84472e99bd18f246085b7b9fe435dcdb", [:mix, :rebar3], [], "hexpm", "078f6c9fb3cd2f4cfafc972c814261a7d1e8d2b3685c0a76eb87e158efff1ac5"},
+ "joken": {:hex, :joken, "2.6.0", "b9dd9b6d52e3e6fcb6c65e151ad38bf4bc286382b5b6f97079c47ade6b1bcc6a", [:mix], [{:jose, "~> 1.11.5", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "5a95b05a71cd0b54abd35378aeb1d487a23a52c324fa7efdffc512b655b5aaa7"},
+ "jose": {:hex, :jose, "1.11.5", "3bc2d75ffa5e2c941ca93e5696b54978323191988eb8d225c2e663ddfefd515e", [:mix, :rebar3], [], "hexpm", "dcd3b215bafe02ea7c5b23dafd3eb8062a5cd8f2d904fd9caa323d37034ab384"},
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
"linkify": {:hex, :linkify, "0.5.3", "5f8143d8f61f5ff08d3aeeff47ef6509492b4948d8f08007fbf66e4d2246a7f2", [:mix], [], "hexpm", "3ef35a1377d47c25506e07c1c005ea9d38d700699d92ee92825f024434258177"},
"majic": {:hex, :majic, "1.0.0", "37e50648db5f5c2ff0c9fb46454d034d11596c03683807b9fb3850676ffdaab3", [:make, :mix], [{:elixir_make, "~> 0.6.1", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7905858f76650d49695f14ea55cd9aaaee0c6654fa391671d4cf305c275a0a9e"},
@@ -72,51 +71,53 @@
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
- "mint": {:hex, :mint, "1.4.2", "50330223429a6e1260b2ca5415f69b0ab086141bc76dc2fbf34d7c389a6675b2", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "ce75a5bbcc59b4d7d8d70f8b2fc284b1751ffb35c7b6a6302b5192f8ab4ddd80"},
+ "mint": {:hex, :mint, "1.5.1", "8db5239e56738552d85af398798c80648db0e90f343c8469f6c6d8898944fb6f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4a63e1e76a7c3956abd2c72f370a0d0aecddc3976dea5c27eccbecfa5e7d5b1e"},
"mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
"mock": {:hex, :mock, "0.3.7", "75b3bbf1466d7e486ea2052a73c6e062c6256fb429d6797999ab02fa32f29e03", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "4da49a4609e41fd99b7836945c26f373623ea968cfb6282742bcb94440cf7e5c"},
- "mogrify": {:hex, :mogrify, "0.9.1", "a26f107c4987477769f272bd0f7e3ac4b7b75b11ba597fd001b877beffa9c068", [:mix], [], "hexpm", "134edf189337d2125c0948bf0c228fdeef975c594317452d536224069a5b7f05"},
- "mox": {:hex, :mox, "1.0.0", "4b3c7005173f47ff30641ba044eb0fe67287743eec9bd9545e37f3002b0a9f8b", [:mix], [], "hexpm", "201b0a20b7abdaaab083e9cf97884950f8a30a1350a1da403b3145e213c6f4df"},
+ "mogrify": {:hex, :mogrify, "0.9.2", "b360984adea7dd6a55f18028e6327973c58de7f548fdb86c9859848aa904d5b0", [:mix], [], "hexpm", "c18d10fd70ca20e2585301616c89f6e4f7159d92efc9cc8ee579e00c886f699d"},
+ "mox": {:hex, :mox, "1.0.2", "dc2057289ac478b35760ba74165b4b3f402f68803dd5aecd3bfd19c183815d64", [:mix], [], "hexpm", "f9864921b3aaf763c8741b5b8e6f908f44566f1e427b2630e89e9a73b981fef2"},
"nimble_options": {:hex, :nimble_options, "0.4.0", "c89babbab52221a24b8d1ff9e7d838be70f0d871be823165c94dd3418eea728f", [:mix], [], "hexpm", "e6701c1af326a11eea9634a3b1c62b475339ace9456c1a23ec3bc9a847bca02d"},
- "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm", "5c040b8469c1ff1b10093d3186e2e10dbe483cd73d79ec017993fb3985b8a9b3"},
+ "nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"},
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
- "oban": {:hex, :oban, "2.13.4", "b4c4f48f4c89cc01036670eefa28aa9c03d09aadd402655475b936983d597006", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a7d26f82b409e2d7928fbb75a17716e06ad3f783ebe9af260e3dd23abed7f124"},
- "open_api_spex": {:hex, :open_api_spex, "3.10.0", "94e9521ad525b3fcf6dc77da7c45f87fdac24756d4de588cb0816b413e7c1844", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm", "2dbb2bde3d2b821f06936e8dfaf3284331186556291946d84eeba3750ac28765"},
+ "oban": {:hex, :oban, "2.13.6", "a0cb1bce3bd393770512231fb5a3695fa19fd3af10d7575bf73f837aee7abf43", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c1c5eb16f377b3cbbf2ea14be24d20e3d91285af9d1ac86260b7c2af5464887"},
+ "open_api_spex": {:hex, :open_api_spex, "3.16.1", "8137c338129d63060b4b04947c6c57429f86267045c479c703a38a6d3f98dee1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "ef6fd778ac121af866b48b75ad4ad256b6ff33949113ea4aa1629af8bfdfdbfb"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"pbkdf2_elixir": {:hex, :pbkdf2_elixir, "1.2.1", "9cbe354b58121075bd20eb83076900a3832324b7dd171a6895fab57b6bb2752c", [:mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}], "hexpm", "d3b40a4a4630f0b442f19eca891fcfeeee4c40871936fed2f68e1c4faa30481f"},
- "phoenix": {:hex, :phoenix, "1.6.15", "0a1d96bbc10747fd83525370d691953cdb6f3ccbac61aa01b4acb012474b047d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d70ab9fbf6b394755ea88b644d34d79d8b146e490973151f248cacd122d20672"},
+ "phoenix": {:hex, :phoenix, "1.6.16", "e5bdd18c7a06da5852a25c7befb72246de4ddc289182285f8685a40b7b5f5451", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e15989ff34f670a96b95ef6d1d25bad0d9c50df5df40b671d8f4a669e050ac39"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
- "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"},
- "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.2", "0769470265eb13af01b5001b29cb935f4710d6adaa1ffc18417a570a337a2f0f", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.1", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "5bc6c6b38a2ca8b5020b442322fcee6afd5e641637a0b1fb059d4bd89bc58e7b"},
+ "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"},
+ "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"},
- "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.5", "63f52a6f9f6983f04e424586ff897c016ecc5e4f8d1e2c22c2887af1c57215d8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.5.9 or ~> 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c5586e6a3d4df71b8214c769d4f5eb8ece2b4001711a7ca0f97323c36958b0e3"},
+ "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.14", "5ec615d4d61bf9d4755f158bd6c80372b715533fe6d6219e12d74fb5eedbeac1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "afeb6ba43ce329a6f7fc1c9acdfc6d3039995345f025febb7f409a92f6faebd3"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
- "phoenix_swoosh": {:hex, :phoenix_swoosh, "1.1.0", "f8e4780705c9f254cc853f7a40e25f7198ba4d91102bcfad2226669b69766b35", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "aa82f10afd9a4b6080fdf3274dbb9432b25b210d42b4b6b55308f6e59cd87c3d"},
- "phoenix_template": {:hex, :phoenix_template, "1.0.0", "c57bc5044f25f007dc86ab21895688c098a9f846a8dda6bc40e2d0ddc146e38f", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "1b066f99a26fd22064c12b2600a9a6e56700f591bf7b20b418054ea38b4d4357"},
- "phoenix_view": {:hex, :phoenix_view, "2.0.1", "a653e3d9d944aace0a064e4a13ad473ffa68f7bc4ca42dbf83cc1d464f1fb295", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "6c358e2cefc5f341c728914b867c556bbfd239fed9e881bac257d70cb2b8a6f6"},
+ "phoenix_swoosh": {:hex, :phoenix_swoosh, "1.2.0", "a544d83fde4a767efb78f45404a74c9e37b2a9c5ea3339692e65a6966731f935", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "e88d117251e89a16b92222415a6d87b99a96747ddf674fc5c7631de734811dba"},
+ "phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"},
+ "phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"},
"plug": {:hex, :plug, "1.10.4", "41eba7d1a2d671faaf531fa867645bd5a3dce0957d8e2a3f398ccff7d2ef017f", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad1e233fe73d2eec56616568d260777b67f53148a999dc2d048f4eb9778fe4a0"},
- "plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"},
- "plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"},
+ "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"},
+ "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"},
"plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"},
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
"postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"},
- "pot": {:hex, :pot, "1.0.1", "81b511b1fa7c3123171c265cb7065a1528cebd7277b0cbc94257c50a8b2e4c17", [:rebar3], [], "hexpm", "ed87f5976531d91528452faa1138a5328db7f9f20d8feaae15f5051f79bcfb6d"},
+ "pot": {:hex, :pot, "1.0.2", "13abb849139fdc04ab8154986abbcb63bdee5de6ed2ba7e1713527e33df923dd", [:rebar3], [], "hexpm", "78fe127f5a4f5f919d6ea5a2a671827bd53eb9d37e5b4128c0ad3df99856c2e0"},
"prom_ex": {:hex, :prom_ex, "1.7.1", "39331ee3fe6f9a8587d8208bf9274a253bb80281700e127dd18786cda5e08c37", [:mix], [{:absinthe, ">= 1.6.0", [hex: :absinthe, repo: "hexpm", optional: true]}, {:broadway, ">= 1.0.2", [hex: :broadway, repo: "hexpm", optional: true]}, {:ecto, ">= 3.5.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:finch, "~> 0.10.2", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:oban, ">= 2.4.0", [hex: :oban, repo: "hexpm", optional: true]}, {:phoenix, ">= 1.5.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, ">= 0.14.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, ">= 1.12.1", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, "~> 2.5.1", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.1", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.0.2", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: false]}, {:telemetry_poller, "~> 1.0.0", [hex: :telemetry_poller, repo: "hexpm", optional: false]}], "hexpm", "4c978872b88a929833925a0f4d0561824804c671fdd04581e765509ed0a6ed08"},
- "prometheus": {:hex, :prometheus, "4.8.0", "1ce1e1002b173c336d61f186b56263346536e76814edd9a142e12aeb2d6c1ad2", [:mix, :rebar3], [], "hexpm", "0fc2e17103073edb3758a46a5d44b006191bf25b73cbaa2b779109de396afcb5"},
+ "prometheus": {:hex, :prometheus, "4.10.0", "792adbf0130ff61b5fa8826f013772af24b6e57b984445c8d602c8a0355704a1", [:mix, :rebar3], [{:quantile_estimator, "~> 0.2.1", [hex: :quantile_estimator, repo: "hexpm", optional: false]}], "hexpm", "2a99bb6dce85e238c7236fde6b0064f9834dc420ddbd962aac4ea2a3c3d59384"},
"prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"},
"prometheus_ex": {:git, "https://github.com/lanodan/prometheus.ex.git", "31f7fbe4b71b79ba27efc2a5085746c4011ceb8f", [branch: "fix/elixir-1.14"]},
"prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "c4d1404ac4e9d3d963da601db2a7d8ea31194f0017057fabf0cfb9bf5a6c8c75"},
"prometheus_phx": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus-phx.git", "9cd8f248c9381ffedc799905050abce194a97514", [branch: "no-logging"]},
"prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"},
+ "quantile_estimator": {:hex, :quantile_estimator, "0.2.1", "ef50a361f11b5f26b5f16d0696e46a9e4661756492c981f7b2229ef42ff1cd15", [:rebar3], [], "hexpm", "282a8a323ca2a845c9e6f787d166348f776c1d4a41ede63046d72d422e3da946"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
- "recon": {:hex, :recon, "2.5.1", "430ffa60685ac1efdfb1fe4c97b8767c92d0d92e6e7c3e8621559ba77598678a", [:mix, :rebar3], [], "hexpm", "5721c6b6d50122d8f68cccac712caa1231f97894bab779eff5ff0f886cb44648"},
+ "recon": {:hex, :recon, "2.5.3", "739107b9050ea683c30e96de050bc59248fd27ec147696f79a8797ff9fa17153", [:mix, :rebar3], [], "hexpm", "6c6683f46fd4a1dfd98404b9f78dcabc7fcd8826613a89dcb984727a8c3099d7"},
"remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8", [ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"]},
- "sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"},
+ "sleeplocks": {:hex, :sleeplocks, "1.1.2", "d45aa1c5513da48c888715e3381211c859af34bee9b8290490e10c90bb6ff0ca", [:rebar3], [], "hexpm", "9fe5d048c5b781d6305c1a3a0f40bb3dfc06f49bf40571f3d2d0c57eaa7f59a5"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
- "sweet_xml": {:hex, :sweet_xml, "0.7.2", "4729f997286811fabdd8288f8474e0840a76573051062f066c4b597e76f14f9f", [:mix], [], "hexpm", "6894e68a120f454534d99045ea3325f7740ea71260bc315f82e29731d570a6e8"},
- "swoosh": {:hex, :swoosh, "1.8.2", "af9a22ab2c0d20b266f61acca737fa11a121902de9466a39e91bacdce012101c", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d058ba750eafadb6c09a84a352c14c5d1eeeda6e84945fcc95785b7f3067b7db"},
+ "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
+ "sweet_xml": {:hex, :sweet_xml, "0.7.3", "debb256781c75ff6a8c5cbf7981146312b66f044a2898f453709a53e5031b45b", [:mix], [], "hexpm", "e110c867a1b3fe74bfc7dd9893aa851f0eed5518d0d7cad76d7baafd30e4f5ba"},
+ "swoosh": {:hex, :swoosh, "1.9.1", "0a5d7bf9954eb41d7e55525bc0940379982b090abbaef67cd8e1fd2ed7f8ca1a", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76dffff3ffcab80f249d5937a592eaef7cc49ac6f4cdd27e622868326ed6371e"},
"syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
"table_rex": {:hex, :table_rex, "3.1.1", "0c67164d1714b5e806d5067c1e96ff098ba7ae79413cc075973e17c38a587caa", [:mix], [], "hexpm", "678a23aba4d670419c23c17790f9dcd635a4a89022040df7d5d772cb21012490"},
"telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"},
@@ -124,10 +125,10 @@
"telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.0.2", "c98b1c580de637bfeac00db41b9fb91fb4c3548ee3d512a8ed7299172312eaf3", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "48351a0d56f80e38c997b44232b1043e0a081670d16766eee920e6254175b730"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
"tesla": {:hex, :tesla, "1.4.4", "bb89aa0c9745190930366f6a2ac612cdf2d0e4d7fff449861baa7875afd797b2", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "d5503a49f9dec1b287567ea8712d085947e247cb11b06bc54adb05bfde466457"},
- "timex": {:hex, :timex, "3.7.5", "3eca56e23bfa4e0848f0b0a29a92fa20af251a975116c6d504966e8a90516dfd", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "a15608dca680f2ef663d71c95842c67f0af08a0f3b1d00e17bbd22872e2874e4"},
+ "timex": {:hex, :timex, "3.7.7", "3ed093cae596a410759104d878ad7b38e78b7c2151c6190340835515d4a46b8a", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "0ec4b09f25fe311321f9fc04144a7e3affe48eb29481d7a5583849b6c4dfa0a7"},
"trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
"tzdata": {:hex, :tzdata, "1.0.5", "69f1ee029a49afa04ad77801febaf69385f3d3e3d1e4b56b9469025677b89a28", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "55519aa2a99e5d2095c1e61cc74c9be69688f8ab75c27da724eb8279ff402a5a"},
- "ueberauth": {:hex, :ueberauth, "0.6.3", "d42ace28b870e8072cf30e32e385579c57b9cc96ec74fa1f30f30da9c14f3cc0", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "afc293d8a1140d6591b53e3eaf415ca92842cb1d32fad3c450c6f045f7f91b60"},
+ "ueberauth": {:hex, :ueberauth, "0.10.5", "806adb703df87e55b5615cf365e809f84c20c68aa8c08ff8a416a5a6644c4b02", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3efd1f31d490a125c7ed453b926f7c31d78b97b8a854c755f5c40064bf3ac9e1"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"},
"web_push_encryption": {:hex, :web_push_encryption, "0.3.1", "76d0e7375142dfee67391e7690e89f92578889cbcf2879377900b5620ee4708d", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.1", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "4f82b2e57622fb9337559058e8797cb0df7e7c9790793bdc4e40bc895f70e2a2"},
diff --git a/priv/gettext/config_descriptions.pot b/priv/gettext/config_descriptions.pot
index 1c3a98d3e..53b81fa41 100644
--- a/priv/gettext/config_descriptions.pot
+++ b/priv/gettext/config_descriptions.pot
@@ -1914,12 +1914,6 @@ msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
-msgctxt "config description at :pleroma-:instance > :privileged_staff"
-msgid "Let moderators access sensitive data (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)"
-msgstr ""
-
-#, elixir-autogen, elixir-format
-#: lib/pleroma/docs/translator.ex:5
msgctxt "config description at :pleroma-:instance > :profile_directory"
msgid "Enable profile directory."
msgstr ""
@@ -4326,12 +4320,6 @@ msgstr ""
#, elixir-autogen, elixir-format
#: lib/pleroma/docs/translator.ex:5
-msgctxt "config label at :pleroma-:instance > :privileged_staff"
-msgid "Privileged staff"
-msgstr ""
-
-#, elixir-autogen, elixir-format
-#: lib/pleroma/docs/translator.ex:5
msgctxt "config label at :pleroma-:instance > :profile_directory"
msgid "Profile directory"
msgstr ""
@@ -6021,3 +6009,39 @@ msgstr ""
msgctxt "config label at :pleroma-:instance > :report_strip_status"
msgid "Report strip status"
msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/docs/translator.ex:5
+msgctxt "config description at :pleroma-:instance > :admin_privileges"
+msgid "What extra privileges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/docs/translator.ex:5
+msgctxt "config description at :pleroma-:instance > :moderator_privileges"
+msgid "What extra privileges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/docs/translator.ex:5
+msgctxt "config label at :pleroma-:instance > :admin_privileges"
+msgid "Admin privileges"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/docs/translator.ex:5
+msgctxt "config label at :pleroma-:instance > :moderator_privileges"
+msgid "Moderator privileges"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/docs/translator.ex:5
+msgctxt "config description at :pleroma-:instance > :languages"
+msgid "Languages to be exposed in /api/v1/instance. Should be in the format of BCP47 language codes."
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/docs/translator.ex:5
+msgctxt "config label at :pleroma-:instance > :languages"
+msgid "Languages"
+msgstr ""
diff --git a/priv/gettext/en/LC_MESSAGES/oauth_scopes.po b/priv/gettext/en/LC_MESSAGES/oauth_scopes.po
new file mode 100644
index 000000000..105ca022b
--- /dev/null
+++ b/priv/gettext/en/LC_MESSAGES/oauth_scopes.po
@@ -0,0 +1,264 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"PO-Revision-Date: 2023-05-02 17:02-0400\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin"
+msgstr "All admin access"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read"
+msgstr "Read all using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write"
+msgstr "Write all using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "follow"
+msgstr "Read and write user relationships"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "push"
+msgstr "Push notifications"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read"
+msgstr "Read everything"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:accounts"
+msgstr "Read information of all accounts"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:backups"
+msgstr "Read your backups"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:blocks"
+msgstr "Read block relationships"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:bookmarks"
+msgstr "Read your bookmarks"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:chats"
+msgstr "Read your chats"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:favourites"
+msgstr "Read your favourites"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:filters"
+msgstr "Read your filtering settings"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:follows"
+msgstr "Read follow relationships"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:lists"
+msgstr "Read your lists"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:notifications"
+msgstr "Read your notifications"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:reports"
+msgstr "Read your reports"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:search"
+msgstr "Perform searches"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:statuses"
+msgstr "Read all statuses you can see"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write"
+msgstr "Write everything"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:accounts"
+msgstr "Change your account information"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:blocks"
+msgstr "Block or unblock someone"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:bookmarks"
+msgstr "Add to or remove from your bookmarks"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:chats"
+msgstr "Create or delete chats or chat messages, or mark them as read"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:conversations"
+msgstr "Change recipients of, mark as read, or delete conversations"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:favourites"
+msgstr "Favourite or unfavourite statuses"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:filters"
+msgstr "Change your filtering settings"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:follow"
+msgstr "Follow or unfollow someone"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:follows"
+msgstr "Follow or unfollow someone"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:lists"
+msgstr "Create, change or delete your lists"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:media"
+msgstr "Upload media files or modify those you uploaded"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:mutes"
+msgstr "Mute or unmute someone"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:notifications"
+msgstr "Mark notifications as read"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:reports"
+msgstr "Submit reports"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:statuses"
+msgstr "Post, edit, reblog or react to statuses"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:accounts"
+msgstr "Read all accounts using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:chats"
+msgstr "Read all chats using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:invites"
+msgstr "Read all invites using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:media_proxy_caches"
+msgstr "Read media proxy caches using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:reports"
+msgstr "Read all reports using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:statuses"
+msgstr "Read all statuses using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:accounts"
+msgstr "Change all accounts using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:chats"
+msgstr "Change all chats using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:follows"
+msgstr "Change follow relationships using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:invites"
+msgstr "Invite or revoke an invite using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:media_proxy_caches"
+msgstr "Change media proxy caches using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:reports"
+msgstr "Handle reports using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:statuses"
+msgstr "Delete, change scope of, or mark as sensitive statuses using admin API"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:media"
+msgstr "Read media attachments"
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:mutes"
+msgstr "Read mute relationships"
diff --git a/priv/gettext/errors.pot b/priv/gettext/errors.pot
index 19a0039ca..fa61d509e 100644
--- a/priv/gettext/errors.pot
+++ b/priv/gettext/errors.pot
@@ -111,7 +111,7 @@ msgid "Can't display this activity"
msgstr ""
#, elixir-autogen, elixir-format
-#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:337
+#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:334
msgid "Can't find user"
msgstr ""
@@ -236,7 +236,7 @@ msgid "Poll's author can't vote"
msgstr ""
#, elixir-autogen, elixir-format
-#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:502
+#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:499
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:20
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:39
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:51
@@ -558,12 +558,11 @@ msgid "Access denied"
msgstr ""
#, elixir-autogen, elixir-format
-#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:334
+#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:331
msgid "This API requires an authenticated user"
msgstr ""
#, elixir-autogen, elixir-format
-#: lib/pleroma/web/plugs/ensure_staff_privileged_plug.ex:26
#: lib/pleroma/web/plugs/user_is_admin_plug.ex:21
msgid "User is not an admin."
msgstr ""
@@ -586,7 +585,6 @@ msgid "Too many attachments"
msgstr ""
#, elixir-autogen, elixir-format
-#: lib/pleroma/web/plugs/ensure_staff_privileged_plug.ex:33
#: lib/pleroma/web/plugs/user_is_staff_plug.ex:20
msgid "User is not a staff member."
msgstr ""
@@ -602,3 +600,10 @@ msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:264
msgid "File is too large"
msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/plugs/ensure_privileged_plug.ex:21
+#: lib/pleroma/web/plugs/ensure_privileged_plug.ex:34
+#: lib/pleroma/web/plugs/ensure_privileged_plug.ex:41
+msgid "User isn't privileged."
+msgstr ""
diff --git a/priv/gettext/oauth_scopes.pot b/priv/gettext/oauth_scopes.pot
new file mode 100644
index 000000000..5f7b425f3
--- /dev/null
+++ b/priv/gettext/oauth_scopes.pot
@@ -0,0 +1,261 @@
+## This file is a PO Template file.
+##
+## "msgid"s here are often extracted from source code.
+## Add new translations manually only if they're dynamic
+## translations that can't be statically extracted.
+##
+## Run "mix gettext.extract" to bring this file up to
+## date. Leave "msgstr"s empty as changing them here has no
+## effect: edit them in PO (.po) files instead.
+msgid ""
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "follow"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "push"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:accounts"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:backups"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:blocks"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:bookmarks"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:chats"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:favourites"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:filters"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:follows"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:lists"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:notifications"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:reports"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:search"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:statuses"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:accounts"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:blocks"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:bookmarks"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:chats"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:conversations"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:favourites"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:filters"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:follow"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:follows"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:lists"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:media"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:mutes"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:notifications"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:reports"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "write:statuses"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:accounts"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:chats"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:invites"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:media_proxy_caches"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:reports"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:read:statuses"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:accounts"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:chats"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:follows"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:invites"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:media_proxy_caches"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:reports"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "admin:write:statuses"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:media"
+msgstr ""
+
+#, elixir-autogen, elixir-format
+#: lib/pleroma/web/api_spec/scopes/translator.ex:5
+msgid "read:mutes"
+msgstr ""
diff --git a/priv/scrubbers/default.ex b/priv/scrubbers/default.ex
index e10e3ec87..d1215d2e0 100644
--- a/priv/scrubbers/default.ex
+++ b/priv/scrubbers/default.ex
@@ -33,35 +33,35 @@ defmodule Pleroma.HTML.Scrubber.Default do
"ugc"
])
- Meta.allow_tag_with_these_attributes(:a, ["name", "title"])
-
- Meta.allow_tag_with_these_attributes(:abbr, ["title"])
-
- Meta.allow_tag_with_these_attributes(:b, [])
- Meta.allow_tag_with_these_attributes(:blockquote, [])
- Meta.allow_tag_with_these_attributes(:br, [])
- Meta.allow_tag_with_these_attributes(:code, [])
- Meta.allow_tag_with_these_attributes(:del, [])
- Meta.allow_tag_with_these_attributes(:em, [])
- Meta.allow_tag_with_these_attributes(:hr, [])
- Meta.allow_tag_with_these_attributes(:i, [])
- Meta.allow_tag_with_these_attributes(:li, [])
- Meta.allow_tag_with_these_attributes(:ol, [])
- Meta.allow_tag_with_these_attributes(:p, [])
- Meta.allow_tag_with_these_attributes(:pre, [])
- Meta.allow_tag_with_these_attributes(:strong, [])
- Meta.allow_tag_with_these_attributes(:sub, [])
- Meta.allow_tag_with_these_attributes(:sup, [])
- Meta.allow_tag_with_these_attributes(:ruby, [])
- Meta.allow_tag_with_these_attributes(:rb, [])
- Meta.allow_tag_with_these_attributes(:rp, [])
- Meta.allow_tag_with_these_attributes(:rt, [])
- Meta.allow_tag_with_these_attributes(:rtc, [])
- Meta.allow_tag_with_these_attributes(:u, [])
- Meta.allow_tag_with_these_attributes(:ul, [])
+ Meta.allow_tag_with_these_attributes(:a, ["name", "title", "lang"])
+
+ Meta.allow_tag_with_these_attributes(:abbr, ["title", "lang"])
+
+ Meta.allow_tag_with_these_attributes(:b, ["lang"])
+ Meta.allow_tag_with_these_attributes(:blockquote, ["lang"])
+ Meta.allow_tag_with_these_attributes(:br, ["lang"])
+ Meta.allow_tag_with_these_attributes(:code, ["lang"])
+ Meta.allow_tag_with_these_attributes(:del, ["lang"])
+ Meta.allow_tag_with_these_attributes(:em, ["lang"])
+ Meta.allow_tag_with_these_attributes(:hr, ["lang"])
+ Meta.allow_tag_with_these_attributes(:i, ["lang"])
+ Meta.allow_tag_with_these_attributes(:li, ["lang"])
+ Meta.allow_tag_with_these_attributes(:ol, ["lang"])
+ Meta.allow_tag_with_these_attributes(:p, ["lang"])
+ Meta.allow_tag_with_these_attributes(:pre, ["lang"])
+ Meta.allow_tag_with_these_attributes(:strong, ["lang"])
+ Meta.allow_tag_with_these_attributes(:sub, ["lang"])
+ Meta.allow_tag_with_these_attributes(:sup, ["lang"])
+ Meta.allow_tag_with_these_attributes(:ruby, ["lang"])
+ Meta.allow_tag_with_these_attributes(:rb, ["lang"])
+ Meta.allow_tag_with_these_attributes(:rp, ["lang"])
+ Meta.allow_tag_with_these_attributes(:rt, ["lang"])
+ Meta.allow_tag_with_these_attributes(:rtc, ["lang"])
+ Meta.allow_tag_with_these_attributes(:u, ["lang"])
+ Meta.allow_tag_with_these_attributes(:ul, ["lang"])
Meta.allow_tag_with_this_attribute_values(:span, "class", ["h-card", "recipients-inline"])
- Meta.allow_tag_with_these_attributes(:span, [])
+ Meta.allow_tag_with_these_attributes(:span, ["lang"])
Meta.allow_tag_with_this_attribute_values(:code, "class", ["inline"])
@@ -77,29 +77,30 @@ defmodule Pleroma.HTML.Scrubber.Default do
"width",
"height",
"title",
- "alt"
+ "alt",
+ "lang"
])
end
if Pleroma.Config.get([:markup, :allow_tables]) do
- Meta.allow_tag_with_these_attributes(:table, [])
- Meta.allow_tag_with_these_attributes(:tbody, [])
- Meta.allow_tag_with_these_attributes(:td, [])
- Meta.allow_tag_with_these_attributes(:th, [])
- Meta.allow_tag_with_these_attributes(:thead, [])
- Meta.allow_tag_with_these_attributes(:tr, [])
+ Meta.allow_tag_with_these_attributes(:table, ["lang"])
+ Meta.allow_tag_with_these_attributes(:tbody, ["lang"])
+ Meta.allow_tag_with_these_attributes(:td, ["lang"])
+ Meta.allow_tag_with_these_attributes(:th, ["lang"])
+ Meta.allow_tag_with_these_attributes(:thead, ["lang"])
+ Meta.allow_tag_with_these_attributes(:tr, ["lang"])
end
if Pleroma.Config.get([:markup, :allow_headings]) do
- Meta.allow_tag_with_these_attributes(:h1, [])
- Meta.allow_tag_with_these_attributes(:h2, [])
- Meta.allow_tag_with_these_attributes(:h3, [])
- Meta.allow_tag_with_these_attributes(:h4, [])
- Meta.allow_tag_with_these_attributes(:h5, [])
+ Meta.allow_tag_with_these_attributes(:h1, ["lang"])
+ Meta.allow_tag_with_these_attributes(:h2, ["lang"])
+ Meta.allow_tag_with_these_attributes(:h3, ["lang"])
+ Meta.allow_tag_with_these_attributes(:h4, ["lang"])
+ Meta.allow_tag_with_these_attributes(:h5, ["lang"])
end
if Pleroma.Config.get([:markup, :allow_fonts]) do
- Meta.allow_tag_with_these_attributes(:font, ["face"])
+ Meta.allow_tag_with_these_attributes(:font, ["face", "lang"])
end
Meta.strip_everything_not_covered()
diff --git a/test/fixtures/custom-emoji-reaction.json b/test/fixtures/custom-emoji-reaction.json
new file mode 100644
index 000000000..003de0511
--- /dev/null
+++ b/test/fixtures/custom-emoji-reaction.json
@@ -0,0 +1,28 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "Hashtag": "as:Hashtag"
+ }
+ ],
+ "type": "Like",
+ "id": "https://misskey.local.live/likes/917ocsybgp",
+ "actor": "https://misskey.local.live/users/8x8yep20u2",
+ "object": "https://pleroma.local.live/objects/89937a53-2692-4631-bb62-770091267391",
+ "content": ":hanapog:",
+ "_misskey_reaction": ":hanapog:",
+ "tag": [
+ {
+ "id": "https://misskey.local.live/emojis/hanapog",
+ "type": "Emoji",
+ "name": ":hanapog:",
+ "updated": "2022-06-07T12:00:05.773Z",
+ "icon": {
+ "type": "Image",
+ "mediaType": "image/png",
+ "url": "https://misskey.local.live/files/webpublic-8f8a9768-7264-4171-88d6-2356aabeadcd"
+ }
+ }
+ ]
+}
diff --git a/test/fixtures/fep-e232.json b/test/fixtures/fep-e232.json
new file mode 100644
index 000000000..e9d12ae35
--- /dev/null
+++ b/test/fixtures/fep-e232.json
@@ -0,0 +1,31 @@
+{
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Create",
+ "actor": "https://example.org/users/alice",
+ "object": {
+ "id": "https://example.org/objects/10",
+ "type": "Note",
+ "attributedTo": "https://example.org/users/alice",
+ "content": "<p>test <a href=\"https://example.org/objects/9\">https://example.org/objects/9</a></p>",
+ "published": "2022-10-01T21:30:05.211215Z",
+ "tag": [
+ {
+ "name": "@bob@example.net",
+ "type": "Mention",
+ "href": "https://example.net/users/bob"
+ },
+ {
+ "name": "https://example.org/objects/9",
+ "type": "Link",
+ "href": "https://example.org/objects/9",
+ "mediaType": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
+ }
+ ],
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://example.org/users/alice/followers"
+ ]
+ }
+}
diff --git a/test/fixtures/hubzilla-actor.json b/test/fixtures/hubzilla-actor.json
new file mode 100644
index 000000000..445d6413c
--- /dev/null
+++ b/test/fixtures/hubzilla-actor.json
@@ -0,0 +1 @@
+{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1","https://hub.somaton.com/apschema/v1.9"],"type":"Person","id":"https://hub.somaton.com/channel/testc6","preferredUsername":"testc6","name":"testc6 lala","updated":"2021-08-29T10:07:23Z","icon":{"type":"Image","mediaType":"image/png","updated":"2021-10-09T04:54:35Z","url":"https://hub.somaton.com/photo/profile/l/33","height":300,"width":300},"url":"https://hub.somaton.com/channel/testc6","publicKey":{"id":"https://hub.somaton.com/channel/testc6","owner":"https://hub.somaton.com/channel/testc6","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq5ep+6MhhaAiqZSd8nXe\nUAokXNgqTr/DjUic5VDudjQgvetchaiBUieBnqpJSPNNAvvf6Qs4eDW4w2JQeA6y\nqEplKrmb8l1EyhwXeFLDUGQdf0f6hg++x5mIrO6uX0tlQGU6nutvhItn6JMZc5GU\nv3C/UW0OfHCCdHSGZ/1nIqq1P98FqF0+PA1pvTHCkLr4kcKzfpmkLjsccUSq0FGh\nQF+paW9FU89o4hkaH/X3E/Ac7DL8zgcyt29KSj4eUIvjBIEPAMdRno345fiZ+QYr\nlYQYaBC2gvozjxtxl9MyfqjBRzfl9VDHzoDvMn5+LD5dCRB1zOESv/b3EpiHYqXl\nwiPzP9az8e8cw6D72n/Mlrf27yIuVAdwaGdbAwekjIQZHIDoP0XNnA5i31RLpEMI\nbNpH47ChtjxeilQZ3va6qIShYfGlndpy/rx4i4Yt4xIG+BbGb/dWo3AbtHi64fPZ\nMoLuR71sEBe7uAvalJ+lopxuQ2qLJpCInukQ13p/G/n9tVDwbfGyumzr5hHk7JoY\nN+JqH737MCZqb9dRDof+fju58GY1VzFjBph38sHYJh0ykA+2BzYU2+nT7CDXfKWA\nsmHhizp7haoPjl/yclZG5FJwg3oqHTD14dASUs+OI4K+Q//74wfb4/6E3CDyOkW3\nUj+8TPZooKulxtQ9ezergr0CAwEAAQ==\n-----END PUBLIC KEY-----\n"},"outbox":"https://hub.somaton.com/outbox/testc6","inbox":"https://hub.somaton.com/inbox/testc6","followers":"https://hub.somaton.com/followers/testc6","following":"https://hub.somaton.com/following/testc6","endpoints":{"sharedInbox":"https://hub.somaton.com/inbox"},"discoverable":false,"signature":{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],"type":"RsaSignature2017","nonce":"8d6dea03f04cbb7faaf43958a4cf39a115ff1c61c7febaa6154c463eab9a42c8","creator":"https://hub.somaton.com/channel/testc6","created":"2021-10-13T18:21:48Z","signatureValue":"N4CJBO2K/8v7KI97REyJXaSYOlLWscuEDlODDnjNYD1fbVQFO3s2JtqPcN2lVJvNTlW5HUze+owaAYNcvZe3mNm1iz05Xru3s8yRA8bNCdKBuWd/3zb3/JQVkbSb09D2PloeuoKBQmPIn+dNiTyFR0jxLsxCXXTomGKigWPtTOUIt52Dv9MFJ3jRZmfoykT9bHrAIVCASHoiluhTkPAzc6pt0lSyZd0D3X4J1K4/sLXa8HRoooMFu2dHWfqV4tyLU9WzofAhvnYg9tEbKCH42DIAbwDfjAeC4qL8xkqAlYWLvXYVGH76cZLdp9Zuv1p3NHqaPEJ85MbuaUkfnU75Bx/Fcfoi0pEieWRdFvMx5b/UFwGbJd6iSAO1zRbGYTPEMPWHzh0AEAaLeyY+g3ZmpNu88ujrIr8iJ1U4EkjOBn8ooxA5LaI2fXDiYC2NwRiAbY+xVtgJgvHDi9tXCdvzjZWfU/cgiwF/cYMbsB2BCyPRd+XZhudfXSOysFC4WYnawhiRVevba9lQ6rEP4FMepOGq4ZOSGzxgw2xNIXpu0IkrxX5mEv/ahEhDy1KGRIFc0GnPJrv3kMVxJrZ7SF8PNAGqftQBLkqQR+SEygs3XB4cd2DQ2lPeiMd8+Xv+lBjtzZtZAM/Y4CZCOdV9DHXDGNSKKFDzzna4QcUzQ+KRc8w="}} \ No newline at end of file
diff --git a/test/fixtures/hubzilla-create-image.json b/test/fixtures/hubzilla-create-image.json
new file mode 100644
index 000000000..9f0669bb7
--- /dev/null
+++ b/test/fixtures/hubzilla-create-image.json
@@ -0,0 +1 @@
+{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1","https://hub.somaton.com/apschema/v1.9"],"type":"Create","id":"https://hub.somaton.com/activity/452583b2-7e1f-4ac3-8334-ff666f134afe","diaspora:guid":"452583b2-7e1f-4ac3-8334-ff666f134afe","name":"daf82c18ef92a84cda72(1).jpg","published":"2021-10-12T21:28:26Z","actor":"https://hub.somaton.com/channel/testc6","object":{"type":"Image","name":"daf82c18ef92a84cda72(1).jpg","published":"2021-10-12T21:28:23Z","updated":"2021-10-12T21:28:23Z","attributedTo":"https://hub.somaton.com/channel/testc6","id":"https://hub.somaton.com/photo/452583b2-7e1f-4ac3-8334-ff666f134afe","url":[{"type":"Link","mediaType":"image/jpeg","href":"https://hub.somaton.com/photo/452583b2-7e1f-4ac3-8334-ff666f134afe-0.jpg","width":2200,"height":2200},{"type":"Link","mediaType":"image/jpeg","href":"https://hub.somaton.com/photo/452583b2-7e1f-4ac3-8334-ff666f134afe-1.jpg","width":1024,"height":1024},{"type":"Link","mediaType":"image/jpeg","href":"https://hub.somaton.com/photo/452583b2-7e1f-4ac3-8334-ff666f134afe-2.jpg","width":640,"height":640},{"type":"Link","mediaType":"image/jpeg","href":"https://hub.somaton.com/photo/452583b2-7e1f-4ac3-8334-ff666f134afe-3.jpg","width":320,"height":320},{"type":"Link","mediaType":"text/html","href":"https://hub.somaton.com/photos/testc6/image/452583b2-7e1f-4ac3-8334-ff666f134afe"}],"source":{"content":"[footer][zrl=https://hub.somaton.com/channel/testc6]testc6 lala[/zrl] posted [zrl=https://hub.somaton.com/photos/testc6/image/452583b2-7e1f-4ac3-8334-ff666f134afe]a new photo[/zrl] to [zrl=https://hub.somaton.com/photos/testc6/album/1e9b0d74-633e-4bd0-b37f-694bb0ed0145]test[/zrl][/footer]","mediaType":"text/bbcode"},"content":"<div class=\"wall-item-footer\"><a class=\"zrl\" href=\"https://hub.somaton.com/channel/testc6\" target=\"_blank\" rel=\"nofollow noopener\" >testc6 lala</a> posted <a class=\"zrl\" href=\"https://hub.somaton.com/photos/testc6/image/452583b2-7e1f-4ac3-8334-ff666f134afe\" target=\"_blank\" rel=\"nofollow noopener\" >a new photo</a> to <a class=\"zrl\" href=\"https://hub.somaton.com/photos/testc6/album/1e9b0d74-633e-4bd0-b37f-694bb0ed0145\" target=\"_blank\" rel=\"nofollow noopener\" >test</a></div>","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://hub.somaton.com/followers/testc6"]},"target":{"type":"orderedCollection","name":"test","id":"https://hub.somaton.com/album/testc6/test"},"to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://hub.somaton.com/followers/testc6"],"signature":{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1"],"type":"RsaSignature2017","nonce":"e0d077edccf262f02ed59ff67e91a5324ccaffc3d2b3f23793b4bd24cdbe70bb","creator":"https://hub.somaton.com/channel/testc6","created":"2021-10-13T18:39:05Z","signatureValue":"YYU0/17PqqUmLCn4oVS2N62rV1G9WQ+wLax2cI+EpMw/WOWKuVvtGrvhzciQ5ITXoh3scrZRYH8Bke1jDWkjL9YtjVD6TjMsv6f3OoO1vvMNgEfQfgZJ78QQt5MoLrT2mkRa35lSmVHkTDROKJPrwIAnpN6bDb577wZ63BsuBjqW7ca/E6oXSIr+meCXv3kqkyYDSz0ImYvVmki+OfX97xbYkQlzM06EgK1LZTHfuf4sk09hVfDDqVB9tHO4ObYQCYNiOWRHjA5S1Cw8WX1OQJ+GCQ8yxHmtiU3tJsxeYhxGs7VEmTLUvf/QZ0VTPumkd1CewdxzNGvAP3f9JCakuV7eyk88oqF+p7xxfxmBjLYbMTuhrcZIdUdMcjW9pENOYBbt+a+FhPsjbm8zVU3iKPqe/8UAvo01hGW7jiKJUm4qdcX3H3MExTLEFuz0NTeqxl4djlyGTT9KBqNouD+/oSSgwm6qeRZ5y3RsC27N0HRbg74qNXhhWQZVWQtHdSCHjAfHVPOSpjxpSPs7qkMLQ0vPsVsCsukZz8JCoXRo+JoKuaiaRgfiIRGNBO/XEicKMyu2JCU+UmkroiDJHy+4IfZRevnlneRa1jmu5KA/4xk5KU8l0I0Inap7TSPhv14Ex2sF89LkT8MbcDM3S3QL4urYsQj37zOKRDTFzE96TmI="}} \ No newline at end of file
diff --git a/test/mix/tasks/pleroma/openapi_spec_test.exs b/test/mix/tasks/pleroma/openapi_spec_test.exs
new file mode 100644
index 000000000..01437187a
--- /dev/null
+++ b/test/mix/tasks/pleroma/openapi_spec_test.exs
@@ -0,0 +1,62 @@
+# 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.OpenapiSpecTest do
+ use Pleroma.DataCase, async: true
+
+ alias Mix.Tasks.Pleroma.OpenapiSpec
+
+ @spec_base %{
+ "paths" => %{
+ "/cofe" => %{
+ "get" => %{
+ "operationId" => "Some.operation",
+ "tags" => []
+ }
+ },
+ "/mew" => %{
+ "post" => %{
+ "operationId" => "Another.operation",
+ "tags" => ["mew mew"]
+ }
+ }
+ },
+ "x-tagGroups" => [
+ %{
+ "name" => "mew",
+ "tags" => ["mew mew", "abc"]
+ },
+ %{
+ "name" => "lol",
+ "tags" => ["lol lol", "xyz"]
+ }
+ ]
+ }
+
+ describe "check_specs/1" do
+ test "Every operation must have a tag" do
+ assert {:error, ["Some.operation (get /cofe): No tags specified"]} ==
+ OpenapiSpec.check_specs(@spec_base)
+ end
+
+ test "Every tag must be in tag groups" do
+ spec =
+ @spec_base
+ |> put_in(["paths", "/cofe", "get", "tags"], ["abc", "def", "not specified"])
+
+ assert {:error,
+ [
+ "Some.operation (get /cofe): Tags #{inspect(["def", "not specified"])} not available. Please add it in \"x-tagGroups\" in Pleroma.Web.ApiSpec"
+ ]} == OpenapiSpec.check_specs(spec)
+ end
+
+ test "No errors if ok" do
+ spec =
+ @spec_base
+ |> put_in(["paths", "/cofe", "get", "tags"], ["abc", "mew mew"])
+
+ assert :ok == OpenapiSpec.check_specs(spec)
+ end
+ end
+end
diff --git a/test/pleroma/bbs/handler_test.exs b/test/pleroma/bbs/handler_test.exs
deleted file mode 100644
index aea3b6ead..000000000
--- a/test/pleroma/bbs/handler_test.exs
+++ /dev/null
@@ -1,89 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.BBS.HandlerTest do
- use Pleroma.DataCase, async: true
- alias Pleroma.Activity
- alias Pleroma.BBS.Handler
- alias Pleroma.Object
- alias Pleroma.Repo
- alias Pleroma.User
- alias Pleroma.Web.CommonAPI
-
- import ExUnit.CaptureIO
- import Pleroma.Factory
- import Ecto.Query
-
- test "getting the home timeline" do
- user = insert(:user)
- followed = insert(:user)
-
- {:ok, user, followed} = User.follow(user, followed)
-
- {:ok, _first} = CommonAPI.post(user, %{status: "hey"})
- {:ok, _second} = CommonAPI.post(followed, %{status: "hello"})
-
- output =
- capture_io(fn ->
- Handler.handle_command(%{user: user}, "home")
- end)
-
- assert output =~ user.nickname
- assert output =~ followed.nickname
-
- assert output =~ "hey"
- assert output =~ "hello"
- end
-
- test "posting" do
- user = insert(:user)
-
- output =
- capture_io(fn ->
- Handler.handle_command(%{user: user}, "p this is a test post")
- end)
-
- assert output =~ "Posted"
-
- activity =
- Repo.one(
- from(a in Activity,
- where: fragment("?->>'type' = ?", a.data, "Create")
- )
- )
-
- assert activity.actor == user.ap_id
- object = Object.normalize(activity, fetch: false)
- assert object.data["content"] == "this is a test post"
- end
-
- test "replying" do
- user = insert(:user)
- another_user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(another_user, %{status: "this is a test post"})
- activity_object = Object.normalize(activity, fetch: false)
-
- output =
- capture_io(fn ->
- Handler.handle_command(%{user: user}, "r #{activity.id} this is a reply")
- end)
-
- assert output =~ "Replied"
-
- reply =
- Repo.one(
- from(a in Activity,
- where: fragment("?->>'type' = ?", a.data, "Create"),
- where: a.actor == ^user.ap_id
- )
- )
-
- assert reply.actor == user.ap_id
-
- reply_object_data = Object.normalize(reply, fetch: false).data
- assert reply_object_data["content"] == "this is a reply"
- assert reply_object_data["inReplyTo"] == activity_object.data["id"]
- end
-end
diff --git a/test/pleroma/object_test.exs b/test/pleroma/object_test.exs
index d536e0b16..7bc5c9928 100644
--- a/test/pleroma/object_test.exs
+++ b/test/pleroma/object_test.exs
@@ -444,4 +444,42 @@ defmodule Pleroma.ObjectTest do
Enum.sort_by(object.hashtags, & &1.name)
end
end
+
+ describe "get_emoji_reactions/1" do
+ test "3-tuple current format" do
+ object = %Object{
+ data: %{
+ "reactions" => [
+ ["x", ["https://some/user"], "https://some/emoji"]
+ ]
+ }
+ }
+
+ assert Object.get_emoji_reactions(object) == object.data["reactions"]
+ end
+
+ test "2-tuple legacy format" do
+ object = %Object{
+ data: %{
+ "reactions" => [
+ ["x", ["https://some/user"]]
+ ]
+ }
+ }
+
+ assert Object.get_emoji_reactions(object) == [["x", ["https://some/user"], nil]]
+ end
+
+ test "Map format" do
+ object = %Object{
+ data: %{
+ "reactions" => %{
+ "x" => ["https://some/user"]
+ }
+ }
+ }
+
+ assert Object.get_emoji_reactions(object) == [["x", ["https://some/user"], nil]]
+ end
+ end
end
diff --git a/test/pleroma/user/import_test.exs b/test/pleroma/user/import_test.exs
index b4efd4bb0..f75305e0e 100644
--- a/test/pleroma/user/import_test.exs
+++ b/test/pleroma/user/import_test.exs
@@ -3,7 +3,6 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.User.ImportTest do
- alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
diff --git a/test/pleroma/user_search_test.exs b/test/pleroma/user_search_test.exs
index 1deab6888..1af9a1493 100644
--- a/test/pleroma/user_search_test.exs
+++ b/test/pleroma/user_search_test.exs
@@ -3,7 +3,6 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.UserSearchTest do
- alias Pleroma.Repo
alias Pleroma.User
use Pleroma.DataCase
diff --git a/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs b/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs
index bbdb09c4c..9bb291a38 100644
--- a/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs
@@ -38,16 +38,70 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactHandlingTest do
assert {:content, {"can't be blank", [validation: :required]}} in cng.errors
end
- test "it is not valid with a non-emoji content field", %{valid_emoji_react: valid_emoji_react} do
+ test "it is valid when custom emoji is used", %{valid_emoji_react: valid_emoji_react} do
without_emoji_content =
valid_emoji_react
- |> Map.put("content", "x")
+ |> Map.put("content", ":hello:")
+ |> Map.put("tag", [
+ %{
+ "type" => "Emoji",
+ "name" => ":hello:",
+ "icon" => %{"url" => "http://somewhere", "type" => "Image"}
+ }
+ ])
+
+ {:ok, _, _} = ObjectValidator.validate(without_emoji_content, [])
+ end
+
+ test "it is not valid when custom emoji don't have a matching tag", %{
+ valid_emoji_react: valid_emoji_react
+ } do
+ without_emoji_content =
+ valid_emoji_react
+ |> Map.put("content", ":hello:")
+ |> Map.put("tag", [
+ %{
+ "type" => "Emoji",
+ "name" => ":whoops:",
+ "icon" => %{"url" => "http://somewhere", "type" => "Image"}
+ }
+ ])
+
+ {:error, cng} = ObjectValidator.validate(without_emoji_content, [])
+
+ refute cng.valid?
+
+ assert {:tag, {"does not contain an Emoji tag", []}} in cng.errors
+ end
+
+ test "it is not valid when custom emoji have no tags", %{
+ valid_emoji_react: valid_emoji_react
+ } do
+ without_emoji_content =
+ valid_emoji_react
+ |> Map.put("content", ":hello:")
+ |> Map.put("tag", [])
+
+ {:error, cng} = ObjectValidator.validate(without_emoji_content, [])
+
+ refute cng.valid?
+
+ assert {:tag, {"does not contain an Emoji tag", []}} in cng.errors
+ end
+
+ test "it is not valid when custom emoji doesn't match a shortcode format", %{
+ valid_emoji_react: valid_emoji_react
+ } do
+ without_emoji_content =
+ valid_emoji_react
+ |> Map.put("content", "hello")
+ |> Map.put("tag", [])
{:error, cng} = ObjectValidator.validate(without_emoji_content, [])
refute cng.valid?
- assert {:content, {"must be a single character emoji", []}} in cng.errors
+ assert {:tag, {"does not contain an Emoji tag", []}} in cng.errors
end
end
end
diff --git a/test/pleroma/web/activity_pub/side_effects_test.exs b/test/pleroma/web/activity_pub/side_effects_test.exs
index b24831e85..6820e23d0 100644
--- a/test/pleroma/web/activity_pub/side_effects_test.exs
+++ b/test/pleroma/web/activity_pub/side_effects_test.exs
@@ -453,7 +453,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
object = Object.get_by_ap_id(emoji_react.data["object"])
assert object.data["reaction_count"] == 1
- assert ["👌", [user.ap_id]] in object.data["reactions"]
+ assert ["👌", [user.ap_id], nil] in object.data["reactions"]
end
test "creates a notification", %{emoji_react: emoji_react, poster: poster} do
diff --git a/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
index 9d99df27c..f2e1cefa3 100644
--- a/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
@@ -34,7 +34,56 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do
object = Object.get_by_ap_id(data["object"])
assert object.data["reaction_count"] == 1
- assert match?([["👌", _]], object.data["reactions"])
+ assert match?([["👌", _, nil]], object.data["reactions"])
+ end
+
+ test "it works for incoming custom emoji reactions" do
+ user = insert(:user)
+ other_user = insert(:user, local: false)
+ {:ok, activity} = CommonAPI.post(user, %{status: "hello"})
+
+ data =
+ File.read!("test/fixtures/custom-emoji-reaction.json")
+ |> Jason.decode!()
+ |> Map.put("object", activity.data["object"])
+ |> Map.put("actor", other_user.ap_id)
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["actor"] == other_user.ap_id
+ assert data["type"] == "EmojiReact"
+ assert data["id"] == "https://misskey.local.live/likes/917ocsybgp"
+ assert data["object"] == activity.data["object"]
+ assert data["content"] == ":hanapog:"
+
+ assert data["tag"] == [
+ %{
+ "id" => "https://misskey.local.live/emojis/hanapog",
+ "type" => "Emoji",
+ "name" => "hanapog",
+ "updated" => "2022-06-07T12:00:05.773Z",
+ "icon" => %{
+ "type" => "Image",
+ "url" =>
+ "https://misskey.local.live/files/webpublic-8f8a9768-7264-4171-88d6-2356aabeadcd"
+ }
+ }
+ ]
+
+ object = Object.get_by_ap_id(data["object"])
+
+ assert object.data["reaction_count"] == 1
+
+ assert match?(
+ [
+ [
+ "hanapog",
+ _,
+ "https://misskey.local.live/files/webpublic-8f8a9768-7264-4171-88d6-2356aabeadcd"
+ ]
+ ],
+ object.data["reactions"]
+ )
end
test "it works for incoming unqualified emoji reactions" do
@@ -65,7 +114,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do
object = Object.get_by_ap_id(data["object"])
assert object.data["reaction_count"] == 1
- assert match?([[emoji, _]], object.data["reactions"])
+ assert match?([[^emoji, _, _]], object.data["reactions"])
end
test "it reject invalid emoji reactions" do
diff --git a/test/pleroma/web/activity_pub/transmogrifier/image_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/image_handling_test.exs
new file mode 100644
index 000000000..b85f0a477
--- /dev/null
+++ b/test/pleroma/web/activity_pub/transmogrifier/image_handling_test.exs
@@ -0,0 +1,50 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.Transmogrifier.ImageHandlingTest do
+ use Oban.Testing, repo: Pleroma.Repo
+ use Pleroma.DataCase
+
+ alias Pleroma.Activity
+ alias Pleroma.Object
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+
+ test "Hubzilla Image object" do
+ Tesla.Mock.mock(fn
+ %{url: "https://hub.somaton.com/channel/testc6"} ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/hubzilla-actor.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
+ }
+ end)
+
+ data = File.read!("test/fixtures/hubzilla-create-image.json") |> Poison.decode!()
+
+ {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
+
+ assert object = Object.normalize(activity, fetch: false)
+
+ assert object.data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
+
+ assert object.data["cc"] == ["https://hub.somaton.com/followers/testc6"]
+
+ assert object.data["attachment"] == [
+ %{
+ "mediaType" => "image/jpeg",
+ "type" => "Link",
+ "url" => [
+ %{
+ "height" => 2200,
+ "href" =>
+ "https://hub.somaton.com/photo/452583b2-7e1f-4ac3-8334-ff666f134afe-0.jpg",
+ "mediaType" => "image/jpeg",
+ "type" => "Link",
+ "width" => 2200
+ }
+ ]
+ }
+ ]
+ end
+end
diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs
index 7c406fbd0..a9ad3e9c8 100644
--- a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs
@@ -104,6 +104,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
end
end
+ @tag capture_log: true
test "it does not crash if the object in inReplyTo can't be fetched" do
data =
File.read!("test/fixtures/mastodon-post-activity.json")
@@ -723,6 +724,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
assert modified.data["context"] == object.data["id"]
end
+ @tag capture_log: true
test "the reply note uses its parent's ID when context is missing and reply is unreachable" do
insert(:user, ap_id: "https://mk.absturztau.be/users/8ozbzjs3o8")
diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs
index 6b4636d22..f76606479 100644
--- a/test/pleroma/web/activity_pub/transmogrifier_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs
@@ -123,6 +123,20 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert activity.data["context"] == object.data["context"]
end
+
+ test "it drops link tags" do
+ insert(:user, ap_id: "https://example.org/users/alice")
+
+ message = File.read!("test/fixtures/fep-e232.json") |> Jason.decode!()
+
+ assert {:ok, activity} = Transmogrifier.handle_incoming(message)
+
+ object = Object.normalize(activity)
+ assert length(object.data["tag"]) == 1
+
+ tag = object.data["tag"] |> List.first()
+ assert tag["type"] == "Mention"
+ end
end
describe "prepare outgoing" do
diff --git a/test/pleroma/web/activity_pub/utils_test.exs b/test/pleroma/web/activity_pub/utils_test.exs
index e7d1e01c4..3f93c872b 100644
--- a/test/pleroma/web/activity_pub/utils_test.exs
+++ b/test/pleroma/web/activity_pub/utils_test.exs
@@ -587,15 +587,38 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
end
describe "get_cached_emoji_reactions/1" do
- test "returns the data or an emtpy list" do
+ test "returns the normalized data or an emtpy list" do
object = insert(:note)
assert Utils.get_cached_emoji_reactions(object) == []
object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]})
- assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"]]]
+ assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"], nil]]
object = insert(:note, data: %{"reactions" => %{}})
assert Utils.get_cached_emoji_reactions(object) == []
end
end
+
+ describe "add_emoji_reaction_to_object/1" do
+ test "works with legacy 2-tuple format" do
+ user = insert(:user)
+ other_user = insert(:user)
+ third_user = insert(:user)
+
+ note =
+ insert(:note,
+ user: user,
+ data: %{
+ "reactions" => [["😿", [other_user.ap_id]]]
+ }
+ )
+
+ _activity = insert(:note_activity, user: user, note: note)
+
+ Utils.add_emoji_reaction_to_object(
+ %Activity{data: %{"content" => "😿", "actor" => third_user.ap_id}},
+ note
+ )
+ end
+ end
end
diff --git a/test/pleroma/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs
index 9ef7c0c46..19ce3681c 100644
--- a/test/pleroma/web/admin_api/controllers/config_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs
@@ -316,6 +316,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
end
+ @tag capture_log: true
test "save configs setting without explicit key", %{conn: conn} do
adapter = Application.get_env(:http, :adapter)
send_user_agent = Application.get_env(:http, :send_user_agent)
@@ -1501,15 +1502,14 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
clear_config(:database_config_whitelist, [
{:pleroma, :instance},
{:pleroma, :activitypub},
- {:pleroma, Pleroma.Upload},
- {:esshd}
+ {:pleroma, Pleroma.Upload}
])
conn = get(conn, "/api/pleroma/admin/config/descriptions")
children = json_response_and_validate_schema(conn, 200)
- assert length(children) == 4
+ assert length(children) == 3
assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3
@@ -1521,9 +1521,6 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end)
assert web_endpoint["children"]
-
- esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end)
- assert esshd["children"]
end
end
end
diff --git a/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs b/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs
index 38a23b224..0d1a4999e 100644
--- a/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs
@@ -89,6 +89,7 @@ defmodule Pleroma.Web.AdminAPI.FrontendControllerTest do
"build_url" => "http://gensokyo.2hu/builds/${ref}",
"git" => nil,
"installed" => true,
+ "installed_refs" => ["fantasy"],
"name" => "pleroma",
"ref" => "fantasy"
}
diff --git a/test/pleroma/web/api_spec/scopes/compiler_test.exs b/test/pleroma/web/api_spec/scopes/compiler_test.exs
new file mode 100644
index 000000000..99e1d343a
--- /dev/null
+++ b/test/pleroma/web/api_spec/scopes/compiler_test.exs
@@ -0,0 +1,56 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Scopes.CompilerTest do
+ use ExUnit.Case, async: true
+
+ alias Pleroma.Web.ApiSpec.Scopes.Compiler
+
+ @dummy_response %{}
+
+ @data %{
+ paths: %{
+ "/mew" => %OpenApiSpex.PathItem{
+ post: %OpenApiSpex.Operation{
+ security: [%{"oAuth" => ["a:b:c"]}],
+ responses: @dummy_response
+ },
+ get: %OpenApiSpex.Operation{security: nil, responses: @dummy_response}
+ },
+ "/mew2" => %OpenApiSpex.PathItem{
+ post: %OpenApiSpex.Operation{
+ security: [%{"oAuth" => ["d:e", "f:g"]}],
+ responses: @dummy_response
+ },
+ get: %OpenApiSpex.Operation{security: nil, responses: @dummy_response}
+ }
+ }
+ }
+
+ describe "process_scope/1" do
+ test "gives all higher-level scopes" do
+ scopes = Compiler.process_scope("admin:read:accounts")
+
+ assert [_, _, _] = scopes
+ assert "admin" in scopes
+ assert "admin:read" in scopes
+ assert "admin:read:accounts" in scopes
+ end
+ end
+
+ describe "extract_all_scopes_from/1" do
+ test "extracts scopes" do
+ scopes = Compiler.extract_all_scopes_from(@data)
+
+ assert [_, _, _, _, _, _, _] = scopes
+ assert "a" in scopes
+ assert "a:b" in scopes
+ assert "a:b:c" in scopes
+ assert "d" in scopes
+ assert "d:e" in scopes
+ assert "f" in scopes
+ assert "f:g" in scopes
+ end
+ end
+end
diff --git a/test/pleroma/web/common_api_test.exs b/test/pleroma/web/common_api_test.exs
index 5c9103e9f..968d826a2 100644
--- a/test/pleroma/web/common_api_test.exs
+++ b/test/pleroma/web/common_api_test.exs
@@ -527,6 +527,17 @@ defmodule Pleroma.Web.CommonAPITest do
assert Object.tags(object) == ["ساٴين‌س"]
end
+ test "allows lang attribute" do
+ user = insert(:user)
+ text = ~s{<span lang="en">something</span><p lang="diaetuitech_rpyhpgc">random</p>}
+
+ {:ok, activity} = CommonAPI.post(user, %{status: text, content_type: "text/html"})
+
+ object = Object.normalize(activity, fetch: false)
+
+ assert object.data["content"] == text
+ end
+
test "double dot in link is allowed" do
user = insert(:user)
text = "https://example.to/something..mp3"
diff --git a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
index 958b7f76f..128e60b0a 100644
--- a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
@@ -2031,6 +2031,39 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert [%{"id" => ^id1}] = result
end
+ test "list of blocks with with_relationships parameter" do
+ %{user: user, conn: conn} = oauth_access(["read:blocks"])
+ %{id: id1} = other_user1 = insert(:user)
+ %{id: id2} = other_user2 = insert(:user)
+ %{id: id3} = other_user3 = insert(:user)
+
+ {:ok, _, _} = User.follow(other_user1, user)
+ {:ok, _, _} = User.follow(other_user2, user)
+ {:ok, _, _} = User.follow(other_user3, user)
+
+ {:ok, _} = User.block(user, other_user1)
+ {:ok, _} = User.block(user, other_user2)
+ {:ok, _} = User.block(user, other_user3)
+
+ assert [
+ %{
+ "id" => ^id3,
+ "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
+ },
+ %{
+ "id" => ^id2,
+ "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
+ },
+ %{
+ "id" => ^id1,
+ "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
+ }
+ ] =
+ conn
+ |> get("/api/v1/blocks?with_relationships=true")
+ |> json_response_and_validate_schema(200)
+ end
+
test "account lookup", %{conn: conn} do
%{nickname: acct} = insert(:user, %{nickname: "nickname"})
%{nickname: acct_two} = insert(:user, %{nickname: "nickname@notlocaldoma.in"})
diff --git a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
index 5bae2cd00..1e8979127 100644
--- a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
@@ -626,7 +626,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses", %{
"status" => "desu~",
- "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1}
+ "poll" => %{
+ "options" => Enum.map(0..limit, fn num -> "desu #{num}" end),
+ "expires_in" => 1
+ }
})
%{"error" => error} = json_response_and_validate_schema(conn, 422)
@@ -642,7 +645,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> post("/api/v1/statuses", %{
"status" => "...",
"poll" => %{
- "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)],
+ "options" => [String.duplicate(".", limit + 1), "lol"],
"expires_in" => 1
}
})
@@ -724,6 +727,32 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
assert object.data["type"] == "Question"
assert length(object.data["oneOf"]) == 3
end
+
+ test "cannot have only one option", %{conn: conn} do
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses", %{
+ "status" => "desu~",
+ "poll" => %{"options" => ["mew"], "expires_in" => 1}
+ })
+
+ %{"error" => error} = json_response_and_validate_schema(conn, 422)
+ assert error == "Poll must contain at least 2 options"
+ end
+
+ test "cannot have only duplicated options", %{conn: conn} do
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses", %{
+ "status" => "desu~",
+ "poll" => %{"options" => ["mew", "mew"], "expires_in" => 1}
+ })
+
+ %{"error" => error} = json_response_and_validate_schema(conn, 422)
+ assert error == "Poll must contain at least 2 options"
+ end
end
test "get a status" do
diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs
index 57fa0f047..6c63d53c2 100644
--- a/test/pleroma/web/mastodon_api/update_credentials_test.exs
+++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs
@@ -375,7 +375,9 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
"pleroma_background_image" => new_background_oversized
})
- assert user_response = json_response_and_validate_schema(res, 413)
+ assert %{"error" => "File is too large"} == json_response_and_validate_schema(res, 413)
+
+ user = Repo.get(User, user.id)
assert user.background == %{}
clear_config([:instance, :upload_limit], upload_limit)
diff --git a/test/pleroma/web/mastodon_api/views/notification_view_test.exs b/test/pleroma/web/mastodon_api/views/notification_view_test.exs
index 6ea894691..ddbe4557f 100644
--- a/test/pleroma/web/mastodon_api/views/notification_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/notification_view_test.exs
@@ -190,7 +190,47 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
emoji: "☕",
account: AccountView.render("show.json", %{user: other_user, for: user}),
status: StatusView.render("show.json", %{activity: activity, for: user}),
- created_at: Utils.to_masto_date(notification.inserted_at)
+ created_at: Utils.to_masto_date(notification.inserted_at),
+ emoji_url: nil
+ }
+
+ test_notifications_rendering([notification], user, [expected])
+ end
+
+ test "EmojiReact custom emoji notification" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ note =
+ insert(:note,
+ user: user,
+ data: %{
+ "reactions" => [
+ ["👍", [user.ap_id], nil],
+ ["dinosaur", [user.ap_id], "http://localhost:4001/emoji/dino walking.gif"]
+ ]
+ }
+ )
+
+ activity = insert(:note_activity, note: note, user: user)
+
+ {:ok, _activity} = CommonAPI.react_with_emoji(activity.id, other_user, "dinosaur")
+
+ activity = Repo.get(Activity, activity.id)
+
+ [notification] = Notification.for_user(user)
+
+ assert notification
+
+ expected = %{
+ id: to_string(notification.id),
+ pleroma: %{is_seen: false, is_muted: false},
+ type: "pleroma:emoji_reaction",
+ emoji: ":dinosaur:",
+ account: AccountView.render("show.json", %{user: other_user, for: user}),
+ status: StatusView.render("show.json", %{activity: activity, for: user}),
+ created_at: Utils.to_masto_date(notification.inserted_at),
+ emoji_url: "http://localhost:4001/emoji/dino walking.gif"
}
test_notifications_rendering([notification], user, [expected])
diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs
index f76b115b7..b93335190 100644
--- a/test/pleroma/web/mastodon_api/views/status_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs
@@ -35,16 +35,26 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
{:ok, activity} = CommonAPI.post(user, %{status: "dae cofe??"})
{:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "☕")
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, ":dinosaur:")
{:ok, _} = CommonAPI.react_with_emoji(activity.id, third_user, "🍵")
{:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, ":dinosaur:")
+
activity = Repo.get(Activity, activity.id)
status = StatusView.render("show.json", activity: activity)
assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 2, me: false},
- %{name: "🍵", count: 1, me: false}
+ %{name: "☕", count: 2, me: false, url: nil, account_ids: [other_user.id, user.id]},
+ %{
+ count: 2,
+ me: false,
+ name: "dinosaur",
+ url: "http://localhost:4001/emoji/dino walking.gif",
+ account_ids: [other_user.id, user.id]
+ },
+ %{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
]
status = StatusView.render("show.json", activity: activity, for: user)
@@ -52,8 +62,36 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 2, me: true},
- %{name: "🍵", count: 1, me: false}
+ %{name: "☕", count: 2, me: true, url: nil, account_ids: [other_user.id, user.id]},
+ %{
+ count: 2,
+ me: true,
+ name: "dinosaur",
+ url: "http://localhost:4001/emoji/dino walking.gif",
+ account_ids: [other_user.id, user.id]
+ },
+ %{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
+ ]
+ end
+
+ test "works with legacy-formatted reactions" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ note =
+ insert(:note,
+ user: user,
+ data: %{
+ "reactions" => [["😿", [other_user.ap_id]]]
+ }
+ )
+
+ activity = insert(:note_activity, user: user, note: note)
+
+ status = StatusView.render("show.json", activity: activity, for: user)
+
+ assert status[:pleroma][:emoji_reactions] == [
+ %{name: "😿", count: 1, me: false, url: nil, account_ids: [other_user.id]}
]
end
@@ -66,11 +104,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
|> Object.update_data(%{"reactions" => %{"☕" => [user.ap_id], "x" => 1}})
activity = Activity.get_by_id(activity.id)
-
status = StatusView.render("show.json", activity: activity, for: user)
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 1, me: true}
+ %{name: "☕", count: 1, me: true, url: nil, account_ids: [user.id]}
]
end
@@ -90,7 +127,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
status = StatusView.render("show.json", activity: activity)
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 1, me: false}
+ %{name: "☕", count: 1, me: false, url: nil, account_ids: [other_user.id]}
]
status = StatusView.render("show.json", activity: activity, for: user)
@@ -102,19 +139,25 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
status = StatusView.render("show.json", activity: activity)
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 2, me: false}
+ %{
+ name: "☕",
+ count: 2,
+ me: false,
+ url: nil,
+ account_ids: [third_user.id, other_user.id]
+ }
]
status = StatusView.render("show.json", activity: activity, for: user)
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 1, me: false}
+ %{name: "☕", count: 1, me: false, url: nil, account_ids: [third_user.id]}
]
status = StatusView.render("show.json", activity: activity, for: other_user)
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 1, me: true}
+ %{name: "☕", count: 1, me: true, url: nil, account_ids: [other_user.id]}
]
end
diff --git a/test/pleroma/web/metadata/providers/rel_me_test.exs b/test/pleroma/web/metadata/providers/rel_me_test.exs
index cce4f3607..793669037 100644
--- a/test/pleroma/web/metadata/providers/rel_me_test.exs
+++ b/test/pleroma/web/metadata/providers/rel_me_test.exs
@@ -11,11 +11,24 @@ defmodule Pleroma.Web.Metadata.Providers.RelMeTest do
bio =
~s(<a href="https://some-link.com">https://some-link.com</a> <a rel="me" href="https://another-link.com">https://another-link.com</a> <link href="http://some.com"> <link rel="me" href="http://some3.com">)
- user = insert(:user, %{bio: bio})
+ fields = [
+ %{
+ "name" => "profile",
+ "value" => ~S(<a rel="me" href="http://profile.com">http://profile.com</a>)
+ },
+ %{
+ "name" => "like",
+ "value" => ~S(<a href="http://cofe.io">http://cofe.io</a>)
+ },
+ %{"name" => "foo", "value" => "bar"}
+ ]
+
+ user = insert(:user, %{bio: bio, fields: fields})
assert RelMe.build_tags(%{user: user}) == [
{:link, [rel: "me", href: "http://some3.com"], []},
- {:link, [rel: "me", href: "https://another-link.com"], []}
+ {:link, [rel: "me", href: "https://another-link.com"], []},
+ {:link, [rel: "me", href: "http://profile.com"], []}
]
end
end
diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
index 77c75b560..21e7d4839 100644
--- a/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
@@ -17,23 +17,113 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
user = insert(:user)
other_user = insert(:user)
+ note = insert(:note, user: user, data: %{"reactions" => [["👍", [other_user.ap_id], nil]]})
+ activity = insert(:note_activity, note: note, user: user)
+
+ result =
+ conn
+ |> assign(:user, other_user)
+ |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
+ |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/\u26A0")
+ |> json_response_and_validate_schema(200)
+
+ assert %{"id" => id} = result
+ assert to_string(activity.id) == id
+
+ assert result["pleroma"]["emoji_reactions"] == [
+ %{
+ "name" => "👍",
+ "count" => 1,
+ "me" => true,
+ "url" => nil,
+ "account_ids" => [other_user.id]
+ },
+ %{
+ "name" => "\u26A0\uFE0F",
+ "count" => 1,
+ "me" => true,
+ "url" => nil,
+ "account_ids" => [other_user.id]
+ }
+ ]
+
{:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
+ ObanHelpers.perform_all()
+
+ # Reacting with a custom emoji
result =
conn
|> assign(:user, other_user)
|> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
- |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕")
+ |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/:dinosaur:")
|> json_response_and_validate_schema(200)
- # We return the status, but this our implementation detail.
assert %{"id" => id} = result
assert to_string(activity.id) == id
assert result["pleroma"]["emoji_reactions"] == [
- %{"name" => "☕", "count" => 1, "me" => true}
+ %{
+ "name" => "dinosaur",
+ "count" => 1,
+ "me" => true,
+ "url" => "http://localhost:4001/emoji/dino walking.gif",
+ "account_ids" => [other_user.id]
+ }
+ ]
+
+ # Reacting with a remote emoji
+ note =
+ insert(:note,
+ user: user,
+ data: %{
+ "reactions" => [
+ ["👍", [other_user.ap_id], nil],
+ ["wow", [other_user.ap_id], "https://remote/emoji/wow"]
+ ]
+ }
+ )
+
+ activity = insert(:note_activity, note: note, user: user)
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:statuses"]))
+ |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/:wow@remote:")
+ |> json_response(200)
+
+ assert result["pleroma"]["emoji_reactions"] == [
+ %{
+ "account_ids" => [other_user.id],
+ "count" => 1,
+ "me" => false,
+ "name" => "👍",
+ "url" => nil
+ },
+ %{
+ "name" => "wow@remote",
+ "count" => 2,
+ "me" => true,
+ "url" => "https://remote/emoji/wow",
+ "account_ids" => [user.id, other_user.id]
+ }
]
+ # Reacting with a remote custom emoji that hasn't been reacted with yet
+ note =
+ insert(:note,
+ user: user
+ )
+
+ activity = insert(:note_activity, note: note, user: user)
+
+ assert conn
+ |> assign(:user, user)
+ |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:statuses"]))
+ |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/:wow@remote:")
+ |> json_response(400)
+
# Reacting with a non-emoji
assert conn
|> assign(:user, other_user)
@@ -46,8 +136,21 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
+ note =
+ insert(:note,
+ user: user,
+ data: %{"reactions" => [["wow", [user.ap_id], "https://remote/emoji/wow"]]}
+ )
+
+ activity = insert(:note_activity, note: note, user: user)
+
+ ObanHelpers.perform_all()
+
{:ok, _reaction_activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
+ {:ok, _reaction_activity} = CommonAPI.react_with_emoji(activity.id, other_user, ":dinosaur:")
+
+ {:ok, _reaction_activity} =
+ CommonAPI.react_with_emoji(activity.id, other_user, ":wow@remote:")
ObanHelpers.perform_all()
@@ -60,11 +163,47 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
assert %{"id" => id} = json_response_and_validate_schema(result, 200)
assert to_string(activity.id) == id
+ # Remove custom emoji
+
+ result =
+ conn
+ |> assign(:user, other_user)
+ |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
+ |> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/:dinosaur:")
+
+ assert %{"id" => id} = json_response_and_validate_schema(result, 200)
+ assert to_string(activity.id) == id
+
ObanHelpers.perform_all()
object = Object.get_by_ap_id(activity.data["object"])
- assert object.data["reaction_count"] == 0
+ assert object.data["reaction_count"] == 2
+
+ # Remove custom remote emoji
+ result =
+ conn
+ |> assign(:user, other_user)
+ |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
+ |> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/:wow@remote:")
+ |> json_response(200)
+
+ assert result["pleroma"]["emoji_reactions"] == [
+ %{
+ "name" => "wow@remote",
+ "count" => 1,
+ "me" => false,
+ "url" => "https://remote/emoji/wow",
+ "account_ids" => [user.id]
+ }
+ ]
+
+ # Remove custom remote emoji that hasn't been reacted with yet
+ assert conn
+ |> assign(:user, other_user)
+ |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
+ |> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/:zoop@remote:")
+ |> json_response(400)
end
test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do
@@ -106,6 +245,38 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
result
end
+ test "GET /api/v1/pleroma/statuses/:id/reactions with legacy format", %{conn: conn} do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ note =
+ insert(:note,
+ user: user,
+ data: %{
+ "reactions" => [["😿", [other_user.ap_id]]]
+ }
+ )
+
+ activity = insert(:note_activity, user: user, note: note)
+
+ result =
+ conn
+ |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions")
+ |> json_response_and_validate_schema(200)
+
+ other_user_id = other_user.id
+
+ assert [
+ %{
+ "name" => "😿",
+ "count" => 1,
+ "me" => false,
+ "url" => nil,
+ "accounts" => [%{"id" => ^other_user_id}]
+ }
+ ] = result
+ end
+
test "GET /api/v1/pleroma/statuses/:id/reactions?with_muted=true", %{conn: conn} do
user = insert(:user)
user2 = insert(:user)
@@ -181,7 +352,15 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
{:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
{:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
- assert [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] =
+ assert [
+ %{
+ "name" => "🎅",
+ "count" => 1,
+ "accounts" => [represented_user],
+ "me" => false,
+ "url" => nil
+ }
+ ] =
conn
|> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅")
|> json_response_and_validate_schema(200)
diff --git a/test/pleroma/web/plugs/uploaded_media_plug_test.exs b/test/pleroma/web/plugs/uploaded_media_plug_test.exs
index ec46b0537..8323ff6ab 100644
--- a/test/pleroma/web/plugs/uploaded_media_plug_test.exs
+++ b/test/pleroma/web/plugs/uploaded_media_plug_test.exs
@@ -33,11 +33,11 @@ defmodule Pleroma.Web.Plugs.UploadedMediaPlugTest do
test "sends Content-Disposition header when name param is set", %{
attachment_url: attachment_url
} do
- conn = get(build_conn(), attachment_url <> "?name=\"cofe\".gif")
+ conn = get(build_conn(), attachment_url <> ~s[?name="cofe".gif])
assert Enum.any?(
conn.resp_headers,
- &(&1 == {"content-disposition", "filename=\"\\\"cofe\\\".gif\""})
+ &(&1 == {"content-disposition", ~s[inline; filename="\\"cofe\\".gif"]})
)
end
end
diff --git a/test/test_helper.exs b/test/test_helper.exs
index 60a61484f..7727cffbc 100644
--- a/test/test_helper.exs
+++ b/test/test_helper.exs
@@ -2,6 +2,8 @@
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
+Code.put_compiler_option(:warnings_as_errors, true)
+
os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: []
ExUnit.start(exclude: [:federated, :erratic] ++ os_exclude)
diff --git a/tools/check-changelog b/tools/check-changelog
new file mode 100644
index 000000000..60692033f
--- /dev/null
+++ b/tools/check-changelog
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+echo "looking for change log"
+
+git remote add upstream https://git.pleroma.social/pleroma/pleroma.git
+git fetch upstream ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}:refs/remotes/upstream/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME
+
+git diff --raw --no-renames upstream/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME HEAD -- changelog.d | \
+ grep ' A\t' | grep '\.\(skip\|add\|remove\|fix\|security\)$'
+ret=$?
+
+if [ $ret -eq 0 ]; then
+ echo "found a changelog entry"
+ exit 0
+else
+ echo "changelog entry not found"
+ exit 1
+fi