forked from AkkomaGang/akkoma
Merge remote-tracking branch 'pleroma/develop' into manifest
This commit is contained in:
commit
720198d569
3830 changed files with 4026 additions and 11356 deletions
|
@ -134,6 +134,7 @@ unit-testing-rum:
|
||||||
- mix test --preload-modules
|
- mix test --preload-modules
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
|
image: elixir:1.12
|
||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
changes:
|
changes:
|
||||||
|
@ -243,7 +244,7 @@ stop_review_app:
|
||||||
|
|
||||||
amd64:
|
amd64:
|
||||||
stage: release
|
stage: release
|
||||||
image: elixir:1.10.3
|
image: elixir:1.10.4
|
||||||
only: &release-only
|
only: &release-only
|
||||||
- stable@pleroma/pleroma
|
- stable@pleroma/pleroma
|
||||||
- develop@pleroma/pleroma
|
- develop@pleroma/pleroma
|
||||||
|
@ -281,7 +282,7 @@ amd64-musl:
|
||||||
stage: release
|
stage: release
|
||||||
artifacts: *release-artifacts
|
artifacts: *release-artifacts
|
||||||
only: *release-only
|
only: *release-only
|
||||||
image: elixir:1.10.3-alpine
|
image: elixir:1.10.4-alpine
|
||||||
cache: *release-cache
|
cache: *release-cache
|
||||||
variables: *release-variables
|
variables: *release-variables
|
||||||
before_script: &before-release-musl
|
before_script: &before-release-musl
|
||||||
|
@ -297,7 +298,7 @@ arm:
|
||||||
only: *release-only
|
only: *release-only
|
||||||
tags:
|
tags:
|
||||||
- arm32-specified
|
- arm32-specified
|
||||||
image: arm32v7/elixir:1.10.3
|
image: arm32v7/elixir:1.10.4
|
||||||
cache: *release-cache
|
cache: *release-cache
|
||||||
variables: *release-variables
|
variables: *release-variables
|
||||||
before_script: *before-release
|
before_script: *before-release
|
||||||
|
@ -309,7 +310,7 @@ arm-musl:
|
||||||
only: *release-only
|
only: *release-only
|
||||||
tags:
|
tags:
|
||||||
- arm32-specified
|
- arm32-specified
|
||||||
image: arm32v7/elixir:1.10.3-alpine
|
image: arm32v7/elixir:1.10.4-alpine
|
||||||
cache: *release-cache
|
cache: *release-cache
|
||||||
variables: *release-variables
|
variables: *release-variables
|
||||||
before_script: *before-release-musl
|
before_script: *before-release-musl
|
||||||
|
@ -321,7 +322,7 @@ arm64:
|
||||||
only: *release-only
|
only: *release-only
|
||||||
tags:
|
tags:
|
||||||
- arm
|
- arm
|
||||||
image: arm64v8/elixir:1.10.3
|
image: arm64v8/elixir:1.10.4
|
||||||
cache: *release-cache
|
cache: *release-cache
|
||||||
variables: *release-variables
|
variables: *release-variables
|
||||||
before_script: *before-release
|
before_script: *before-release
|
||||||
|
@ -333,7 +334,7 @@ arm64-musl:
|
||||||
only: *release-only
|
only: *release-only
|
||||||
tags:
|
tags:
|
||||||
- arm
|
- arm
|
||||||
image: arm64v8/elixir:1.10.3-alpine
|
image: arm64v8/elixir:1.10.4-alpine
|
||||||
cache: *release-cache
|
cache: *release-cache
|
||||||
variables: *release-variables
|
variables: *release-variables
|
||||||
before_script: *before-release-musl
|
before_script: *before-release-musl
|
||||||
|
@ -351,8 +352,8 @@ docker:
|
||||||
IMAGE_TAG_SLUG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
|
IMAGE_TAG_SLUG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
|
||||||
IMAGE_TAG_LATEST: $CI_REGISTRY_IMAGE:latest
|
IMAGE_TAG_LATEST: $CI_REGISTRY_IMAGE:latest
|
||||||
IMAGE_TAG_LATEST_STABLE: $CI_REGISTRY_IMAGE:latest-stable
|
IMAGE_TAG_LATEST_STABLE: $CI_REGISTRY_IMAGE:latest-stable
|
||||||
DOCKER_BUILDX_URL: https://github.com/docker/buildx/releases/download/v0.4.1/buildx-v0.4.1.linux-amd64
|
DOCKER_BUILDX_URL: https://github.com/docker/buildx/releases/download/v0.6.3/buildx-v0.6.3.linux-amd64
|
||||||
DOCKER_BUILDX_HASH: 71a7d01439aa8c165a25b59c44d3f016fddbd98b
|
DOCKER_BUILDX_HASH: 980e6b9655f971991fbbb5fd6cd19f1672386195
|
||||||
before_script: &before-docker
|
before_script: &before-docker
|
||||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
- docker pull $IMAGE_TAG_SLUG || true
|
- docker pull $IMAGE_TAG_SLUG || true
|
||||||
|
|
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -6,11 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- MastoFE
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
- Allow users to remove their emails if instance does not need email to register
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
@ -39,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- **Breaking:** Configuration: `:chat, enabled` moved to `:shout, enabled` and `:instance, chat_limit` moved to `:shout, limit`
|
- **Breaking:** Configuration: `:chat, enabled` moved to `:shout, enabled` and `:instance, chat_limit` moved to `:shout, limit`
|
||||||
|
- **Breaking** Entries for simple_policy, transparency_exclusions and quarantined_instances now list both the instance and a reason.
|
||||||
- Support for Erlang/OTP 24
|
- Support for Erlang/OTP 24
|
||||||
- The `application` metadata returned with statuses is no longer hardcoded. Apps that want to display these details will now have valid data for new posts after this change.
|
- The `application` metadata returned with statuses is no longer hardcoded. Apps that want to display these details will now have valid data for new posts after this change.
|
||||||
- HTTPSecurityPlug now sends a response header to opt out of Google's FLoC (Federated Learning of Cohorts) targeted advertising.
|
- HTTPSecurityPlug now sends a response header to opt out of Google's FLoC (Federated Learning of Cohorts) targeted advertising.
|
||||||
|
@ -52,8 +59,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- MRF (`FollowBotPolicy`): New MRF Policy which makes a designated local Bot account attempt to follow all users in public Notes received by your instance. Users who require approving follower requests or have #nobot in their profile are excluded.
|
- MRF (`FollowBotPolicy`): New MRF Policy which makes a designated local Bot account attempt to follow all users in public Notes received by your instance. Users who require approving follower requests or have #nobot in their profile are excluded.
|
||||||
- Return OAuth token `id` (primary key) in POST `/oauth/token`.
|
- Return OAuth token `id` (primary key) in POST `/oauth/token`.
|
||||||
- AdminAPI: return `created_at` date with users.
|
- AdminAPI: return `created_at` date with users.
|
||||||
|
- AdminAPI: add DELETE `/api/v1/pleroma/admin/instances/:instance` to delete all content from a remote instance.
|
||||||
- `AnalyzeMetadata` upload filter for extracting image/video attachment dimensions and generating blurhashes for images. Blurhashes for videos are not generated at this time.
|
- `AnalyzeMetadata` upload filter for extracting image/video attachment dimensions and generating blurhashes for images. Blurhashes for videos are not generated at this time.
|
||||||
- Attachment dimensions and blurhashes are federated when available.
|
- Attachment dimensions and blurhashes are federated when available.
|
||||||
|
- Mastodon API: support `poll` notification.
|
||||||
- Pinned posts federation
|
- Pinned posts federation
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
@ -61,6 +70,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Checking activated Upload Filters for required commands.
|
- Checking activated Upload Filters for required commands.
|
||||||
- Remote users can no longer reappear after being deleted.
|
- Remote users can no longer reappear after being deleted.
|
||||||
- Deactivated users may now be deleted.
|
- Deactivated users may now be deleted.
|
||||||
|
- Deleting an activity with a lot of likes/boosts no longer causes a database timeout.
|
||||||
- Mix task `pleroma.database prune_objects`
|
- Mix task `pleroma.database prune_objects`
|
||||||
- Fixed rendering of JSON errors on ActivityPub endpoints.
|
- Fixed rendering of JSON errors on ActivityPub endpoints.
|
||||||
- Linkify: Parsing crash with URLs ending in unbalanced closed paren, no path separator, and no query parameters
|
- Linkify: Parsing crash with URLs ending in unbalanced closed paren, no path separator, and no query parameters
|
||||||
|
@ -125,6 +135,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Support pagination of blocks and mutes.
|
- Support pagination of blocks and mutes.
|
||||||
- Account backup.
|
- Account backup.
|
||||||
- Configuration: Add `:instance, autofollowing_nicknames` setting to provide a way to make accounts automatically follow new users that register on the local Pleroma instance.
|
- Configuration: Add `:instance, autofollowing_nicknames` setting to provide a way to make accounts automatically follow new users that register on the local Pleroma instance.
|
||||||
|
- `[:activitypub, :blockers_visible]` config to control visibility of blockers.
|
||||||
- Ability to view remote timelines, with ex. `/api/v1/timelines/public?instance=lain.com` and streams `public:remote` and `public:remote:media`.
|
- Ability to view remote timelines, with ex. `/api/v1/timelines/public?instance=lain.com` and streams `public:remote` and `public:remote:media`.
|
||||||
- The site title is now injected as a `title` tag like preloads or metadata.
|
- The site title is now injected as a `title` tag like preloads or metadata.
|
||||||
- Password reset tokens now are not accepted after a certain age.
|
- Password reset tokens now are not accepted after a certain age.
|
||||||
|
|
|
@ -30,7 +30,7 @@ If your platform is not supported, or you just want to be able to edit the sourc
|
||||||
- [OpenBSD (fi)](https://docs-develop.pleroma.social/backend/installation/openbsd_fi/)
|
- [OpenBSD (fi)](https://docs-develop.pleroma.social/backend/installation/openbsd_fi/)
|
||||||
|
|
||||||
### OS/Distro packages
|
### OS/Distro packages
|
||||||
Currently Pleroma is not packaged by any OS/Distros, but if you want to package it for one, we can guide you through the process on our [community channels](#community-channels). If you want to change default options in your Pleroma package, please **discuss it with us first**.
|
Currently Pleroma is packaged for [YunoHost](https://yunohost.org). If you want to package Pleroma for any OS/Distros, we can guide you through the process on our [community channels](#community-channels). If you want to change default options in your Pleroma package, please **discuss it with us first**.
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
While we don’t provide docker files, other people have written very good ones. Take a look at <https://github.com/angristan/docker-pleroma> or <https://glitch.sh/sn0w/pleroma-docker>.
|
While we don’t provide docker files, other people have written very good ones. Take a look at <https://github.com/angristan/docker-pleroma> or <https://glitch.sh/sn0w/pleroma-docker>.
|
||||||
|
|
|
@ -321,9 +321,6 @@
|
||||||
subjectLineBehavior: "email",
|
subjectLineBehavior: "email",
|
||||||
theme: "pleroma-dark",
|
theme: "pleroma-dark",
|
||||||
webPushNotifications: false
|
webPushNotifications: false
|
||||||
},
|
|
||||||
masto_fe: %{
|
|
||||||
showInstanceSpecificPanel: true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config :pleroma, :assets,
|
config :pleroma, :assets,
|
||||||
|
@ -352,6 +349,7 @@
|
||||||
config :pleroma, :activitypub,
|
config :pleroma, :activitypub,
|
||||||
unfollow_blocked: true,
|
unfollow_blocked: true,
|
||||||
outgoing_blocks: true,
|
outgoing_blocks: true,
|
||||||
|
blockers_visible: true,
|
||||||
follow_handshake_timeout: 500,
|
follow_handshake_timeout: 500,
|
||||||
note_replies_output_limit: 5,
|
note_replies_output_limit: 5,
|
||||||
sign_object_fetches: true,
|
sign_object_fetches: true,
|
||||||
|
@ -560,6 +558,7 @@
|
||||||
mailer: 10,
|
mailer: 10,
|
||||||
transmogrifier: 20,
|
transmogrifier: 20,
|
||||||
scheduled_activities: 10,
|
scheduled_activities: 10,
|
||||||
|
poll_notifications: 10,
|
||||||
background: 5,
|
background: 5,
|
||||||
remote_fetcher: 2,
|
remote_fetcher: 2,
|
||||||
attachments_cleanup: 1,
|
attachments_cleanup: 1,
|
||||||
|
|
|
@ -687,12 +687,14 @@
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :quarantined_instances,
|
key: :quarantined_instances,
|
||||||
type: {:list, :string},
|
type: {:list, :tuple},
|
||||||
|
key_placeholder: "instance",
|
||||||
|
value_placeholder: "reason",
|
||||||
description:
|
description:
|
||||||
"List of ActivityPub instances where private (DMs, followers-only) activities will not be sent",
|
"List of ActivityPub instances where private (DMs, followers-only) activities will not be sent and the reason for doing so",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
"quarantined.com",
|
{"quarantined.com", "Reason"},
|
||||||
"*.quarantined.com"
|
{"*.quarantined.com", "Reason"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -1162,7 +1164,7 @@
|
||||||
type: :group,
|
type: :group,
|
||||||
description:
|
description:
|
||||||
"This form can be used to configure a keyword list that keeps the configuration data for any " <>
|
"This form can be used to configure a keyword list that keeps the configuration data for any " <>
|
||||||
"kind of frontend. By default, settings for pleroma_fe and masto_fe are configured. If you want to " <>
|
"kind of frontend. By default, settings for pleroma_fe are configured. If you want to " <>
|
||||||
"add your own configuration your settings all fields must be complete.",
|
"add your own configuration your settings all fields must be complete.",
|
||||||
children: [
|
children: [
|
||||||
%{
|
%{
|
||||||
|
@ -1362,25 +1364,6 @@
|
||||||
suggestions: ["pleroma-dark"]
|
suggestions: ["pleroma-dark"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
%{
|
|
||||||
key: :masto_fe,
|
|
||||||
label: "Masto FE",
|
|
||||||
type: :map,
|
|
||||||
description: "Settings for Masto FE",
|
|
||||||
suggestions: [
|
|
||||||
%{
|
|
||||||
showInstanceSpecificPanel: true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
children: [
|
|
||||||
%{
|
|
||||||
key: :showInstanceSpecificPanel,
|
|
||||||
label: "Show instance specific panel",
|
|
||||||
type: :boolean,
|
|
||||||
description: "Whenether to show the instance's specific panel"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1687,6 +1670,11 @@
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Whether to federate blocks to other instances"
|
description: "Whether to federate blocks to other instances"
|
||||||
},
|
},
|
||||||
|
%{
|
||||||
|
key: :blockers_visible,
|
||||||
|
type: :boolean,
|
||||||
|
description: "Whether a user can see someone who has blocked them"
|
||||||
|
},
|
||||||
%{
|
%{
|
||||||
key: :sign_object_fetches,
|
key: :sign_object_fetches,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
import_config "dev.secret.exs"
|
import_config "dev.secret.exs"
|
||||||
else
|
else
|
||||||
IO.puts(
|
IO.puts(
|
||||||
|
:stderr,
|
||||||
"!!! RUNNING IN LOCALHOST DEV MODE! !!!\nFEDERATION WON'T WORK UNTIL YOU CONFIGURE A dev.secret.exs"
|
"!!! RUNNING IN LOCALHOST DEV MODE! !!!\nFEDERATION WON'T WORK UNTIL YOU CONFIGURE A dev.secret.exs"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,7 +39,7 @@ To add configuration to your config file, you can copy it from the base config.
|
||||||
* `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.
|
* `federation_reachability_timeout_days`: Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.
|
||||||
* `allow_relay`: Permits remote instances to subscribe to all public posts of your instance. This may increase the visibility of your instance.
|
* `allow_relay`: Permits remote instances to subscribe to all public posts of your instance. This may increase the visibility of your instance.
|
||||||
* `public`: Makes the client API in authenticated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. Note that there is a dependent setting restricting or allowing unauthenticated access to specific resources, see `restrict_unauthenticated` for more details.
|
* `public`: Makes the client API in authenticated mode-only except for user-profiles. Useful for disabling the Local Timeline and The Whole Known Network. Note that there is a dependent setting restricting or allowing unauthenticated access to specific resources, see `restrict_unauthenticated` for more details.
|
||||||
* `quarantined_instances`: List of ActivityPub instances where private (DMs, followers-only) activities will not be send.
|
* `quarantined_instances`: ActivityPub instances where private (DMs, followers-only) activities will not be send.
|
||||||
* `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML).
|
* `allowed_post_formats`: MIME-type list of formats allowed to be posted (transformed into HTML).
|
||||||
* `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with
|
* `extended_nickname_format`: Set to `true` to use extended local nicknames format (allows underscores/dashes). This will break federation with
|
||||||
older software for theses nicknames.
|
older software for theses nicknames.
|
||||||
|
@ -135,15 +135,16 @@ To add configuration to your config file, you can copy it from the base config.
|
||||||
Configuring MRF policies is not enough for them to take effect. You have to enable them by specifying their module in `policies` under [:mrf](#mrf) section.
|
Configuring MRF policies is not enough for them to take effect. You have to enable them by specifying their module in `policies` under [:mrf](#mrf) section.
|
||||||
|
|
||||||
#### :mrf_simple
|
#### :mrf_simple
|
||||||
* `media_removal`: List of instances to remove media from.
|
* `media_removal`: List of instances to strip media attachments from and the reason for doing so.
|
||||||
* `media_nsfw`: List of instances to put media as NSFW(sensitive) from.
|
* `media_nsfw`: List of instances to tag all media as NSFW (sensitive) from and the reason for doing so.
|
||||||
* `federated_timeline_removal`: List of instances to remove from Federated (aka The Whole Known Network) Timeline.
|
* `federated_timeline_removal`: List of instances to remove from the Federated Timeline (aka The Whole Known Network) and the reason for doing so.
|
||||||
* `reject`: List of instances to reject any activities from.
|
* `reject`: List of instances to reject activities (except deletes) from and the reason for doing so.
|
||||||
* `accept`: List of instances to accept any activities from.
|
* `accept`: List of instances to only accept activities (except deletes) from and the reason for doing so.
|
||||||
* `followers_only`: List of instances to decrease post visibility to only the followers, including for DM mentions.
|
* `followers_only`: Force posts from the given instances to be visible by followers only and the reason for doing so.
|
||||||
* `report_removal`: List of instances to reject reports from.
|
* `report_removal`: List of instances to reject reports from and the reason for doing so.
|
||||||
* `avatar_removal`: List of instances to strip avatars from.
|
* `avatar_removal`: List of instances to strip avatars from and the reason for doing so.
|
||||||
* `banner_removal`: List of instances to strip banners from.
|
* `banner_removal`: List of instances to strip banners from and the reason for doing so.
|
||||||
|
* `reject_deletes`: List of instances to reject deletions from and the reason for doing so.
|
||||||
|
|
||||||
#### :mrf_subchain
|
#### :mrf_subchain
|
||||||
This policy processes messages through an alternate pipeline when a given message matches certain criteria.
|
This policy processes messages through an alternate pipeline when a given message matches certain criteria.
|
||||||
|
@ -229,6 +230,7 @@ Notes:
|
||||||
### :activitypub
|
### :activitypub
|
||||||
* `unfollow_blocked`: Whether blocks result in people getting unfollowed
|
* `unfollow_blocked`: Whether blocks result in people getting unfollowed
|
||||||
* `outgoing_blocks`: Whether to federate blocks to other instances
|
* `outgoing_blocks`: Whether to federate blocks to other instances
|
||||||
|
* `blockers_visible`: Whether a user can see the posts of users who blocked them
|
||||||
* `deny_follow_blocked`: Whether to disallow following an account that has blocked the user in question
|
* `deny_follow_blocked`: Whether to disallow following an account that has blocked the user in question
|
||||||
* `sign_object_fetches`: Sign object fetches with HTTP signatures
|
* `sign_object_fetches`: Sign object fetches with HTTP signatures
|
||||||
* `authorized_fetch_mode`: Require HTTP signatures for AP fetches
|
* `authorized_fetch_mode`: Require HTTP signatures for AP fetches
|
||||||
|
@ -246,7 +248,7 @@ Notes:
|
||||||
|
|
||||||
### :frontend_configurations
|
### :frontend_configurations
|
||||||
|
|
||||||
This can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for `pleroma_fe` and `masto_fe` are configured. You can find the documentation for `pleroma_fe` configuration into [Pleroma-FE configuration and customization for instance administrators](/frontend/CONFIGURATION/#options).
|
This can be used to configure a keyword list that keeps the configuration data for any kind of frontend. By default, settings for `pleroma_fe` are configured. You can find the documentation for `pleroma_fe` configuration into [Pleroma-FE configuration and customization for instance administrators](/frontend/CONFIGURATION/#options).
|
||||||
|
|
||||||
Frontends can access these settings at `/api/v1/pleroma/frontend_configurations`
|
Frontends can access these settings at `/api/v1/pleroma/frontend_configurations`
|
||||||
|
|
||||||
|
@ -257,10 +259,7 @@ config :pleroma, :frontend_configurations,
|
||||||
pleroma_fe: %{
|
pleroma_fe: %{
|
||||||
theme: "pleroma-dark",
|
theme: "pleroma-dark",
|
||||||
# ... see /priv/static/static/config.json for the available keys.
|
# ... see /priv/static/static/config.json for the available keys.
|
||||||
},
|
}
|
||||||
masto_fe: %{
|
|
||||||
showInstanceSpecificPanel: true
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
These settings **need to be complete**, they will override the defaults.
|
These settings **need to be complete**, they will override the defaults.
|
||||||
|
|
|
@ -55,18 +55,18 @@ Servers should be configured as lists.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
This example will enable `SimplePolicy`, block media from `illegalporn.biz`, mark media as NSFW from `porn.biz` and `porn.business`, reject messages from `spam.com`, remove messages from `spam.university` from the federated timeline and block reports (flags) from `whiny.whiner`:
|
This example will enable `SimplePolicy`, block media from `illegalporn.biz`, mark media as NSFW from `porn.biz` and `porn.business`, reject messages from `spam.com`, remove messages from `spam.university` from the federated timeline and block reports (flags) from `whiny.whiner`. We also give a reason why the moderation was done:
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
config :pleroma, :mrf,
|
config :pleroma, :mrf,
|
||||||
policies: [Pleroma.Web.ActivityPub.MRF.SimplePolicy]
|
policies: [Pleroma.Web.ActivityPub.MRF.SimplePolicy]
|
||||||
|
|
||||||
config :pleroma, :mrf_simple,
|
config :pleroma, :mrf_simple,
|
||||||
media_removal: ["illegalporn.biz"],
|
media_removal: [{"illegalporn.biz", "Media can contain illegal contant"}],
|
||||||
media_nsfw: ["porn.biz", "porn.business"],
|
media_nsfw: [{"porn.biz", "unmarked nsfw media"}, {"porn.business", "A lot of unmarked nsfw media"}],
|
||||||
reject: ["spam.com"],
|
reject: [{"spam.com", "They keep spamming our users"}],
|
||||||
federated_timeline_removal: ["spam.university"],
|
federated_timeline_removal: [{"spam.university", "Annoying low-quality posts who otherwise fill up TWKN"}],
|
||||||
report_removal: ["whiny.whiner"]
|
report_removal: [{"whiny.whiner", "Keep spamming us with irrelevant reports"}]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Use with Care
|
### Use with Care
|
||||||
|
|
|
@ -319,6 +319,22 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `DELETE /api/v1/pleroma/admin/instances/:instance`
|
||||||
|
|
||||||
|
### Delete all users and activities from a remote instance
|
||||||
|
|
||||||
|
Note: this will trigger a job to remove instance content in the background.
|
||||||
|
It may take some time.
|
||||||
|
|
||||||
|
- Params:
|
||||||
|
- `instance`: remote instance host
|
||||||
|
- Response:
|
||||||
|
- The `instance` name as a string
|
||||||
|
|
||||||
|
```json
|
||||||
|
"lain.com"
|
||||||
|
```
|
||||||
|
|
||||||
## `GET /api/v1/pleroma/admin/statuses`
|
## `GET /api/v1/pleroma/admin/statuses`
|
||||||
|
|
||||||
### Retrives all latest statuses
|
### Retrives all latest statuses
|
||||||
|
|
|
@ -16,11 +16,4 @@ Installation instructions can be found in the installation section of these docs
|
||||||
Great! Now you can explore the fediverse! Open the login page for your Pleroma instance (e.g. <https://pleroma.soykaf.com>) and login with your username and password. (If you don't have an account yet, click on Register)
|
Great! Now you can explore the fediverse! Open the login page for your Pleroma instance (e.g. <https://pleroma.soykaf.com>) and login with your username and password. (If you don't have an account yet, click on Register)
|
||||||
|
|
||||||
### Pleroma-FE
|
### Pleroma-FE
|
||||||
The default front-end used by Pleroma is Pleroma-FE. You can find more information on what it is and how to use it in the [Introduction to Pleroma-FE](../frontend).
|
The default front-end used by Pleroma is Pleroma-FE. You can find more information on what it is and how to use it in the [Introduction to Pleroma-FE](../frontend).
|
||||||
|
|
||||||
### Mastodon interface
|
|
||||||
If the Pleroma interface isn't your thing, or you're just trying something new but you want to keep using the familiar Mastodon interface, we got that too!
|
|
||||||
Just add a "/web" after your instance url (e.g. <https://pleroma.soykaf.com/web>) and you'll end on the Mastodon web interface, but with a Pleroma backend! MAGIC!
|
|
||||||
The Mastodon interface is from the Glitch-soc fork. For more information on the Mastodon interface you can check the [Mastodon](https://docs.joinmastodon.org/) and [Glitch-soc](https://glitch-soc.github.io/docs/) documentation.
|
|
||||||
|
|
||||||
Remember, what you see is only the frontend part of Mastodon, the backend is still Pleroma.
|
|
|
@ -9,7 +9,7 @@
|
||||||
* GNU make
|
* GNU make
|
||||||
* CMake
|
* CMake
|
||||||
|
|
||||||
## Optionnal dependencies
|
## Optional dependencies
|
||||||
|
|
||||||
* ImageMagick
|
* ImageMagick
|
||||||
* FFmpeg
|
* FFmpeg
|
||||||
|
|
9
docs/installation/yunohost_en.md
Normal file
9
docs/installation/yunohost_en.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Installing on Yunohost
|
||||||
|
|
||||||
|
[YunoHost](https://yunohost.org) is a server operating system aimed at self-hosting. The YunoHost community maintains a package of Pleroma which allows you to install Pleroma on YunoHost. You can install it via the normal way through the admin web interface, or through the CLI. More information can be found at [the repo of the package](https://github.com/YunoHost-Apps/pleroma_ynh).
|
||||||
|
|
||||||
|
## Questions
|
||||||
|
|
||||||
|
Questions and problems related to the YunoHost parts can be done through the [regular YunoHost channels](https://yunohost.org/en/help).
|
||||||
|
|
||||||
|
For questions about Pleroma, ask in [#pleroma:libera.chat](https://matrix.to/#/#pleroma:libera.chat) via Matrix or **#pleroma** on **libera.chat** via IRC.
|
|
@ -1,48 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
project_id="74"
|
|
||||||
project_branch="rebase/glitch-soc"
|
|
||||||
static_dir="instance/static"
|
|
||||||
# For bundling:
|
|
||||||
# project_branch="pleroma"
|
|
||||||
# static_dir="priv/static"
|
|
||||||
|
|
||||||
if [ ! -d "${static_dir}" ]
|
|
||||||
then
|
|
||||||
echo "Error: ${static_dir} directory is missing, are you sure you are running this script at the root of pleroma’s repository?"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
last_modified="$(curl --fail -s -I 'https://git.pleroma.social/api/v4/projects/'${project_id}'/jobs/artifacts/'${project_branch}'/download?job=build' | grep '^Last-Modified:' | cut -d: -f2-)"
|
|
||||||
|
|
||||||
echo "branch:${project_branch}"
|
|
||||||
echo "Last-Modified:${last_modified}"
|
|
||||||
|
|
||||||
artifact="mastofe.zip"
|
|
||||||
|
|
||||||
if [ "${last_modified}x" = "x" ]
|
|
||||||
then
|
|
||||||
echo "ERROR: Couldn't get the modification date of the latest build archive, maybe it expired, exiting..."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -e mastofe.timestamp ] && [ "$(cat mastofe.timestamp)" = "${last_modified}" ]
|
|
||||||
then
|
|
||||||
echo "MastoFE is up-to-date, exiting..."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
curl --fail -c - "https://git.pleroma.social/api/v4/projects/${project_id}/jobs/artifacts/${project_branch}/download?job=build" -o "${artifact}" || exit
|
|
||||||
|
|
||||||
# TODO: Update the emoji as well
|
|
||||||
rm -fr "${static_dir}/sw.js" "${static_dir}/packs" || exit
|
|
||||||
unzip -q "${artifact}" || exit
|
|
||||||
|
|
||||||
cp public/assets/sw.js "${static_dir}/sw.js" || exit
|
|
||||||
cp -r public/packs "${static_dir}/packs" || exit
|
|
||||||
|
|
||||||
echo "${last_modified}" > mastofe.timestamp
|
|
||||||
rm -fr public
|
|
||||||
rm -i "${artifact}"
|
|
|
@ -286,9 +286,7 @@ defp migrate_from_db(opts) do
|
||||||
file = File.open!(tmp_config_path)
|
file = File.open!(tmp_config_path)
|
||||||
|
|
||||||
shell_info(
|
shell_info(
|
||||||
"Saving database configuration settings to #{tmp_config_path}. Copy it to the #{
|
"Saving database configuration settings to #{tmp_config_path}. Copy it to the #{Path.dirname(config_path)} manually."
|
||||||
Path.dirname(config_path)
|
|
||||||
} manually."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
write_config(file, tmp_config_path, opts)
|
write_config(file, tmp_config_path, opts)
|
||||||
|
|
|
@ -51,9 +51,7 @@ def run(["new", nickname, email | rest]) do
|
||||||
A user will be created with the following information:
|
A user will be created with the following information:
|
||||||
- nickname: #{nickname}
|
- nickname: #{nickname}
|
||||||
- email: #{email}
|
- email: #{email}
|
||||||
- password: #{
|
- password: #{if(generated_password?, do: "[generated; a reset link will be created]", else: password)}
|
||||||
if(generated_password?, do: "[generated; a reset link will be created]", else: password)
|
|
||||||
}
|
|
||||||
- name: #{name}
|
- name: #{name}
|
||||||
- bio: #{bio}
|
- bio: #{bio}
|
||||||
- moderator: #{if(moderator?, do: "true", else: "false")}
|
- moderator: #{if(moderator?, do: "true", else: "false")}
|
||||||
|
@ -114,15 +112,9 @@ def run(["reset_password", nickname]) do
|
||||||
{:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
|
{:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
|
||||||
shell_info("Generated password reset token for #{user.nickname}")
|
shell_info("Generated password reset token for #{user.nickname}")
|
||||||
|
|
||||||
IO.puts(
|
IO.puts("URL: #{Pleroma.Web.Router.Helpers.reset_password_url(Pleroma.Web.Endpoint,
|
||||||
"URL: #{
|
:reset,
|
||||||
Pleroma.Web.Router.Helpers.reset_password_url(
|
token.token)}")
|
||||||
Pleroma.Web.Endpoint,
|
|
||||||
:reset,
|
|
||||||
token.token
|
|
||||||
)
|
|
||||||
}"
|
|
||||||
)
|
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
shell_error("No local user #{nickname}")
|
shell_error("No local user #{nickname}")
|
||||||
|
@ -321,9 +313,7 @@ def run(["invites"]) do
|
||||||
end
|
end
|
||||||
|
|
||||||
shell_info(
|
shell_info(
|
||||||
"ID: #{invite.id} | Token: #{invite.token} | Token type: #{invite.invite_type} | Used: #{
|
"ID: #{invite.id} | Token: #{invite.token} | Token type: #{invite.invite_type} | Used: #{invite.used}#{expire_info}#{using_info}"
|
||||||
invite.used
|
|
||||||
}#{expire_info}#{using_info}"
|
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@ -424,9 +414,7 @@ def run(["list"]) do
|
||||||
users
|
users
|
||||||
|> Enum.each(fn user ->
|
|> Enum.each(fn user ->
|
||||||
shell_info(
|
shell_info(
|
||||||
"#{user.nickname} moderator: #{user.is_moderator}, admin: #{user.is_admin}, locked: #{
|
"#{user.nickname} moderator: #{user.is_moderator}, admin: #{user.is_admin}, locked: #{user.is_locked}, is_active: #{user.is_active}"
|
||||||
user.is_locked
|
|
||||||
}, is_active: #{user.is_active}"
|
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -302,7 +302,7 @@ def delete_all_by_object_ap_id(id) when is_binary(id) do
|
||||||
|> Queries.by_object_id()
|
|> Queries.by_object_id()
|
||||||
|> Queries.exclude_type("Delete")
|
|> Queries.exclude_type("Delete")
|
||||||
|> select([u], u)
|
|> select([u], u)
|
||||||
|> Repo.delete_all()
|
|> Repo.delete_all(timeout: :infinity)
|
||||||
|> elem(1)
|
|> elem(1)
|
||||||
|> Enum.find(fn
|
|> Enum.find(fn
|
||||||
%{data: %{"type" => "Create", "object" => ap_id}} when is_binary(ap_id) -> ap_id == id
|
%{data: %{"type" => "Create", "object" => ap_id}} when is_binary(ap_id) -> ap_id == id
|
||||||
|
|
|
@ -19,9 +19,7 @@ def on_shell(username, _pubkey, _ip, _port) do
|
||||||
def on_connect(username, ip, port, method) do
|
def on_connect(username, ip, port, method) do
|
||||||
Logger.debug(fn ->
|
Logger.debug(fn ->
|
||||||
"""
|
"""
|
||||||
Incoming SSH shell #{inspect(self())} requested for #{username} from #{inspect(ip)}:#{
|
Incoming SSH shell #{inspect(self())} requested for #{username} from #{inspect(ip)}:#{inspect(port)} using #{inspect(method)}
|
||||||
inspect(port)
|
|
||||||
} using #{inspect(method)}
|
|
||||||
"""
|
"""
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,6 +20,140 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
||||||
"\n* `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`"}
|
"\n* `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`"}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def check_simple_policy_tuples do
|
||||||
|
has_strings =
|
||||||
|
Config.get([:mrf_simple])
|
||||||
|
|> Enum.any?(fn {_, v} -> Enum.any?(v, &is_binary/1) end)
|
||||||
|
|
||||||
|
if has_strings do
|
||||||
|
Logger.warn("""
|
||||||
|
!!!DEPRECATION WARNING!!!
|
||||||
|
Your config is using strings in the SimplePolicy configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, :mrf_simple,
|
||||||
|
media_removal: ["instance.tld"],
|
||||||
|
media_nsfw: ["instance.tld"],
|
||||||
|
federated_timeline_removal: ["instance.tld"],
|
||||||
|
report_removal: ["instance.tld"],
|
||||||
|
reject: ["instance.tld"],
|
||||||
|
followers_only: ["instance.tld"],
|
||||||
|
accept: ["instance.tld"],
|
||||||
|
avatar_removal: ["instance.tld"],
|
||||||
|
banner_removal: ["instance.tld"],
|
||||||
|
reject_deletes: ["instance.tld"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Is now
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, :mrf_simple,
|
||||||
|
media_removal: [{"instance.tld", "Reason for media removal"}],
|
||||||
|
media_nsfw: [{"instance.tld", "Reason for media nsfw"}],
|
||||||
|
federated_timeline_removal: [{"instance.tld", "Reason for federated timeline removal"}],
|
||||||
|
report_removal: [{"instance.tld", "Reason for report removal"}],
|
||||||
|
reject: [{"instance.tld", "Reason for reject"}],
|
||||||
|
followers_only: [{"instance.tld", "Reason for followers only"}],
|
||||||
|
accept: [{"instance.tld", "Reason for accept"}],
|
||||||
|
avatar_removal: [{"instance.tld", "Reason for avatar removal"}],
|
||||||
|
banner_removal: [{"instance.tld", "Reason for banner removal"}],
|
||||||
|
reject_deletes: [{"instance.tld", "Reason for reject deletes"}]
|
||||||
|
```
|
||||||
|
""")
|
||||||
|
|
||||||
|
new_config =
|
||||||
|
Config.get([:mrf_simple])
|
||||||
|
|> Enum.map(fn {k, v} ->
|
||||||
|
{k,
|
||||||
|
Enum.map(v, fn
|
||||||
|
{instance, reason} -> {instance, reason}
|
||||||
|
instance -> {instance, ""}
|
||||||
|
end)}
|
||||||
|
end)
|
||||||
|
|
||||||
|
Config.put([:mrf_simple], new_config)
|
||||||
|
|
||||||
|
:error
|
||||||
|
else
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_quarantined_instances_tuples do
|
||||||
|
has_strings = Config.get([:instance, :quarantined_instances]) |> Enum.any?(&is_binary/1)
|
||||||
|
|
||||||
|
if has_strings do
|
||||||
|
Logger.warn("""
|
||||||
|
!!!DEPRECATION WARNING!!!
|
||||||
|
Your config is using strings in the quarantined_instances configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, :instance,
|
||||||
|
quarantined_instances: ["instance.tld"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Is now
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, :instance,
|
||||||
|
quarantined_instances: [{"instance.tld", "Reason for quarantine"}]
|
||||||
|
```
|
||||||
|
""")
|
||||||
|
|
||||||
|
new_config =
|
||||||
|
Config.get([:instance, :quarantined_instances])
|
||||||
|
|> Enum.map(fn
|
||||||
|
{instance, reason} -> {instance, reason}
|
||||||
|
instance -> {instance, ""}
|
||||||
|
end)
|
||||||
|
|
||||||
|
Config.put([:instance, :quarantined_instances], new_config)
|
||||||
|
|
||||||
|
:error
|
||||||
|
else
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_transparency_exclusions_tuples do
|
||||||
|
has_strings = Config.get([:mrf, :transparency_exclusions]) |> Enum.any?(&is_binary/1)
|
||||||
|
|
||||||
|
if has_strings do
|
||||||
|
Logger.warn("""
|
||||||
|
!!!DEPRECATION WARNING!!!
|
||||||
|
Your config is using strings in the transparency_exclusions configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, :mrf,
|
||||||
|
transparency_exclusions: ["instance.tld"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Is now
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, :mrf,
|
||||||
|
transparency_exclusions: [{"instance.tld", "Reason to exlude transparency"}]
|
||||||
|
```
|
||||||
|
""")
|
||||||
|
|
||||||
|
new_config =
|
||||||
|
Config.get([:mrf, :transparency_exclusions])
|
||||||
|
|> Enum.map(fn
|
||||||
|
{instance, reason} -> {instance, reason}
|
||||||
|
instance -> {instance, ""}
|
||||||
|
end)
|
||||||
|
|
||||||
|
Config.put([:mrf, :transparency_exclusions], new_config)
|
||||||
|
|
||||||
|
:error
|
||||||
|
else
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def check_hellthread_threshold do
|
def check_hellthread_threshold do
|
||||||
if Config.get([:mrf_hellthread, :threshold]) do
|
if Config.get([:mrf_hellthread, :threshold]) do
|
||||||
Logger.warn("""
|
Logger.warn("""
|
||||||
|
@ -34,20 +168,24 @@ def check_hellthread_threshold do
|
||||||
end
|
end
|
||||||
|
|
||||||
def warn do
|
def warn do
|
||||||
with :ok <- check_hellthread_threshold(),
|
[
|
||||||
:ok <- check_old_mrf_config(),
|
check_hellthread_threshold(),
|
||||||
:ok <- check_media_proxy_whitelist_config(),
|
check_old_mrf_config(),
|
||||||
:ok <- check_welcome_message_config(),
|
check_media_proxy_whitelist_config(),
|
||||||
:ok <- check_gun_pool_options(),
|
check_welcome_message_config(),
|
||||||
:ok <- check_activity_expiration_config(),
|
check_gun_pool_options(),
|
||||||
:ok <- check_remote_ip_plug_name(),
|
check_activity_expiration_config(),
|
||||||
:ok <- check_uploders_s3_public_endpoint(),
|
check_remote_ip_plug_name(),
|
||||||
:ok <- check_old_chat_shoutbox() do
|
check_uploders_s3_public_endpoint(),
|
||||||
:ok
|
check_old_chat_shoutbox(),
|
||||||
else
|
check_quarantined_instances_tuples(),
|
||||||
_ ->
|
check_transparency_exclusions_tuples(),
|
||||||
:error
|
check_simple_policy_tuples()
|
||||||
end
|
]
|
||||||
|
|> Enum.reduce(:ok, fn
|
||||||
|
:ok, :ok -> :ok
|
||||||
|
_, _ -> :error
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_welcome_message_config do
|
def check_welcome_message_config do
|
||||||
|
|
|
@ -21,9 +21,7 @@ def warn do
|
||||||
"""
|
"""
|
||||||
!!!OBAN CONFIG WARNING!!!
|
!!!OBAN CONFIG WARNING!!!
|
||||||
You are using old workers in Oban crontab settings, which were removed.
|
You are using old workers in Oban crontab settings, which were removed.
|
||||||
Please, remove setting from crontab in your config file (prod.secret.exs): #{
|
Please, remove setting from crontab in your config file (prod.secret.exs): #{inspect(setting)}
|
||||||
inspect(setting)
|
|
||||||
}
|
|
||||||
"""
|
"""
|
||||||
|> Logger.warn()
|
|> Logger.warn()
|
||||||
|
|
||||||
|
|
|
@ -148,9 +148,7 @@ defp update({group, key, value, merged}) do
|
||||||
rescue
|
rescue
|
||||||
error ->
|
error ->
|
||||||
error_msg =
|
error_msg =
|
||||||
"updating env causes error, group: #{inspect(group)}, key: #{inspect(key)}, value: #{
|
"updating env causes error, group: #{inspect(group)}, key: #{inspect(key)}, value: #{inspect(value)} error: #{inspect(error)}"
|
||||||
inspect(value)
|
|
||||||
} error: #{inspect(error)}"
|
|
||||||
|
|
||||||
Logger.warn(error_msg)
|
Logger.warn(error_msg)
|
||||||
|
|
||||||
|
|
|
@ -60,9 +60,7 @@ def load do
|
||||||
|
|
||||||
if not Enum.empty?(files) do
|
if not Enum.empty?(files) do
|
||||||
Logger.warn(
|
Logger.warn(
|
||||||
"Found files in the emoji folder. These will be ignored, please move them to a subdirectory\nFound files: #{
|
"Found files in the emoji folder. These will be ignored, please move them to a subdirectory\nFound files: #{Enum.join(files, ", ")}"
|
||||||
Enum.join(files, ", ")
|
|
||||||
}"
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -122,9 +120,7 @@ defp load_pack(pack_dir, emoji_groups) do
|
||||||
extensions = Config.get([:emoji, :pack_extensions])
|
extensions = Config.get([:emoji, :pack_extensions])
|
||||||
|
|
||||||
Logger.info(
|
Logger.info(
|
||||||
"No emoji.txt found for pack \"#{pack_name}\", assuming all #{
|
"No emoji.txt found for pack \"#{pack_name}\", assuming all #{Enum.join(extensions, ", ")} files are emoji"
|
||||||
Enum.join(extensions, ", ")
|
|
||||||
} files are emoji"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
make_shortcode_to_file_map(pack_dir, extensions)
|
make_shortcode_to_file_map(pack_dir, extensions)
|
||||||
|
|
|
@ -57,9 +57,7 @@ defp do_open(uri, %{proxy: {proxy_host, proxy_port}} = opts) do
|
||||||
else
|
else
|
||||||
error ->
|
error ->
|
||||||
Logger.warn(
|
Logger.warn(
|
||||||
"Opening proxied connection to #{compose_uri_log(uri)} failed with error #{
|
"Opening proxied connection to #{compose_uri_log(uri)} failed with error #{inspect(error)}"
|
||||||
inspect(error)
|
|
||||||
}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
error
|
error
|
||||||
|
@ -93,9 +91,7 @@ defp do_open(uri, %{proxy: {proxy_type, proxy_host, proxy_port}} = opts) do
|
||||||
else
|
else
|
||||||
error ->
|
error ->
|
||||||
Logger.warn(
|
Logger.warn(
|
||||||
"Opening socks proxied connection to #{compose_uri_log(uri)} failed with error #{
|
"Opening socks proxied connection to #{compose_uri_log(uri)} failed with error #{inspect(error)}"
|
||||||
inspect(error)
|
|
||||||
}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
error
|
error
|
||||||
|
|
|
@ -8,6 +8,8 @@ defmodule Pleroma.Instances.Instance do
|
||||||
alias Pleroma.Instances
|
alias Pleroma.Instances
|
||||||
alias Pleroma.Instances.Instance
|
alias Pleroma.Instances.Instance
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Workers.BackgroundWorker
|
||||||
|
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
|
@ -195,4 +197,24 @@ defp scrape_favicon(%URI{} = instance_uri) do
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Deletes all users from an instance in a background task, thus also deleting
|
||||||
|
all of those users' activities and notifications.
|
||||||
|
"""
|
||||||
|
def delete_users_and_activities(host) when is_binary(host) do
|
||||||
|
BackgroundWorker.enqueue("delete_instance", %{"host" => host})
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform(:delete_instance, host) when is_binary(host) do
|
||||||
|
User.Query.build(%{nickname: "@#{host}"})
|
||||||
|
|> Repo.chunk_stream(100, :batches)
|
||||||
|
|> Stream.each(fn users ->
|
||||||
|
users
|
||||||
|
|> Enum.each(fn user ->
|
||||||
|
User.perform(:delete, user)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|> Stream.run()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.Maintenance do
|
||||||
def vacuum(args) do
|
def vacuum(args) do
|
||||||
case args do
|
case args do
|
||||||
"analyze" ->
|
"analyze" ->
|
||||||
Logger.info("Runnning VACUUM ANALYZE.")
|
Logger.info("Running VACUUM ANALYZE.")
|
||||||
|
|
||||||
Repo.query!(
|
Repo.query!(
|
||||||
"vacuum analyze;",
|
"vacuum analyze;",
|
||||||
|
@ -18,7 +18,7 @@ def vacuum(args) do
|
||||||
)
|
)
|
||||||
|
|
||||||
"full" ->
|
"full" ->
|
||||||
Logger.info("Runnning VACUUM FULL.")
|
Logger.info("Running VACUUM FULL.")
|
||||||
|
|
||||||
Logger.warn(
|
Logger.warn(
|
||||||
"Re-packing your entire database may take a while and will consume extra disk space during the process."
|
"Re-packing your entire database may take a while and will consume extra disk space during the process."
|
||||||
|
|
|
@ -481,9 +481,7 @@ def get_log_entry_message(%ModerationLog{
|
||||||
"visibility" => visibility
|
"visibility" => visibility
|
||||||
}
|
}
|
||||||
}) do
|
}) do
|
||||||
"@#{actor_nickname} updated status ##{subject_id}, set sensitive: '#{sensitive}', visibility: '#{
|
"@#{actor_nickname} updated status ##{subject_id}, set sensitive: '#{sensitive}', visibility: '#{visibility}'"
|
||||||
visibility
|
|
||||||
}'"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_log_entry_message(%ModerationLog{
|
def get_log_entry_message(%ModerationLog{
|
||||||
|
@ -523,9 +521,7 @@ def get_log_entry_message(%ModerationLog{
|
||||||
"subject" => subjects
|
"subject" => subjects
|
||||||
}
|
}
|
||||||
}) do
|
}) do
|
||||||
"@#{actor_nickname} re-sent confirmation email for users: #{
|
"@#{actor_nickname} re-sent confirmation email for users: #{users_to_nicknames_string(subjects)}"
|
||||||
users_to_nicknames_string(subjects)
|
|
||||||
}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_log_entry_message(%ModerationLog{
|
def get_log_entry_message(%ModerationLog{
|
||||||
|
|
|
@ -72,6 +72,7 @@ def unread_notifications_count(%User{id: user_id}) do
|
||||||
pleroma:emoji_reaction
|
pleroma:emoji_reaction
|
||||||
pleroma:report
|
pleroma:report
|
||||||
reblog
|
reblog
|
||||||
|
poll
|
||||||
}
|
}
|
||||||
|
|
||||||
def changeset(%Notification{} = notification, attrs) do
|
def changeset(%Notification{} = notification, attrs) do
|
||||||
|
@ -127,6 +128,7 @@ def for_user_query(user, opts \\ %{}) do
|
||||||
|> where([user_actor: user_actor], user_actor.is_active)
|
|> where([user_actor: user_actor], user_actor.is_active)
|
||||||
|> exclude_notification_muted(user, exclude_notification_muted_opts)
|
|> exclude_notification_muted(user, exclude_notification_muted_opts)
|
||||||
|> exclude_blocked(user, exclude_blocked_opts)
|
|> exclude_blocked(user, exclude_blocked_opts)
|
||||||
|
|> exclude_blockers(user)
|
||||||
|> exclude_filtered(user)
|
|> exclude_filtered(user)
|
||||||
|> exclude_visibility(opts)
|
|> exclude_visibility(opts)
|
||||||
end
|
end
|
||||||
|
@ -140,6 +142,17 @@ defp exclude_blocked(query, user, opts) do
|
||||||
|> FollowingRelationship.keep_following_or_not_domain_blocked(user)
|
|> FollowingRelationship.keep_following_or_not_domain_blocked(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp exclude_blockers(query, user) do
|
||||||
|
if Pleroma.Config.get([:activitypub, :blockers_visible]) == true do
|
||||||
|
query
|
||||||
|
else
|
||||||
|
blocker_ap_ids = User.incoming_relationships_ungrouped_ap_ids(user, [:block])
|
||||||
|
|
||||||
|
query
|
||||||
|
|> where([n, a], a.actor not in ^blocker_ap_ids)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp exclude_notification_muted(query, _, %{@include_muted_option => true}) do
|
defp exclude_notification_muted(query, _, %{@include_muted_option => true}) do
|
||||||
query
|
query
|
||||||
end
|
end
|
||||||
|
@ -379,7 +392,7 @@ defp do_create_notifications(%Activity{} = activity, options) do
|
||||||
notifications =
|
notifications =
|
||||||
Enum.map(potential_receivers, fn user ->
|
Enum.map(potential_receivers, fn user ->
|
||||||
do_send = do_send && user in enabled_receivers
|
do_send = do_send && user in enabled_receivers
|
||||||
create_notification(activity, user, do_send)
|
create_notification(activity, user, do_send: do_send)
|
||||||
end)
|
end)
|
||||||
|> Enum.reject(&is_nil/1)
|
|> Enum.reject(&is_nil/1)
|
||||||
|
|
||||||
|
@ -435,15 +448,18 @@ defp type_from_activity_object(%{data: %{"type" => "Create"}} = activity) do
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO move to sql, too.
|
# TODO move to sql, too.
|
||||||
def create_notification(%Activity{} = activity, %User{} = user, do_send \\ true) do
|
def create_notification(%Activity{} = activity, %User{} = user, opts \\ []) do
|
||||||
unless skip?(activity, user) do
|
do_send = Keyword.get(opts, :do_send, true)
|
||||||
|
type = Keyword.get(opts, :type, type_from_activity(activity))
|
||||||
|
|
||||||
|
unless skip?(activity, user, opts) do
|
||||||
{:ok, %{notification: notification}} =
|
{:ok, %{notification: notification}} =
|
||||||
Multi.new()
|
Multi.new()
|
||||||
|> Multi.insert(:notification, %Notification{
|
|> Multi.insert(:notification, %Notification{
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
activity: activity,
|
activity: activity,
|
||||||
seen: mark_as_read?(activity, user),
|
seen: mark_as_read?(activity, user),
|
||||||
type: type_from_activity(activity)
|
type: type
|
||||||
})
|
})
|
||||||
|> Marker.multi_set_last_read_id(user, "notifications")
|
|> Marker.multi_set_last_read_id(user, "notifications")
|
||||||
|> Repo.transaction()
|
|> Repo.transaction()
|
||||||
|
@ -457,6 +473,28 @@ def create_notification(%Activity{} = activity, %User{} = user, do_send \\ true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_poll_notifications(%Activity{} = activity) do
|
||||||
|
with %Object{data: %{"type" => "Question", "actor" => actor} = data} <-
|
||||||
|
Object.normalize(activity) do
|
||||||
|
voters =
|
||||||
|
case data do
|
||||||
|
%{"voters" => voters} when is_list(voters) -> voters
|
||||||
|
_ -> []
|
||||||
|
end
|
||||||
|
|
||||||
|
notifications =
|
||||||
|
Enum.reduce([actor | voters], [], fn ap_id, acc ->
|
||||||
|
with %User{local: true} = user <- User.get_by_ap_id(ap_id) do
|
||||||
|
[create_notification(activity, user, type: "poll") | acc]
|
||||||
|
else
|
||||||
|
_ -> acc
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
{:ok, notifications}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Returns a tuple with 2 elements:
|
Returns a tuple with 2 elements:
|
||||||
{notification-enabled receivers, currently disabled receivers (blocking / [thread] muting)}
|
{notification-enabled receivers, currently disabled receivers (blocking / [thread] muting)}
|
||||||
|
@ -572,8 +610,10 @@ def exclude_thread_muter_ap_ids(ap_ids, %Activity{} = activity) do
|
||||||
Enum.uniq(ap_ids) -- thread_muter_ap_ids
|
Enum.uniq(ap_ids) -- thread_muter_ap_ids
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec skip?(Activity.t(), User.t()) :: boolean()
|
def skip?(activity, user, opts \\ [])
|
||||||
def skip?(%Activity{} = activity, %User{} = user) do
|
|
||||||
|
@spec skip?(Activity.t(), User.t(), Keyword.t()) :: boolean()
|
||||||
|
def skip?(%Activity{} = activity, %User{} = user, opts) do
|
||||||
[
|
[
|
||||||
:self,
|
:self,
|
||||||
:invisible,
|
:invisible,
|
||||||
|
@ -581,17 +621,21 @@ def skip?(%Activity{} = activity, %User{} = user) do
|
||||||
:recently_followed,
|
:recently_followed,
|
||||||
:filtered
|
:filtered
|
||||||
]
|
]
|
||||||
|> Enum.find(&skip?(&1, activity, user))
|
|> Enum.find(&skip?(&1, activity, user, opts))
|
||||||
end
|
end
|
||||||
|
|
||||||
def skip?(_, _), do: false
|
def skip?(_activity, _user, _opts), do: false
|
||||||
|
|
||||||
@spec skip?(atom(), Activity.t(), User.t()) :: boolean()
|
@spec skip?(atom(), Activity.t(), User.t(), Keyword.t()) :: boolean()
|
||||||
def skip?(:self, %Activity{} = activity, %User{} = user) do
|
def skip?(:self, %Activity{} = activity, %User{} = user, opts) do
|
||||||
activity.data["actor"] == user.ap_id
|
cond do
|
||||||
|
opts[:type] == "poll" -> false
|
||||||
|
activity.data["actor"] == user.ap_id -> true
|
||||||
|
true -> false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def skip?(:invisible, %Activity{} = activity, _) do
|
def skip?(:invisible, %Activity{} = activity, _user, _opts) do
|
||||||
actor = activity.data["actor"]
|
actor = activity.data["actor"]
|
||||||
user = User.get_cached_by_ap_id(actor)
|
user = User.get_cached_by_ap_id(actor)
|
||||||
User.invisible?(user)
|
User.invisible?(user)
|
||||||
|
@ -600,15 +644,27 @@ def skip?(:invisible, %Activity{} = activity, _) do
|
||||||
def skip?(
|
def skip?(
|
||||||
:block_from_strangers,
|
:block_from_strangers,
|
||||||
%Activity{} = activity,
|
%Activity{} = activity,
|
||||||
%User{notification_settings: %{block_from_strangers: true}} = user
|
%User{notification_settings: %{block_from_strangers: true}} = user,
|
||||||
|
opts
|
||||||
) do
|
) do
|
||||||
actor = activity.data["actor"]
|
actor = activity.data["actor"]
|
||||||
follower = User.get_cached_by_ap_id(actor)
|
follower = User.get_cached_by_ap_id(actor)
|
||||||
!User.following?(follower, user)
|
|
||||||
|
cond do
|
||||||
|
opts[:type] == "poll" -> false
|
||||||
|
user.ap_id == actor -> false
|
||||||
|
!User.following?(follower, user) -> true
|
||||||
|
true -> false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# To do: consider defining recency in hours and checking FollowingRelationship with a single SQL
|
# To do: consider defining recency in hours and checking FollowingRelationship with a single SQL
|
||||||
def skip?(:recently_followed, %Activity{data: %{"type" => "Follow"}} = activity, %User{} = user) do
|
def skip?(
|
||||||
|
:recently_followed,
|
||||||
|
%Activity{data: %{"type" => "Follow"}} = activity,
|
||||||
|
%User{} = user,
|
||||||
|
_opts
|
||||||
|
) do
|
||||||
actor = activity.data["actor"]
|
actor = activity.data["actor"]
|
||||||
|
|
||||||
Notification.for_user(user)
|
Notification.for_user(user)
|
||||||
|
@ -618,9 +674,10 @@ def skip?(:recently_followed, %Activity{data: %{"type" => "Follow"}} = activity,
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def skip?(:filtered, %{data: %{"type" => type}}, _) when type in ["Follow", "Move"], do: false
|
def skip?(:filtered, %{data: %{"type" => type}}, _user, _opts) when type in ["Follow", "Move"],
|
||||||
|
do: false
|
||||||
|
|
||||||
def skip?(:filtered, activity, user) do
|
def skip?(:filtered, activity, user, _opts) do
|
||||||
object = Object.normalize(activity, fetch: false)
|
object = Object.normalize(activity, fetch: false)
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
|
@ -638,7 +695,7 @@ def skip?(:filtered, activity, user) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def skip?(_, _, _), do: false
|
def skip?(_type, _activity, _user, _opts), do: false
|
||||||
|
|
||||||
def mark_as_read?(activity, target_user) do
|
def mark_as_read?(activity, target_user) do
|
||||||
user = Activity.user_actor(activity)
|
user = Activity.user_actor(activity)
|
||||||
|
|
|
@ -29,9 +29,7 @@ def handle_event(
|
||||||
_
|
_
|
||||||
) do
|
) do
|
||||||
Logger.debug(fn ->
|
Logger.debug(fn ->
|
||||||
"Connection pool is exhausted (reached #{max_connections} connections). Starting idle connection cleanup to reclaim as much as #{
|
"Connection pool is exhausted (reached #{max_connections} connections). Starting idle connection cleanup to reclaim as much as #{reclaim_max} connections"
|
||||||
reclaim_max
|
|
||||||
} connections"
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -73,9 +71,7 @@ def handle_event(
|
||||||
_
|
_
|
||||||
) do
|
) do
|
||||||
Logger.warn(fn ->
|
Logger.warn(fn ->
|
||||||
"Pool worker for #{key}: Client #{inspect(client_pid)} died before releasing the connection with #{
|
"Pool worker for #{key}: Client #{inspect(client_pid)} died before releasing the connection with #{inspect(reason)}"
|
||||||
inspect(reason)
|
|
||||||
}"
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,6 @@ defmodule Pleroma.User do
|
||||||
field(:is_moderator, :boolean, default: false)
|
field(:is_moderator, :boolean, default: false)
|
||||||
field(:is_admin, :boolean, default: false)
|
field(:is_admin, :boolean, default: false)
|
||||||
field(:show_role, :boolean, default: true)
|
field(:show_role, :boolean, default: true)
|
||||||
field(:mastofe_settings, :map, default: nil)
|
|
||||||
field(:uri, ObjectValidators.Uri, default: nil)
|
field(:uri, ObjectValidators.Uri, default: nil)
|
||||||
field(:hide_followers_count, :boolean, default: false)
|
field(:hide_followers_count, :boolean, default: false)
|
||||||
field(:hide_follows_count, :boolean, default: false)
|
field(:hide_follows_count, :boolean, default: false)
|
||||||
|
@ -1713,7 +1712,6 @@ def purge_user_changeset(user) do
|
||||||
ap_enabled: false,
|
ap_enabled: false,
|
||||||
is_moderator: false,
|
is_moderator: false,
|
||||||
is_admin: false,
|
is_admin: false,
|
||||||
mastofe_settings: nil,
|
|
||||||
mascot: nil,
|
mascot: nil,
|
||||||
emoji: %{},
|
emoji: %{},
|
||||||
pleroma_settings_store: %{},
|
pleroma_settings_store: %{},
|
||||||
|
@ -2248,7 +2246,7 @@ def get_delivered_users_by_object_id(object_id) do
|
||||||
def change_email(user, email) do
|
def change_email(user, email) do
|
||||||
user
|
user
|
||||||
|> cast(%{email: email}, [:email])
|
|> cast(%{email: email}, [:email])
|
||||||
|> validate_required([:email])
|
|> maybe_validate_required_email(false)
|
||||||
|> unique_constraint(:email)
|
|> unique_constraint(:email)
|
||||||
|> validate_format(:email, @email_regex)
|
|> validate_format(:email, @email_regex)
|
||||||
|> update_and_set_cache()
|
|> update_and_set_cache()
|
||||||
|
@ -2331,13 +2329,6 @@ def mascot_update(user, url) do
|
||||||
|> update_and_set_cache()
|
|> update_and_set_cache()
|
||||||
end
|
end
|
||||||
|
|
||||||
def mastodon_settings_update(user, settings) do
|
|
||||||
user
|
|
||||||
|> cast(%{mastofe_settings: settings}, [:mastofe_settings])
|
|
||||||
|> validate_required([:mastofe_settings])
|
|
||||||
|> update_and_set_cache()
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec confirmation_changeset(User.t(), keyword()) :: Changeset.t()
|
@spec confirmation_changeset(User.t(), keyword()) :: Changeset.t()
|
||||||
def confirmation_changeset(user, set_confirmation: confirmed?) do
|
def confirmation_changeset(user, set_confirmation: confirmed?) do
|
||||||
params =
|
params =
|
||||||
|
|
|
@ -25,6 +25,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
alias Pleroma.Web.Streamer
|
alias Pleroma.Web.Streamer
|
||||||
alias Pleroma.Web.WebFinger
|
alias Pleroma.Web.WebFinger
|
||||||
alias Pleroma.Workers.BackgroundWorker
|
alias Pleroma.Workers.BackgroundWorker
|
||||||
|
alias Pleroma.Workers.PollWorker
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
import Pleroma.Web.ActivityPub.Utils
|
import Pleroma.Web.ActivityPub.Utils
|
||||||
|
@ -288,6 +289,7 @@ defp do_create(%{to: to, actor: actor, context: context, object: object} = param
|
||||||
{:quick_insert, false, activity} <- {:quick_insert, quick_insert?, activity},
|
{:quick_insert, false, activity} <- {:quick_insert, quick_insert?, activity},
|
||||||
{:ok, _actor} <- increase_note_count_if_public(actor, activity),
|
{:ok, _actor} <- increase_note_count_if_public(actor, activity),
|
||||||
_ <- notify_and_stream(activity),
|
_ <- notify_and_stream(activity),
|
||||||
|
:ok <- maybe_schedule_poll_notifications(activity),
|
||||||
:ok <- maybe_federate(activity) do
|
:ok <- maybe_federate(activity) do
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
|
@ -302,6 +304,11 @@ defp do_create(%{to: to, actor: actor, context: context, object: object} = param
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp maybe_schedule_poll_notifications(activity) do
|
||||||
|
PollWorker.schedule_poll_end(activity)
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
@spec listen(map()) :: {:ok, Activity.t()} | {:error, any()}
|
@spec listen(map()) :: {:ok, Activity.t()} | {:error, any()}
|
||||||
def listen(%{to: to, actor: actor, context: context, object: object} = params) do
|
def listen(%{to: to, actor: actor, context: context, object: object} = params) do
|
||||||
additional = params[:additional] || %{}
|
additional = params[:additional] || %{}
|
||||||
|
@ -434,6 +441,7 @@ def fetch_activities_for_context_query(context, opts) do
|
||||||
|> maybe_preload_bookmarks(opts)
|
|> maybe_preload_bookmarks(opts)
|
||||||
|> maybe_set_thread_muted_field(opts)
|
|> maybe_set_thread_muted_field(opts)
|
||||||
|> restrict_blocked(opts)
|
|> restrict_blocked(opts)
|
||||||
|
|> restrict_blockers_visibility(opts)
|
||||||
|> restrict_recipients(recipients, opts[:user])
|
|> restrict_recipients(recipients, opts[:user])
|
||||||
|> restrict_filtered(opts)
|
|> restrict_filtered(opts)
|
||||||
|> where(
|
|> where(
|
||||||
|
@ -1021,7 +1029,10 @@ defp restrict_blocked(query, %{blocking_user: %User{} = user} = opts) do
|
||||||
|
|
||||||
from(
|
from(
|
||||||
[activity, object: o] in query,
|
[activity, object: o] in query,
|
||||||
|
# You don't block the author
|
||||||
where: fragment("not (? = ANY(?))", activity.actor, ^blocked_ap_ids),
|
where: fragment("not (? = ANY(?))", activity.actor, ^blocked_ap_ids),
|
||||||
|
|
||||||
|
# You don't block any recipients, and didn't author the post
|
||||||
where:
|
where:
|
||||||
fragment(
|
fragment(
|
||||||
"((not (? && ?)) or ? = ?)",
|
"((not (? && ?)) or ? = ?)",
|
||||||
|
@ -1030,12 +1041,18 @@ defp restrict_blocked(query, %{blocking_user: %User{} = user} = opts) do
|
||||||
activity.actor,
|
activity.actor,
|
||||||
^user.ap_id
|
^user.ap_id
|
||||||
),
|
),
|
||||||
|
|
||||||
|
# You don't block the domain of any recipients, and didn't author the post
|
||||||
where:
|
where:
|
||||||
fragment(
|
fragment(
|
||||||
"recipients_contain_blocked_domains(?, ?) = false",
|
"(recipients_contain_blocked_domains(?, ?) = false) or ? = ?",
|
||||||
activity.recipients,
|
activity.recipients,
|
||||||
^domain_blocks
|
^domain_blocks,
|
||||||
|
activity.actor,
|
||||||
|
^user.ap_id
|
||||||
),
|
),
|
||||||
|
|
||||||
|
# It's not a boost of a user you block
|
||||||
where:
|
where:
|
||||||
fragment(
|
fragment(
|
||||||
"not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
|
"not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
|
||||||
|
@ -1043,6 +1060,8 @@ defp restrict_blocked(query, %{blocking_user: %User{} = user} = opts) do
|
||||||
activity.data,
|
activity.data,
|
||||||
^blocked_ap_ids
|
^blocked_ap_ids
|
||||||
),
|
),
|
||||||
|
|
||||||
|
# You don't block the author's domain, and also don't follow the author
|
||||||
where:
|
where:
|
||||||
fragment(
|
fragment(
|
||||||
"(not (split_part(?, '/', 3) = ANY(?))) or ? = ANY(?)",
|
"(not (split_part(?, '/', 3) = ANY(?))) or ? = ANY(?)",
|
||||||
|
@ -1051,6 +1070,8 @@ defp restrict_blocked(query, %{blocking_user: %User{} = user} = opts) do
|
||||||
activity.actor,
|
activity.actor,
|
||||||
^following_ap_ids
|
^following_ap_ids
|
||||||
),
|
),
|
||||||
|
|
||||||
|
# Same as above, but checks the Object
|
||||||
where:
|
where:
|
||||||
fragment(
|
fragment(
|
||||||
"(not (split_part(?->>'actor', '/', 3) = ANY(?))) or (?->>'actor') = ANY(?)",
|
"(not (split_part(?->>'actor', '/', 3) = ANY(?))) or (?->>'actor') = ANY(?)",
|
||||||
|
@ -1064,6 +1085,31 @@ defp restrict_blocked(query, %{blocking_user: %User{} = user} = opts) do
|
||||||
|
|
||||||
defp restrict_blocked(query, _), do: query
|
defp restrict_blocked(query, _), do: query
|
||||||
|
|
||||||
|
defp restrict_blockers_visibility(query, %{blocking_user: %User{} = user}) do
|
||||||
|
if Config.get([:activitypub, :blockers_visible]) == true do
|
||||||
|
query
|
||||||
|
else
|
||||||
|
blocker_ap_ids = User.incoming_relationships_ungrouped_ap_ids(user, [:block])
|
||||||
|
|
||||||
|
from(
|
||||||
|
activity in query,
|
||||||
|
# The author doesn't block you
|
||||||
|
where: fragment("not (? = ANY(?))", activity.actor, ^blocker_ap_ids),
|
||||||
|
|
||||||
|
# It's not a boost of a user that blocks you
|
||||||
|
where:
|
||||||
|
fragment(
|
||||||
|
"not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
|
||||||
|
activity.data,
|
||||||
|
activity.data,
|
||||||
|
^blocker_ap_ids
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict_blockers_visibility(query, _), do: query
|
||||||
|
|
||||||
defp restrict_unlisted(query, %{restrict_unlisted: true}) do
|
defp restrict_unlisted(query, %{restrict_unlisted: true}) do
|
||||||
from(
|
from(
|
||||||
activity in query,
|
activity in query,
|
||||||
|
@ -1290,6 +1336,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do
|
||||||
|> restrict_state(opts)
|
|> restrict_state(opts)
|
||||||
|> restrict_favorited_by(opts)
|
|> restrict_favorited_by(opts)
|
||||||
|> restrict_blocked(restrict_blocked_opts)
|
|> restrict_blocked(restrict_blocked_opts)
|
||||||
|
|> restrict_blockers_visibility(opts)
|
||||||
|> restrict_muted(restrict_muted_opts)
|
|> restrict_muted(restrict_muted_opts)
|
||||||
|> restrict_filtered(opts)
|
|> restrict_filtered(opts)
|
||||||
|> restrict_media(opts)
|
|> restrict_media(opts)
|
||||||
|
@ -1590,9 +1637,7 @@ def maybe_handle_clashing_nickname(data) do
|
||||||
%User{} = old_user <- User.get_by_nickname(nickname),
|
%User{} = old_user <- User.get_by_nickname(nickname),
|
||||||
{_, false} <- {:ap_id_comparison, data[:ap_id] == old_user.ap_id} do
|
{_, false} <- {:ap_id_comparison, data[:ap_id] == old_user.ap_id} do
|
||||||
Logger.info(
|
Logger.info(
|
||||||
"Found an old user for #{nickname}, the old ap id is #{old_user.ap_id}, new one is #{
|
"Found an old user for #{nickname}, the old ap id is #{old_user.ap_id}, new one is #{data[:ap_id]}, renaming."
|
||||||
data[:ap_id]
|
|
||||||
}, renaming."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
old_user
|
old_user
|
||||||
|
|
|
@ -283,15 +283,29 @@ def inbox(%{assigns: %{valid_signature: true}} = conn, params) do
|
||||||
json(conn, "ok")
|
json(conn, "ok")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def inbox(%{assigns: %{valid_signature: false}} = conn, _params) do
|
||||||
|
conn
|
||||||
|
|> put_status(:bad_request)
|
||||||
|
|> json("Invalid HTTP Signature")
|
||||||
|
end
|
||||||
|
|
||||||
# POST /relay/inbox -or- POST /internal/fetch/inbox
|
# POST /relay/inbox -or- POST /internal/fetch/inbox
|
||||||
def inbox(conn, params) do
|
def inbox(conn, %{"type" => "Create"} = params) do
|
||||||
if params["type"] == "Create" && FederatingPlug.federating?() do
|
if FederatingPlug.federating?() do
|
||||||
post_inbox_relayed_create(conn, params)
|
post_inbox_relayed_create(conn, params)
|
||||||
else
|
else
|
||||||
post_inbox_fallback(conn, params)
|
conn
|
||||||
|
|> put_status(:bad_request)
|
||||||
|
|> json("Not federating")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def inbox(conn, _params) do
|
||||||
|
conn
|
||||||
|
|> put_status(:bad_request)
|
||||||
|
|> json("error, missing HTTP Signature")
|
||||||
|
end
|
||||||
|
|
||||||
defp post_inbox_relayed_create(conn, params) do
|
defp post_inbox_relayed_create(conn, params) do
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
"Signature missing or not from author, relayed Create message, fetching object from source"
|
"Signature missing or not from author, relayed Create message, fetching object from source"
|
||||||
|
@ -302,23 +316,6 @@ defp post_inbox_relayed_create(conn, params) do
|
||||||
json(conn, "ok")
|
json(conn, "ok")
|
||||||
end
|
end
|
||||||
|
|
||||||
defp post_inbox_fallback(conn, params) do
|
|
||||||
headers = Enum.into(conn.req_headers, %{})
|
|
||||||
|
|
||||||
if headers["signature"] && params["actor"] &&
|
|
||||||
String.contains?(headers["signature"], params["actor"]) do
|
|
||||||
Logger.debug(
|
|
||||||
"Signature validation error for: #{params["actor"]}, make sure you are forwarding the HTTP Host header!"
|
|
||||||
)
|
|
||||||
|
|
||||||
Logger.debug(inspect(conn.req_headers))
|
|
||||||
end
|
|
||||||
|
|
||||||
conn
|
|
||||||
|> put_status(:bad_request)
|
|
||||||
|> json(dgettext("errors", "error"))
|
|
||||||
end
|
|
||||||
|
|
||||||
defp represent_service_actor(%User{} = user, conn) do
|
defp represent_service_actor(%User{} = user, conn) do
|
||||||
with {:ok, user} <- User.ensure_keys_present(user) do
|
with {:ok, user} <- User.ensure_keys_present(user) do
|
||||||
conn
|
conn
|
||||||
|
|
|
@ -15,6 +15,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
||||||
alias Pleroma.Web.ActivityPub.Relay
|
alias Pleroma.Web.ActivityPub.Relay
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
alias Pleroma.Web.ActivityPub.Visibility
|
||||||
|
alias Pleroma.Web.CommonAPI.ActivityDraft
|
||||||
|
|
||||||
require Pleroma.Constants
|
require Pleroma.Constants
|
||||||
|
|
||||||
|
@ -125,6 +126,37 @@ def create(actor, object, recipients) do
|
||||||
|> Pleroma.Maps.put_if_present("context", context), []}
|
|> Pleroma.Maps.put_if_present("context", context), []}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec note(ActivityDraft.t()) :: {:ok, map(), keyword()}
|
||||||
|
def note(%ActivityDraft{} = draft) do
|
||||||
|
data =
|
||||||
|
%{
|
||||||
|
"type" => "Note",
|
||||||
|
"to" => draft.to,
|
||||||
|
"cc" => draft.cc,
|
||||||
|
"content" => draft.content_html,
|
||||||
|
"summary" => draft.summary,
|
||||||
|
"sensitive" => draft.sensitive,
|
||||||
|
"context" => draft.context,
|
||||||
|
"attachment" => draft.attachments,
|
||||||
|
"actor" => draft.user.ap_id,
|
||||||
|
"tag" => Keyword.values(draft.tags) |> Enum.uniq()
|
||||||
|
}
|
||||||
|
|> add_in_reply_to(draft.in_reply_to)
|
||||||
|
|> Map.merge(draft.extra)
|
||||||
|
|
||||||
|
{:ok, data, []}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp add_in_reply_to(object, nil), do: object
|
||||||
|
|
||||||
|
defp add_in_reply_to(object, in_reply_to) do
|
||||||
|
with %Object{} = in_reply_to_object <- Object.normalize(in_reply_to, fetch: false) do
|
||||||
|
Map.put(object, "inReplyTo", in_reply_to_object.data["id"])
|
||||||
|
else
|
||||||
|
_ -> object
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def chat_message(actor, recipient, content, opts \\ []) do
|
def chat_message(actor, recipient, content, opts \\ []) do
|
||||||
basic = %{
|
basic = %{
|
||||||
"id" => Utils.generate_object_id(),
|
"id" => Utils.generate_object_id(),
|
||||||
|
|
|
@ -33,9 +33,11 @@ defmodule Pleroma.Web.ActivityPub.MRF do
|
||||||
%{
|
%{
|
||||||
key: :transparency_exclusions,
|
key: :transparency_exclusions,
|
||||||
label: "MRF transparency exclusions",
|
label: "MRF transparency exclusions",
|
||||||
type: {:list, :string},
|
type: {:list, :tuple},
|
||||||
|
key_placeholder: "instance",
|
||||||
|
value_placeholder: "reason",
|
||||||
description:
|
description:
|
||||||
"Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value.",
|
"Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. You can also provide a reason for excluding these instance names. The instances and reasons won't be publicly disclosed.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
"exclusion.com"
|
"exclusion.com"
|
||||||
]
|
]
|
||||||
|
@ -100,6 +102,11 @@ def subdomain_match?(domains, host) do
|
||||||
Enum.any?(domains, fn domain -> Regex.match?(domain, host) end)
|
Enum.any?(domains, fn domain -> Regex.match?(domain, host) end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec instance_list_from_tuples([{String.t(), String.t()}]) :: [String.t()]
|
||||||
|
def instance_list_from_tuples(list) do
|
||||||
|
Enum.map(list, fn {instance, _} -> instance end)
|
||||||
|
end
|
||||||
|
|
||||||
def describe(policies) do
|
def describe(policies) do
|
||||||
{:ok, policy_configs} =
|
{:ok, policy_configs} =
|
||||||
policies
|
policies
|
||||||
|
@ -150,9 +157,7 @@ def config_descriptions(policies) do
|
||||||
[description | acc]
|
[description | acc]
|
||||||
else
|
else
|
||||||
Logger.warn(
|
Logger.warn(
|
||||||
"#{policy} config description doesn't have one or all required keys #{
|
"#{policy} config description doesn't have one or all required keys #{inspect(@required_description_keys)}"
|
||||||
inspect(@required_description_keys)
|
|
||||||
}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
acc
|
acc
|
||||||
|
|
|
@ -159,6 +159,8 @@ def config_description do
|
||||||
%{
|
%{
|
||||||
key: :replace,
|
key: :replace,
|
||||||
type: {:list, :tuple},
|
type: {:list, :tuple},
|
||||||
|
key_placeholder: "instance",
|
||||||
|
value_placeholder: "reason",
|
||||||
description: """
|
description: """
|
||||||
**Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
|
**Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def describe,
|
def describe,
|
||||||
do: {:ok, %{mrf_rejectnonpublic: Config.get(:mrf_rejectnonpublic) |> Enum.into(%{})}}
|
do: {:ok, %{mrf_rejectnonpublic: Config.get(:mrf_rejectnonpublic) |> Map.new()}}
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def config_description do
|
def config_description do
|
||||||
|
|
|
@ -15,7 +15,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
||||||
|
|
||||||
defp check_accept(%{host: actor_host} = _actor_info, object) do
|
defp check_accept(%{host: actor_host} = _actor_info, object) do
|
||||||
accepts =
|
accepts =
|
||||||
Config.get([:mrf_simple, :accept])
|
instance_list(:accept)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
|
@ -28,7 +28,7 @@ defp check_accept(%{host: actor_host} = _actor_info, object) do
|
||||||
|
|
||||||
defp check_reject(%{host: actor_host} = _actor_info, object) do
|
defp check_reject(%{host: actor_host} = _actor_info, object) do
|
||||||
rejects =
|
rejects =
|
||||||
Config.get([:mrf_simple, :reject])
|
instance_list(:reject)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
|
||||||
if MRF.subdomain_match?(rejects, actor_host) do
|
if MRF.subdomain_match?(rejects, actor_host) do
|
||||||
|
@ -44,7 +44,7 @@ defp check_media_removal(
|
||||||
)
|
)
|
||||||
when length(child_attachment) > 0 do
|
when length(child_attachment) > 0 do
|
||||||
media_removal =
|
media_removal =
|
||||||
Config.get([:mrf_simple, :media_removal])
|
instance_list(:media_removal)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
|
||||||
object =
|
object =
|
||||||
|
@ -68,7 +68,7 @@ defp check_media_nsfw(
|
||||||
} = object
|
} = object
|
||||||
) do
|
) do
|
||||||
media_nsfw =
|
media_nsfw =
|
||||||
Config.get([:mrf_simple, :media_nsfw])
|
instance_list(:media_nsfw)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
|
||||||
object =
|
object =
|
||||||
|
@ -85,7 +85,7 @@ defp check_media_nsfw(_actor_info, object), do: {:ok, object}
|
||||||
|
|
||||||
defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do
|
defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do
|
||||||
timeline_removal =
|
timeline_removal =
|
||||||
Config.get([:mrf_simple, :federated_timeline_removal])
|
instance_list(:federated_timeline_removal)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
|
||||||
object =
|
object =
|
||||||
|
@ -112,7 +112,7 @@ defp intersection(list1, list2) do
|
||||||
|
|
||||||
defp check_followers_only(%{host: actor_host} = _actor_info, object) do
|
defp check_followers_only(%{host: actor_host} = _actor_info, object) do
|
||||||
followers_only =
|
followers_only =
|
||||||
Config.get([:mrf_simple, :followers_only])
|
instance_list(:followers_only)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
|
||||||
object =
|
object =
|
||||||
|
@ -137,7 +137,7 @@ defp check_followers_only(%{host: actor_host} = _actor_info, object) do
|
||||||
|
|
||||||
defp check_report_removal(%{host: actor_host} = _actor_info, %{"type" => "Flag"} = object) do
|
defp check_report_removal(%{host: actor_host} = _actor_info, %{"type" => "Flag"} = object) do
|
||||||
report_removal =
|
report_removal =
|
||||||
Config.get([:mrf_simple, :report_removal])
|
instance_list(:report_removal)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
|
||||||
if MRF.subdomain_match?(report_removal, actor_host) do
|
if MRF.subdomain_match?(report_removal, actor_host) do
|
||||||
|
@ -151,7 +151,7 @@ defp check_report_removal(_actor_info, object), do: {:ok, object}
|
||||||
|
|
||||||
defp check_avatar_removal(%{host: actor_host} = _actor_info, %{"icon" => _icon} = object) do
|
defp check_avatar_removal(%{host: actor_host} = _actor_info, %{"icon" => _icon} = object) do
|
||||||
avatar_removal =
|
avatar_removal =
|
||||||
Config.get([:mrf_simple, :avatar_removal])
|
instance_list(:avatar_removal)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
|
||||||
if MRF.subdomain_match?(avatar_removal, actor_host) do
|
if MRF.subdomain_match?(avatar_removal, actor_host) do
|
||||||
|
@ -165,7 +165,7 @@ defp check_avatar_removal(_actor_info, object), do: {:ok, object}
|
||||||
|
|
||||||
defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image} = object) do
|
defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image} = object) do
|
||||||
banner_removal =
|
banner_removal =
|
||||||
Config.get([:mrf_simple, :banner_removal])
|
instance_list(:banner_removal)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
|
||||||
if MRF.subdomain_match?(banner_removal, actor_host) do
|
if MRF.subdomain_match?(banner_removal, actor_host) do
|
||||||
|
@ -185,12 +185,17 @@ defp check_object(%{"object" => object} = activity) do
|
||||||
|
|
||||||
defp check_object(object), do: {:ok, object}
|
defp check_object(object), do: {:ok, object}
|
||||||
|
|
||||||
|
defp instance_list(config_key) do
|
||||||
|
Config.get([:mrf_simple, config_key])
|
||||||
|
|> MRF.instance_list_from_tuples()
|
||||||
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(%{"type" => "Delete", "actor" => actor} = object) do
|
def filter(%{"type" => "Delete", "actor" => actor} = object) do
|
||||||
%{host: actor_host} = URI.parse(actor)
|
%{host: actor_host} = URI.parse(actor)
|
||||||
|
|
||||||
reject_deletes =
|
reject_deletes =
|
||||||
Config.get([:mrf_simple, :reject_deletes])
|
instance_list(:reject_deletes)
|
||||||
|> MRF.subdomains_regex()
|
|> MRF.subdomains_regex()
|
||||||
|
|
||||||
if MRF.subdomain_match?(reject_deletes, actor_host) do
|
if MRF.subdomain_match?(reject_deletes, actor_host) do
|
||||||
|
@ -253,14 +258,42 @@ def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def describe do
|
def describe do
|
||||||
exclusions = Config.get([:mrf, :transparency_exclusions])
|
exclusions = Config.get([:mrf, :transparency_exclusions]) |> MRF.instance_list_from_tuples()
|
||||||
|
|
||||||
|
mrf_simple_excluded =
|
||||||
|
Config.get(:mrf_simple)
|
||||||
|
|> Enum.map(fn {rule, instances} ->
|
||||||
|
{rule, Enum.reject(instances, fn {host, _} -> host in exclusions end)}
|
||||||
|
end)
|
||||||
|
|
||||||
mrf_simple =
|
mrf_simple =
|
||||||
Config.get(:mrf_simple)
|
mrf_simple_excluded
|
||||||
|> Enum.map(fn {k, v} -> {k, Enum.reject(v, fn v -> v in exclusions end)} end)
|
|> Enum.map(fn {rule, instances} ->
|
||||||
|> Enum.into(%{})
|
{rule, Enum.map(instances, fn {host, _} -> host end)}
|
||||||
|
end)
|
||||||
|
|> Map.new()
|
||||||
|
|
||||||
{:ok, %{mrf_simple: mrf_simple}}
|
# This is for backwards compatibility. We originally didn't sent
|
||||||
|
# extra info like a reason why an instance was rejected/quarantined/etc.
|
||||||
|
# Because we didn't want to break backwards compatibility it was decided
|
||||||
|
# to add an extra "info" key.
|
||||||
|
mrf_simple_info =
|
||||||
|
mrf_simple_excluded
|
||||||
|
|> Enum.map(fn {rule, instances} ->
|
||||||
|
{rule, Enum.reject(instances, fn {_, reason} -> reason == "" end)}
|
||||||
|
end)
|
||||||
|
|> Enum.reject(fn {_, instances} -> instances == [] end)
|
||||||
|
|> Enum.map(fn {rule, instances} ->
|
||||||
|
instances =
|
||||||
|
instances
|
||||||
|
|> Enum.map(fn {host, reason} -> {host, %{"reason" => reason}} end)
|
||||||
|
|> Map.new()
|
||||||
|
|
||||||
|
{rule, instances}
|
||||||
|
end)
|
||||||
|
|> Map.new()
|
||||||
|
|
||||||
|
{:ok, %{mrf_simple: mrf_simple, mrf_simple_info: mrf_simple_info}}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
@ -270,70 +303,67 @@ def config_description do
|
||||||
related_policy: "Pleroma.Web.ActivityPub.MRF.SimplePolicy",
|
related_policy: "Pleroma.Web.ActivityPub.MRF.SimplePolicy",
|
||||||
label: "MRF Simple",
|
label: "MRF Simple",
|
||||||
description: "Simple ingress policies",
|
description: "Simple ingress policies",
|
||||||
children: [
|
children:
|
||||||
%{
|
[
|
||||||
key: :media_removal,
|
%{
|
||||||
type: {:list, :string},
|
key: :media_removal,
|
||||||
description: "List of instances to strip media attachments from",
|
description:
|
||||||
suggestions: ["example.com", "*.example.com"]
|
"List of instances to strip media attachments from and the reason for doing so"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :media_nsfw,
|
key: :media_nsfw,
|
||||||
label: "Media NSFW",
|
label: "Media NSFW",
|
||||||
type: {:list, :string},
|
description:
|
||||||
description: "List of instances to tag all media as NSFW (sensitive) from",
|
"List of instances to tag all media as NSFW (sensitive) from and the reason for doing so"
|
||||||
suggestions: ["example.com", "*.example.com"]
|
},
|
||||||
},
|
%{
|
||||||
%{
|
key: :federated_timeline_removal,
|
||||||
key: :federated_timeline_removal,
|
description:
|
||||||
type: {:list, :string},
|
"List of instances to remove from the Federated (aka The Whole Known Network) Timeline and the reason for doing so"
|
||||||
description:
|
},
|
||||||
"List of instances to remove from the Federated (aka The Whole Known Network) Timeline",
|
%{
|
||||||
suggestions: ["example.com", "*.example.com"]
|
key: :reject,
|
||||||
},
|
description:
|
||||||
%{
|
"List of instances to reject activities from (except deletes) and the reason for doing so"
|
||||||
key: :reject,
|
},
|
||||||
type: {:list, :string},
|
%{
|
||||||
description: "List of instances to reject activities from (except deletes)",
|
key: :accept,
|
||||||
suggestions: ["example.com", "*.example.com"]
|
description:
|
||||||
},
|
"List of instances to only accept activities from (except deletes) and the reason for doing so"
|
||||||
%{
|
},
|
||||||
key: :accept,
|
%{
|
||||||
type: {:list, :string},
|
key: :followers_only,
|
||||||
description: "List of instances to only accept activities from (except deletes)",
|
description:
|
||||||
suggestions: ["example.com", "*.example.com"]
|
"Force posts from the given instances to be visible by followers only and the reason for doing so"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :followers_only,
|
key: :report_removal,
|
||||||
type: {:list, :string},
|
description: "List of instances to reject reports from and the reason for doing so"
|
||||||
description: "Force posts from the given instances to be visible by followers only",
|
},
|
||||||
suggestions: ["example.com", "*.example.com"]
|
%{
|
||||||
},
|
key: :avatar_removal,
|
||||||
%{
|
description: "List of instances to strip avatars from and the reason for doing so"
|
||||||
key: :report_removal,
|
},
|
||||||
type: {:list, :string},
|
%{
|
||||||
description: "List of instances to reject reports from",
|
key: :banner_removal,
|
||||||
suggestions: ["example.com", "*.example.com"]
|
description: "List of instances to strip banners from and the reason for doing so"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :avatar_removal,
|
key: :reject_deletes,
|
||||||
type: {:list, :string},
|
description: "List of instances to reject deletions from and the reason for doing so"
|
||||||
description: "List of instances to strip avatars from",
|
}
|
||||||
suggestions: ["example.com", "*.example.com"]
|
]
|
||||||
},
|
|> Enum.map(fn setting ->
|
||||||
%{
|
Map.merge(
|
||||||
key: :banner_removal,
|
setting,
|
||||||
type: {:list, :string},
|
%{
|
||||||
description: "List of instances to strip banners from",
|
type: {:list, :tuple},
|
||||||
suggestions: ["example.com", "*.example.com"]
|
key_placeholder: "instance",
|
||||||
},
|
value_placeholder: "reason",
|
||||||
%{
|
suggestions: [{"example.com", "Some reason"}, {"*.example.com", "Another reason"}]
|
||||||
key: :reject_deletes,
|
}
|
||||||
type: {:list, :string},
|
)
|
||||||
description: "List of instances to reject deletions from",
|
end)
|
||||||
suggestions: ["example.com", "*.example.com"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,9 +38,7 @@ defp steal_emoji({shortcode, url}, emoji_dir_path) do
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
"MRF.StealEmojiPolicy: :#{shortcode}: at #{url} (#{byte_size(response.body)} B) over size limit (#{
|
"MRF.StealEmojiPolicy: :#{shortcode}: at #{url} (#{byte_size(response.body)} B) over size limit (#{size_limit} B)"
|
||||||
size_limit
|
|
||||||
} B)"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
nil
|
nil
|
||||||
|
|
|
@ -23,9 +23,7 @@ defp lookup_subchain(actor) do
|
||||||
def filter(%{"actor" => actor} = message) do
|
def filter(%{"actor" => actor} = message) do
|
||||||
with {:ok, match, subchain} <- lookup_subchain(actor) do
|
with {:ok, match, subchain} <- lookup_subchain(actor) do
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
"[SubchainPolicy] Matched #{actor} against #{inspect(match)} with subchain #{
|
"[SubchainPolicy] Matched #{actor} against #{inspect(match)} with subchain #{inspect(subchain)}"
|
||||||
inspect(subchain)
|
|
||||||
}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
MRF.filter(subchain, message)
|
MRF.filter(subchain, message)
|
||||||
|
|
|
@ -37,7 +37,7 @@ def filter(object), do: {:ok, object}
|
||||||
def describe do
|
def describe do
|
||||||
mrf_user_allowlist =
|
mrf_user_allowlist =
|
||||||
Config.get([:mrf_user_allowlist], [])
|
Config.get([:mrf_user_allowlist], [])
|
||||||
|> Enum.into(%{}, fn {k, v} -> {k, length(v)} end)
|
|> Map.new(fn {k, v} -> {k, length(v)} end)
|
||||||
|
|
||||||
{:ok, %{mrf_user_allowlist: mrf_user_allowlist}}
|
{:ok, %{mrf_user_allowlist: mrf_user_allowlist}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,7 +39,7 @@ def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def describe,
|
def describe,
|
||||||
do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary) |> Enum.into(%{})}}
|
do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary) |> Map.new()}}
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def config_description do
|
def config_description do
|
||||||
|
|
|
@ -213,6 +213,7 @@ def stringify_keys(%{__struct__: _} = object) do
|
||||||
|
|
||||||
def stringify_keys(object) when is_map(object) do
|
def stringify_keys(object) when is_map(object) do
|
||||||
object
|
object
|
||||||
|
|> Enum.filter(fn {_, v} -> v != nil end)
|
||||||
|> Map.new(fn {key, val} -> {to_string(key), stringify_keys(val)} end)
|
|> Map.new(fn {key, val} -> {to_string(key), stringify_keys(val)} end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
|
@ -14,12 +13,13 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:type, :string)
|
unquote do
|
||||||
field(:object, ObjectValidators.ObjectID)
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
message_fields()
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
activity_fields()
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_data(data) do
|
def cast_data(data) do
|
||||||
|
|
|
@ -10,19 +10,20 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AddRemoveValidator do
|
||||||
|
|
||||||
require Pleroma.Constants
|
require Pleroma.Constants
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
|
||||||
field(:target)
|
field(:target)
|
||||||
field(:object, ObjectValidators.ObjectID)
|
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
quote do
|
||||||
field(:type)
|
unquote do
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
message_fields()
|
||||||
|
activity_fields()
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_validate(data) do
|
def cast_and_validate(data) do
|
||||||
|
|
|
@ -20,13 +20,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:type, :string)
|
unquote do
|
||||||
field(:object, ObjectValidators.ObjectID)
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
message_fields()
|
||||||
|
activity_fields()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
field(:context, :string)
|
field(:context, :string)
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
|
||||||
field(:published, ObjectValidators.DateTime)
|
field(:published, ObjectValidators.DateTime)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,13 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator do
|
||||||
@derive Jason.Encoder
|
@derive Jason.Encoder
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
unquote do
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:bto, ObjectValidators.Recipients, default: [])
|
message_fields()
|
||||||
field(:bcc, ObjectValidators.Recipients, default: [])
|
end
|
||||||
field(:type, :string)
|
end
|
||||||
|
|
||||||
field(:name, :string)
|
field(:name, :string)
|
||||||
field(:inReplyTo, ObjectValidators.ObjectID)
|
field(:inReplyTo, ObjectValidators.ObjectID)
|
||||||
field(:attributedTo, ObjectValidators.ObjectID)
|
field(:attributedTo, ObjectValidators.ObjectID)
|
||||||
|
|
|
@ -6,10 +6,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator
|
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator
|
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
@ -18,38 +16,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
|
||||||
@derive Jason.Encoder
|
@derive Jason.Encoder
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
unquote do
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:bto, ObjectValidators.Recipients, default: [])
|
message_fields()
|
||||||
field(:bcc, ObjectValidators.Recipients, default: [])
|
object_fields()
|
||||||
embeds_many(:tag, TagValidator)
|
status_object_fields()
|
||||||
field(:type, :string)
|
end
|
||||||
|
end
|
||||||
field(:name, :string)
|
|
||||||
field(:summary, :string)
|
|
||||||
field(:content, :string)
|
|
||||||
|
|
||||||
field(:context, :string)
|
|
||||||
# short identifier for PleromaFE to group statuses by context
|
|
||||||
field(:context_id, :integer)
|
|
||||||
|
|
||||||
# TODO: Remove actor on objects
|
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
|
||||||
|
|
||||||
field(:attributedTo, ObjectValidators.ObjectID)
|
|
||||||
field(:published, ObjectValidators.DateTime)
|
|
||||||
field(:emoji, ObjectValidators.Emoji, default: %{})
|
|
||||||
field(:sensitive, :boolean, default: false)
|
|
||||||
embeds_many(:attachment, AttachmentValidator)
|
|
||||||
field(:replies_count, :integer, default: 0)
|
|
||||||
field(:like_count, :integer, default: 0)
|
|
||||||
field(:announcement_count, :integer, default: 0)
|
|
||||||
field(:inReplyTo, ObjectValidators.ObjectID)
|
|
||||||
field(:url, ObjectValidators.Uri)
|
|
||||||
|
|
||||||
field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
|
|
||||||
field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])
|
|
||||||
|
|
||||||
field(:replies, {:array, ObjectValidators.ObjectID}, default: [])
|
field(:replies, {:array, ObjectValidators.ObjectID}, default: [])
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,11 +5,8 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator
|
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator
|
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
@ -18,38 +15,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
|
||||||
@derive Jason.Encoder
|
@derive Jason.Encoder
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
unquote do
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:bto, ObjectValidators.Recipients, default: [])
|
message_fields()
|
||||||
field(:bcc, ObjectValidators.Recipients, default: [])
|
object_fields()
|
||||||
embeds_many(:tag, TagValidator)
|
status_object_fields()
|
||||||
field(:type, :string)
|
end
|
||||||
|
end
|
||||||
field(:name, :string)
|
|
||||||
field(:summary, :string)
|
|
||||||
field(:content, :string)
|
|
||||||
|
|
||||||
field(:context, :string)
|
|
||||||
# short identifier for PleromaFE to group statuses by context
|
|
||||||
field(:context_id, :integer)
|
|
||||||
|
|
||||||
# TODO: Remove actor on objects
|
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
|
||||||
|
|
||||||
field(:attributedTo, ObjectValidators.ObjectID)
|
|
||||||
field(:published, ObjectValidators.DateTime)
|
|
||||||
field(:emoji, ObjectValidators.Emoji, default: %{})
|
|
||||||
field(:sensitive, :boolean, default: false)
|
|
||||||
embeds_many(:attachment, AttachmentValidator)
|
|
||||||
field(:replies_count, :integer, default: 0)
|
|
||||||
field(:like_count, :integer, default: 0)
|
|
||||||
field(:announcement_count, :integer, default: 0)
|
|
||||||
field(:inReplyTo, ObjectValidators.ObjectID)
|
|
||||||
field(:url, ObjectValidators.Uri)
|
|
||||||
|
|
||||||
field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
|
|
||||||
field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_apply(data) do
|
def cast_and_apply(data) do
|
||||||
|
|
|
@ -5,20 +5,21 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
|
||||||
|
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
@derive Jason.Encoder
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:type, :string)
|
unquote do
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
message_fields()
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
activity_fields()
|
||||||
field(:object, ObjectValidators.ObjectID)
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_data(data) do
|
def cast_data(data) do
|
||||||
|
@ -30,8 +31,8 @@ defp validate_data(cng) do
|
||||||
cng
|
cng
|
||||||
|> validate_required([:id, :type, :actor, :to, :cc, :object])
|
|> validate_required([:id, :type, :actor, :to, :cc, :object])
|
||||||
|> validate_inclusion(:type, ["Block"])
|
|> validate_inclusion(:type, ["Block"])
|
||||||
|> validate_actor_presence()
|
|> CommonValidations.validate_actor_presence()
|
||||||
|> validate_actor_presence(field_name: :object)
|
|> CommonValidations.validate_actor_presence(field_name: :object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_validate(data) do
|
def cast_and_validate(data) do
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
# 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.ObjectValidators.CommonFields do
|
||||||
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator
|
||||||
|
|
||||||
|
# Activities and Objects, except (Create)ChatMessage
|
||||||
|
defmacro message_fields do
|
||||||
|
quote bind_quoted: binding() do
|
||||||
|
field(:type, :string)
|
||||||
|
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
||||||
|
|
||||||
|
field(:to, ObjectValidators.Recipients, default: [])
|
||||||
|
field(:cc, ObjectValidators.Recipients, default: [])
|
||||||
|
field(:bto, ObjectValidators.Recipients, default: [])
|
||||||
|
field(:bcc, ObjectValidators.Recipients, default: [])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defmacro activity_fields do
|
||||||
|
quote bind_quoted: binding() do
|
||||||
|
field(:object, ObjectValidators.ObjectID)
|
||||||
|
field(:actor, ObjectValidators.ObjectID)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# All objects except Answer and CHatMessage
|
||||||
|
defmacro object_fields do
|
||||||
|
quote bind_quoted: binding() do
|
||||||
|
field(:content, :string)
|
||||||
|
|
||||||
|
field(:published, ObjectValidators.DateTime)
|
||||||
|
field(:emoji, ObjectValidators.Emoji, default: %{})
|
||||||
|
embeds_many(:attachment, AttachmentValidator)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Basically objects that aren't ChatMessage and Answer
|
||||||
|
defmacro status_object_fields do
|
||||||
|
quote bind_quoted: binding() do
|
||||||
|
# TODO: Remove actor on objects
|
||||||
|
field(:actor, ObjectValidators.ObjectID)
|
||||||
|
field(:attributedTo, ObjectValidators.ObjectID)
|
||||||
|
|
||||||
|
embeds_many(:tag, TagValidator)
|
||||||
|
|
||||||
|
field(:name, :string)
|
||||||
|
field(:summary, :string)
|
||||||
|
|
||||||
|
field(:context, :string)
|
||||||
|
# short identifier for PleromaFE to group statuses by context
|
||||||
|
field(:context_id, :integer)
|
||||||
|
|
||||||
|
field(:sensitive, :boolean, default: false)
|
||||||
|
field(:replies_count, :integer, default: 0)
|
||||||
|
field(:like_count, :integer, default: 0)
|
||||||
|
field(:announcement_count, :integer, default: 0)
|
||||||
|
field(:inReplyTo, ObjectValidators.ObjectID)
|
||||||
|
field(:url, ObjectValidators.Uri)
|
||||||
|
|
||||||
|
field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
|
||||||
|
field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -17,11 +17,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator do
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
|
quote do
|
||||||
|
unquote do
|
||||||
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
|
activity_fields()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
|
||||||
field(:type, :string)
|
field(:type, :string)
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
field(:to, ObjectValidators.Recipients, default: [])
|
||||||
field(:object, ObjectValidators.ObjectID)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_apply(data) do
|
def cast_and_apply(data) do
|
||||||
|
|
|
@ -20,14 +20,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
unquote do
|
||||||
field(:type, :string)
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
message_fields()
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
activity_fields()
|
||||||
field(:bto, ObjectValidators.Recipients, default: [])
|
end
|
||||||
field(:bcc, ObjectValidators.Recipients, default: [])
|
end
|
||||||
field(:object, ObjectValidators.ObjectID)
|
|
||||||
field(:expires_at, ObjectValidators.DateTime)
|
field(:expires_at, ObjectValidators.DateTime)
|
||||||
|
|
||||||
# Should be moved to object, done for CommonAPI.Utils.make_context
|
# Should be moved to object, done for CommonAPI.Utils.make_context
|
||||||
|
|
|
@ -15,13 +15,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator do
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:type, :string)
|
unquote do
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
message_fields()
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
activity_fields()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
field(:deleted_activity_id, ObjectValidators.ObjectID)
|
field(:deleted_activity_id, ObjectValidators.ObjectID)
|
||||||
field(:object, ObjectValidators.ObjectID)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_data(data) do
|
def cast_data(data) do
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
|
|
||||||
|
@ -15,14 +14,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:type, :string)
|
unquote do
|
||||||
field(:object, ObjectValidators.ObjectID)
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
message_fields()
|
||||||
|
activity_fields()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
field(:context, :string)
|
field(:context, :string)
|
||||||
field(:content, :string)
|
field(:content, :string)
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_validate(data) do
|
def cast_and_validate(data) do
|
||||||
|
|
|
@ -5,11 +5,8 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator
|
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator
|
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
@ -19,38 +16,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do
|
||||||
|
|
||||||
# Extends from NoteValidator
|
# Extends from NoteValidator
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
unquote do
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:bto, ObjectValidators.Recipients, default: [])
|
message_fields()
|
||||||
field(:bcc, ObjectValidators.Recipients, default: [])
|
object_fields()
|
||||||
embeds_many(:tag, TagValidator)
|
status_object_fields()
|
||||||
field(:type, :string)
|
end
|
||||||
|
end
|
||||||
field(:name, :string)
|
|
||||||
field(:summary, :string)
|
|
||||||
field(:content, :string)
|
|
||||||
|
|
||||||
field(:context, :string)
|
|
||||||
# short identifier for PleromaFE to group statuses by context
|
|
||||||
field(:context_id, :integer)
|
|
||||||
|
|
||||||
# TODO: Remove actor on objects
|
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
|
||||||
|
|
||||||
field(:attributedTo, ObjectValidators.ObjectID)
|
|
||||||
field(:published, ObjectValidators.DateTime)
|
|
||||||
field(:emoji, ObjectValidators.Emoji, default: %{})
|
|
||||||
field(:sensitive, :boolean, default: false)
|
|
||||||
embeds_many(:attachment, AttachmentValidator)
|
|
||||||
field(:replies_count, :integer, default: 0)
|
|
||||||
field(:like_count, :integer, default: 0)
|
|
||||||
field(:announcement_count, :integer, default: 0)
|
|
||||||
field(:inReplyTo, ObjectValidators.ObjectID)
|
|
||||||
field(:url, ObjectValidators.Uri)
|
|
||||||
|
|
||||||
field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
|
|
||||||
field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_apply(data) do
|
def cast_and_apply(data) do
|
||||||
|
|
|
@ -5,20 +5,20 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.FollowValidator do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.FollowValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
|
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:type, :string)
|
unquote do
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
message_fields()
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
activity_fields()
|
||||||
field(:object, ObjectValidators.ObjectID)
|
end
|
||||||
|
end
|
||||||
|
|
||||||
field(:state, :string, default: "pending")
|
field(:state, :string, default: "pending")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
|
@ -16,13 +15,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:type, :string)
|
unquote do
|
||||||
field(:object, ObjectValidators.ObjectID)
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
message_fields()
|
||||||
|
activity_fields()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
field(:context, :string)
|
field(:context, :string)
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_validate(data) do
|
def cast_and_validate(data) do
|
||||||
|
|
|
@ -6,11 +6,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator
|
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.QuestionOptionsValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.QuestionOptionsValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator
|
|
||||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
@ -20,35 +18,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
|
||||||
|
|
||||||
# Extends from NoteValidator
|
# Extends from NoteValidator
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
unquote do
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:bto, ObjectValidators.Recipients, default: [])
|
message_fields()
|
||||||
field(:bcc, ObjectValidators.Recipients, default: [])
|
object_fields()
|
||||||
embeds_many(:tag, TagValidator)
|
status_object_fields()
|
||||||
field(:type, :string)
|
end
|
||||||
field(:content, :string)
|
end
|
||||||
field(:context, :string)
|
|
||||||
|
|
||||||
# TODO: Remove actor on objects
|
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
|
||||||
|
|
||||||
field(:attributedTo, ObjectValidators.ObjectID)
|
|
||||||
field(:summary, :string)
|
|
||||||
field(:published, ObjectValidators.DateTime)
|
|
||||||
field(:emoji, ObjectValidators.Emoji, default: %{})
|
|
||||||
field(:sensitive, :boolean, default: false)
|
|
||||||
embeds_many(:attachment, AttachmentValidator)
|
|
||||||
field(:replies_count, :integer, default: 0)
|
|
||||||
field(:like_count, :integer, default: 0)
|
|
||||||
field(:announcement_count, :integer, default: 0)
|
|
||||||
field(:inReplyTo, ObjectValidators.ObjectID)
|
|
||||||
field(:url, ObjectValidators.Uri)
|
|
||||||
# short identifier for PleromaFE to group statuses by context
|
|
||||||
field(:context_id, :integer)
|
|
||||||
|
|
||||||
field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
|
|
||||||
field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])
|
|
||||||
|
|
||||||
field(:closed, ObjectValidators.DateTime)
|
field(:closed, ObjectValidators.DateTime)
|
||||||
field(:voters, {:array, ObjectValidators.ObjectID}, default: [])
|
field(:voters, {:array, ObjectValidators.ObjectID}, default: [])
|
||||||
|
|
|
@ -6,7 +6,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
@ -15,12 +14,13 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator do
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:type, :string)
|
unquote do
|
||||||
field(:object, ObjectValidators.ObjectID)
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
message_fields()
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
activity_fields()
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_and_validate(data) do
|
def cast_and_validate(data) do
|
||||||
|
|
|
@ -13,11 +13,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator do
|
||||||
@primary_key false
|
@primary_key false
|
||||||
|
|
||||||
embedded_schema do
|
embedded_schema do
|
||||||
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
quote do
|
||||||
field(:type, :string)
|
unquote do
|
||||||
|
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
|
||||||
|
message_fields()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
field(:actor, ObjectValidators.ObjectID)
|
field(:actor, ObjectValidators.ObjectID)
|
||||||
field(:to, ObjectValidators.Recipients, default: [])
|
|
||||||
field(:cc, ObjectValidators.Recipients, default: [])
|
|
||||||
# In this case, we save the full object in this activity instead of just a
|
# In this case, we save the full object in this activity instead of just a
|
||||||
# reference, so we can always see what was actually changed by this.
|
# reference, so we can always see what was actually changed by this.
|
||||||
field(:object, :map)
|
field(:object, :map)
|
||||||
|
|
|
@ -112,6 +112,7 @@ defp should_federate?(inbox, public) do
|
||||||
|
|
||||||
quarantined_instances =
|
quarantined_instances =
|
||||||
Config.get([:instance, :quarantined_instances], [])
|
Config.get([:instance, :quarantined_instances], [])
|
||||||
|
|> Pleroma.Web.ActivityPub.MRF.instance_list_from_tuples()
|
||||||
|> Pleroma.Web.ActivityPub.MRF.subdomains_regex()
|
|> Pleroma.Web.ActivityPub.MRF.subdomains_regex()
|
||||||
|
|
||||||
!Pleroma.Web.ActivityPub.MRF.subdomain_match?(quarantined_instances, host)
|
!Pleroma.Web.ActivityPub.MRF.subdomain_match?(quarantined_instances, host)
|
||||||
|
|
|
@ -23,6 +23,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.Push
|
alias Pleroma.Web.Push
|
||||||
alias Pleroma.Web.Streamer
|
alias Pleroma.Web.Streamer
|
||||||
|
alias Pleroma.Workers.PollWorker
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
@ -194,7 +195,7 @@ def handle(%{data: %{"type" => "Like"}} = object, meta) do
|
||||||
# - Set up notifications
|
# - Set up notifications
|
||||||
@impl true
|
@impl true
|
||||||
def handle(%{data: %{"type" => "Create"}} = activity, meta) do
|
def handle(%{data: %{"type" => "Create"}} = activity, meta) do
|
||||||
with {:ok, object, meta} <- handle_object_creation(meta[:object_data], meta),
|
with {:ok, object, meta} <- handle_object_creation(meta[:object_data], activity, meta),
|
||||||
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
|
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
|
||||||
{:ok, notifications} = Notification.create_notifications(activity, do_send: false)
|
{:ok, notifications} = Notification.create_notifications(activity, do_send: false)
|
||||||
{:ok, _user} = ActivityPub.increase_note_count_if_public(user, object)
|
{:ok, _user} = ActivityPub.increase_note_count_if_public(user, object)
|
||||||
|
@ -388,7 +389,7 @@ def handle(object, meta) do
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do
|
def handle_object_creation(%{"type" => "ChatMessage"} = object, _activity, meta) do
|
||||||
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
||||||
actor = User.get_cached_by_ap_id(object.data["actor"])
|
actor = User.get_cached_by_ap_id(object.data["actor"])
|
||||||
recipient = User.get_cached_by_ap_id(hd(object.data["to"]))
|
recipient = User.get_cached_by_ap_id(hd(object.data["to"]))
|
||||||
|
@ -423,7 +424,14 @@ def handle_object_creation(%{"type" => "ChatMessage"} = object, meta) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_object_creation(%{"type" => "Answer"} = object_map, meta) do
|
def handle_object_creation(%{"type" => "Question"} = object, activity, meta) do
|
||||||
|
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
||||||
|
PollWorker.schedule_poll_end(activity)
|
||||||
|
{:ok, object, meta}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_object_creation(%{"type" => "Answer"} = object_map, _activity, meta) do
|
||||||
with {:ok, object, meta} <- Pipeline.common_pipeline(object_map, meta) do
|
with {:ok, object, meta} <- Pipeline.common_pipeline(object_map, meta) do
|
||||||
Object.increase_vote_count(
|
Object.increase_vote_count(
|
||||||
object.data["inReplyTo"],
|
object.data["inReplyTo"],
|
||||||
|
@ -435,15 +443,15 @@ def handle_object_creation(%{"type" => "Answer"} = object_map, meta) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_object_creation(%{"type" => objtype} = object, meta)
|
def handle_object_creation(%{"type" => objtype} = object, _activity, meta)
|
||||||
when objtype in ~w[Audio Video Question Event Article Note Page] do
|
when objtype in ~w[Audio Video Event Article Note Page] do
|
||||||
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Nothing to do
|
# Nothing to do
|
||||||
def handle_object_creation(object, meta) do
|
def handle_object_creation(object, _activity, meta) do
|
||||||
{:ok, object, meta}
|
{:ok, object, meta}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{scopes: ["admin:read:statuses"]}
|
%{scopes: ["admin:read:statuses"]}
|
||||||
when action in [:list_user_statuses, :list_instance_statuses]
|
when action in [:list_user_statuses]
|
||||||
)
|
)
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
|
@ -81,24 +81,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
||||||
|
|
||||||
action_fallback(AdminAPI.FallbackController)
|
action_fallback(AdminAPI.FallbackController)
|
||||||
|
|
||||||
def list_instance_statuses(conn, %{"instance" => instance} = params) do
|
|
||||||
with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
|
|
||||||
{page, page_size} = page_params(params)
|
|
||||||
|
|
||||||
result =
|
|
||||||
ActivityPub.fetch_statuses(nil, %{
|
|
||||||
instance: instance,
|
|
||||||
limit: page_size,
|
|
||||||
offset: (page - 1) * page_size,
|
|
||||||
exclude_reblogs: not with_reblogs,
|
|
||||||
total: true
|
|
||||||
})
|
|
||||||
|
|
||||||
conn
|
|
||||||
|> put_view(AdminAPI.StatusView)
|
|
||||||
|> render("index.json", %{total: result[:total], activities: result[:items], as: :activity})
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_user_statuses(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname} = params) do
|
def list_user_statuses(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname} = params) do
|
||||||
with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
|
with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
|
||||||
godmode = params["godmode"] == "true" || params["godmode"] == true
|
godmode = params["godmode"] == "true" || params["godmode"] == true
|
||||||
|
|
63
lib/pleroma/web/admin_api/controllers/instance_controller.ex
Normal file
63
lib/pleroma/web/admin_api/controllers/instance_controller.ex
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.AdminAPI.InstanceController do
|
||||||
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
import Pleroma.Web.ControllerHelper, only: [fetch_integer_param: 3]
|
||||||
|
|
||||||
|
alias Pleroma.Instances.Instance
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.AdminAPI
|
||||||
|
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||||
|
|
||||||
|
require Logger
|
||||||
|
|
||||||
|
@default_page_size 50
|
||||||
|
|
||||||
|
plug(
|
||||||
|
OAuthScopesPlug,
|
||||||
|
%{scopes: ["admin:read:statuses"]}
|
||||||
|
when action in [:list_statuses]
|
||||||
|
)
|
||||||
|
|
||||||
|
plug(
|
||||||
|
OAuthScopesPlug,
|
||||||
|
%{scopes: ["admin:write:accounts", "admin:write:statuses"]}
|
||||||
|
when action in [:delete]
|
||||||
|
)
|
||||||
|
|
||||||
|
action_fallback(AdminAPI.FallbackController)
|
||||||
|
|
||||||
|
def list_statuses(conn, %{"instance" => instance} = params) do
|
||||||
|
with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
|
||||||
|
{page, page_size} = page_params(params)
|
||||||
|
|
||||||
|
result =
|
||||||
|
ActivityPub.fetch_statuses(nil, %{
|
||||||
|
instance: instance,
|
||||||
|
limit: page_size,
|
||||||
|
offset: (page - 1) * page_size,
|
||||||
|
exclude_reblogs: not with_reblogs,
|
||||||
|
total: true
|
||||||
|
})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_view(AdminAPI.StatusView)
|
||||||
|
|> render("index.json", %{total: result[:total], activities: result[:items], as: :activity})
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(conn, %{"instance" => instance}) do
|
||||||
|
with {:ok, _job} <- Instance.delete_users_and_activities(instance) do
|
||||||
|
json(conn, instance)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp page_params(params) do
|
||||||
|
{
|
||||||
|
fetch_integer_param(params, "page", 1),
|
||||||
|
fetch_integer_param(params, "page_size", @default_page_size)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -195,7 +195,8 @@ defp notification_type do
|
||||||
"pleroma:chat_mention",
|
"pleroma:chat_mention",
|
||||||
"pleroma:report",
|
"pleroma:report",
|
||||||
"move",
|
"move",
|
||||||
"follow_request"
|
"follow_request",
|
||||||
|
"poll"
|
||||||
],
|
],
|
||||||
description: """
|
description: """
|
||||||
The type of event that resulted in the notification.
|
The type of event that resulted in the notification.
|
||||||
|
|
|
@ -121,7 +121,10 @@ defp change_email_request do
|
||||||
type: :object,
|
type: :object,
|
||||||
required: [:email, :password],
|
required: [:email, :password],
|
||||||
properties: %{
|
properties: %{
|
||||||
email: %Schema{type: :string, description: "New email"},
|
email: %Schema{
|
||||||
|
type: :string,
|
||||||
|
description: "New email. Set to blank to remove the user's email."
|
||||||
|
},
|
||||||
password: %Schema{type: :string, description: "Current password"}
|
password: %Schema{type: :string, description: "Current password"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -487,9 +487,7 @@ def remove_mute(user_id, activity_id) do
|
||||||
else
|
else
|
||||||
{what, result} = error ->
|
{what, result} = error ->
|
||||||
Logger.warn(
|
Logger.warn(
|
||||||
"CommonAPI.remove_mute/2 failed. #{what}: #{result}, user_id: #{user_id}, activity_id: #{
|
"CommonAPI.remove_mute/2 failed. #{what}: #{result}, user_id: #{user_id}, activity_id: #{activity_id}"
|
||||||
activity_id
|
|
||||||
}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
{:error, error}
|
{:error, error}
|
||||||
|
|
|
@ -6,6 +6,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Conversation.Participation
|
alias Pleroma.Conversation.Participation
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
alias Pleroma.Web.ActivityPub.Builder
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.Web.CommonAPI.Utils
|
alias Pleroma.Web.CommonAPI.Utils
|
||||||
|
|
||||||
|
@ -213,8 +214,10 @@ defp object(draft) do
|
||||||
|
|
||||||
emoji = Map.merge(emoji, summary_emoji)
|
emoji = Map.merge(emoji, summary_emoji)
|
||||||
|
|
||||||
|
{:ok, note_data, _meta} = Builder.note(draft)
|
||||||
|
|
||||||
object =
|
object =
|
||||||
Utils.make_note_data(draft)
|
note_data
|
||||||
|> Map.put("emoji", emoji)
|
|> Map.put("emoji", emoji)
|
||||||
|> Map.put("source", draft.status)
|
|> Map.put("source", draft.status)
|
||||||
|> Map.put("generator", draft.params[:generator])
|
|> Map.put("generator", draft.params[:generator])
|
||||||
|
|
|
@ -291,33 +291,6 @@ def format_input(text, "text/markdown", options) do
|
||||||
|> Formatter.html_escape("text/html")
|
|> Formatter.html_escape("text/html")
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_note_data(%ActivityDraft{} = draft) do
|
|
||||||
%{
|
|
||||||
"type" => "Note",
|
|
||||||
"to" => draft.to,
|
|
||||||
"cc" => draft.cc,
|
|
||||||
"content" => draft.content_html,
|
|
||||||
"summary" => draft.summary,
|
|
||||||
"sensitive" => draft.sensitive,
|
|
||||||
"context" => draft.context,
|
|
||||||
"attachment" => draft.attachments,
|
|
||||||
"actor" => draft.user.ap_id,
|
|
||||||
"tag" => Keyword.values(draft.tags) |> Enum.uniq()
|
|
||||||
}
|
|
||||||
|> add_in_reply_to(draft.in_reply_to)
|
|
||||||
|> Map.merge(draft.extra)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp add_in_reply_to(object, nil), do: object
|
|
||||||
|
|
||||||
defp add_in_reply_to(object, in_reply_to) do
|
|
||||||
with %Object{} = in_reply_to_object <- Object.normalize(in_reply_to, fetch: false) do
|
|
||||||
Map.put(object, "inReplyTo", in_reply_to_object.data["id"])
|
|
||||||
else
|
|
||||||
_ -> object
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def format_naive_asctime(date) do
|
def format_naive_asctime(date) do
|
||||||
date |> DateTime.from_naive!("Etc/UTC") |> format_asctime
|
date |> DateTime.from_naive!("Etc/UTC") |> format_asctime
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,6 +18,8 @@ defmodule Pleroma.Web.Feed.UserController do
|
||||||
def feed_redirect(%{assigns: %{format: "html"}} = conn, %{"nickname" => nickname}) do
|
def feed_redirect(%{assigns: %{format: "html"}} = conn, %{"nickname" => nickname}) do
|
||||||
with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname_or_id(nickname)} do
|
with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname_or_id(nickname)} do
|
||||||
Pleroma.Web.Fallback.RedirectController.redirector_with_meta(conn, %{user: user})
|
Pleroma.Web.Fallback.RedirectController.redirector_with_meta(conn, %{user: user})
|
||||||
|
else
|
||||||
|
_ -> Pleroma.Web.Fallback.RedirectController.redirector(conn, nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.MastoFEController do
|
|
||||||
use Pleroma.Web, :controller
|
|
||||||
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Web.MastodonAPI.AuthController
|
|
||||||
alias Pleroma.Web.OAuth.Token
|
|
||||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
|
||||||
|
|
||||||
plug(OAuthScopesPlug, %{scopes: ["write:accounts"]} when action == :put_settings)
|
|
||||||
|
|
||||||
# Note: :index action handles attempt of unauthenticated access to private instance with redirect
|
|
||||||
plug(:skip_public_check when action == :index)
|
|
||||||
|
|
||||||
plug(
|
|
||||||
OAuthScopesPlug,
|
|
||||||
%{scopes: ["read"], fallback: :proceed_unauthenticated}
|
|
||||||
when action == :index
|
|
||||||
)
|
|
||||||
|
|
||||||
plug(:skip_auth when action == :manifest)
|
|
||||||
|
|
||||||
@doc "GET /web/*path"
|
|
||||||
def index(conn, _params) do
|
|
||||||
with %{assigns: %{user: %User{} = user, token: %Token{app_id: token_app_id} = token}} <- conn,
|
|
||||||
{:ok, %{id: ^token_app_id}} <- AuthController.local_mastofe_app() do
|
|
||||||
conn
|
|
||||||
|> put_layout(false)
|
|
||||||
|> render("index.html",
|
|
||||||
token: token.token,
|
|
||||||
user: user,
|
|
||||||
custom_emojis: Pleroma.Emoji.get_all()
|
|
||||||
)
|
|
||||||
else
|
|
||||||
_ ->
|
|
||||||
conn
|
|
||||||
|> put_session(:return_to, conn.request_path)
|
|
||||||
|> redirect(to: "/web/login")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "GET /web/manifest.json"
|
|
||||||
def manifest(conn, _params) do
|
|
||||||
render(conn, "manifest.json")
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "PUT /api/web/settings: Backend-obscure settings blob for MastoFE, don't parse/reuse elsewhere"
|
|
||||||
def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do
|
|
||||||
with {:ok, _} <- User.mastodon_settings_update(user, settings) do
|
|
||||||
json(conn, %{})
|
|
||||||
else
|
|
||||||
e ->
|
|
||||||
conn
|
|
||||||
|> put_status(:internal_server_error)
|
|
||||||
|> json(%{error: inspect(e)})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -21,8 +21,6 @@ defmodule Pleroma.Web.MastodonAPI.AppController do
|
||||||
|
|
||||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||||
|
|
||||||
@local_mastodon_name "Mastodon-Local"
|
|
||||||
|
|
||||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.AppOperation
|
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.AppOperation
|
||||||
|
|
||||||
@doc "POST /api/v1/apps"
|
@doc "POST /api/v1/apps"
|
||||||
|
@ -35,7 +33,6 @@ def create(%{body_params: params} = conn, _params) do
|
||||||
|> Map.put(:scopes, scopes)
|
|> Map.put(:scopes, scopes)
|
||||||
|
|
||||||
with cs <- App.register_changeset(%App{}, app_attrs),
|
with cs <- App.register_changeset(%App{}, app_attrs),
|
||||||
false <- cs.changes[:client_name] == @local_mastodon_name,
|
|
||||||
{:ok, app} <- Repo.insert(cs) do
|
{:ok, app} <- Repo.insert(cs) do
|
||||||
render(conn, "show.json", app: app)
|
render(conn, "show.json", app: app)
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,77 +7,12 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do
|
||||||
|
|
||||||
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
||||||
|
|
||||||
alias Pleroma.Helpers.AuthHelper
|
|
||||||
alias Pleroma.Helpers.UriHelper
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Web.OAuth.App
|
|
||||||
alias Pleroma.Web.OAuth.Authorization
|
|
||||||
alias Pleroma.Web.OAuth.Token
|
|
||||||
alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken
|
|
||||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||||
|
|
||||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||||
|
|
||||||
plug(Pleroma.Web.Plugs.RateLimiter, [name: :password_reset] when action == :password_reset)
|
plug(Pleroma.Web.Plugs.RateLimiter, [name: :password_reset] when action == :password_reset)
|
||||||
|
|
||||||
@local_mastodon_name "Mastodon-Local"
|
|
||||||
|
|
||||||
@doc "GET /web/login"
|
|
||||||
# Local Mastodon FE login callback action
|
|
||||||
def login(conn, %{"code" => auth_token} = params) do
|
|
||||||
with {:ok, app} <- local_mastofe_app(),
|
|
||||||
{:ok, auth} <- Authorization.get_by_token(app, auth_token),
|
|
||||||
{:ok, oauth_token} <- Token.exchange_token(app, auth) do
|
|
||||||
redirect_to =
|
|
||||||
conn
|
|
||||||
|> local_mastodon_post_login_path()
|
|
||||||
|> UriHelper.modify_uri_params(%{"access_token" => oauth_token.token})
|
|
||||||
|
|
||||||
conn
|
|
||||||
|> AuthHelper.put_session_token(oauth_token.token)
|
|
||||||
|> redirect(to: redirect_to)
|
|
||||||
else
|
|
||||||
_ -> redirect_to_oauth_form(conn, params)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def login(conn, params) do
|
|
||||||
with %{assigns: %{user: %User{}, token: %Token{app_id: app_id}}} <- conn,
|
|
||||||
{:ok, %{id: ^app_id}} <- local_mastofe_app() do
|
|
||||||
redirect(conn, to: local_mastodon_post_login_path(conn))
|
|
||||||
else
|
|
||||||
_ -> redirect_to_oauth_form(conn, params)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp redirect_to_oauth_form(conn, _params) do
|
|
||||||
with {:ok, app} <- local_mastofe_app() do
|
|
||||||
path =
|
|
||||||
Routes.o_auth_path(conn, :authorize,
|
|
||||||
response_type: "code",
|
|
||||||
client_id: app.client_id,
|
|
||||||
redirect_uri: ".",
|
|
||||||
scope: Enum.join(app.scopes, " ")
|
|
||||||
)
|
|
||||||
|
|
||||||
redirect(conn, to: path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "DELETE /auth/sign_out"
|
|
||||||
def logout(conn, _) do
|
|
||||||
conn =
|
|
||||||
with %{assigns: %{token: %Token{} = oauth_token}} <- conn,
|
|
||||||
session_token = AuthHelper.get_session_token(conn),
|
|
||||||
{:ok, %Token{token: ^session_token}} <- RevokeToken.revoke(oauth_token) do
|
|
||||||
AuthHelper.delete_session_token(conn)
|
|
||||||
else
|
|
||||||
_ -> conn
|
|
||||||
end
|
|
||||||
|
|
||||||
redirect(conn, to: "/")
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "POST /auth/password"
|
@doc "POST /auth/password"
|
||||||
def password_reset(conn, params) do
|
def password_reset(conn, params) do
|
||||||
nickname_or_email = params["email"] || params["nickname"]
|
nickname_or_email = params["email"] || params["nickname"]
|
||||||
|
@ -86,23 +21,4 @@ def password_reset(conn, params) do
|
||||||
|
|
||||||
json_response(conn, :no_content, "")
|
json_response(conn, :no_content, "")
|
||||||
end
|
end
|
||||||
|
|
||||||
defp local_mastodon_post_login_path(conn) do
|
|
||||||
case get_session(conn, :return_to) do
|
|
||||||
nil ->
|
|
||||||
Routes.masto_fe_path(conn, :index, ["getting-started"])
|
|
||||||
|
|
||||||
return_to ->
|
|
||||||
delete_session(conn, :return_to)
|
|
||||||
return_to
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec local_mastofe_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
|
|
||||||
def local_mastofe_app do
|
|
||||||
App.get_or_make(
|
|
||||||
%{client_name: @local_mastodon_name, redirect_uris: "."},
|
|
||||||
["read", "write", "follow", "push", "admin"]
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -50,6 +50,7 @@ def index(conn, %{account_id: account_id} = params) do
|
||||||
favourite
|
favourite
|
||||||
move
|
move
|
||||||
pleroma:emoji_reaction
|
pleroma:emoji_reaction
|
||||||
|
poll
|
||||||
}
|
}
|
||||||
def index(%{assigns: %{user: user}} = conn, params) do
|
def index(%{assigns: %{user: user}} = conn, params) do
|
||||||
params =
|
params =
|
||||||
|
|
|
@ -95,7 +95,20 @@ def federation do
|
||||||
{:ok, data} = MRF.describe()
|
{:ok, data} = MRF.describe()
|
||||||
|
|
||||||
data
|
data
|
||||||
|> Map.merge(%{quarantined_instances: quarantined})
|
|> Map.put(
|
||||||
|
:quarantined_instances,
|
||||||
|
Enum.map(quarantined, fn {instance, _reason} -> instance end)
|
||||||
|
)
|
||||||
|
# This is for backwards compatibility. We originally didn't sent
|
||||||
|
# extra info like a reason why an instance was rejected/quarantined/etc.
|
||||||
|
# Because we didn't want to break backwards compatibility it was decided
|
||||||
|
# to add an extra "info" key.
|
||||||
|
|> Map.put(:quarantined_instances_info, %{
|
||||||
|
"quarantined_instances" =>
|
||||||
|
quarantined
|
||||||
|
|> Enum.map(fn {instance, reason} -> {instance, %{"reason" => reason}} end)
|
||||||
|
|> Map.new()
|
||||||
|
})
|
||||||
else
|
else
|
||||||
%{}
|
%{}
|
||||||
end
|
end
|
||||||
|
|
|
@ -112,6 +112,9 @@ def render(
|
||||||
"move" ->
|
"move" ->
|
||||||
put_target(response, activity, reading_user, %{})
|
put_target(response, activity, reading_user, %{})
|
||||||
|
|
||||||
|
"poll" ->
|
||||||
|
put_status(response, activity, reading_user, status_render_opts)
|
||||||
|
|
||||||
"pleroma:emoji_reaction" ->
|
"pleroma:emoji_reaction" ->
|
||||||
response
|
response
|
||||||
|> put_status(parent_activity_fn.(), reading_user, status_render_opts)
|
|> put_status(parent_activity_fn.(), reading_user, status_render_opts)
|
||||||
|
|
|
@ -49,9 +49,7 @@ def init(%{qs: qs} = req, state) do
|
||||||
|
|
||||||
def websocket_init(state) do
|
def websocket_init(state) do
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
"#{__MODULE__} accepted websocket connection for user #{
|
"#{__MODULE__} accepted websocket connection for user #{(state.user || %{id: "anonymous"}).id}, topic #{state.topic}"
|
||||||
(state.user || %{id: "anonymous"}).id
|
|
||||||
}, topic #{state.topic}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Streamer.add_socket(state.topic, state.user)
|
Streamer.add_socket(state.topic, state.user)
|
||||||
|
@ -106,9 +104,7 @@ def terminate(_reason, _req, []), do: :ok
|
||||||
|
|
||||||
def terminate(reason, _req, state) do
|
def terminate(reason, _req, state) do
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
"#{__MODULE__} terminating websocket connection for user #{
|
"#{__MODULE__} terminating websocket connection for user #{(state.user || %{id: "anonymous"}).id}, topic #{state.topic || "?"}: #{inspect(reason)}"
|
||||||
(state.user || %{id: "anonymous"}).id
|
|
||||||
}, topic #{state.topic || "?"}: #{inspect(reason)}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Streamer.remove_socket(state.topic)
|
Streamer.remove_socket(state.topic)
|
||||||
|
|
|
@ -597,9 +597,6 @@ def login(%User{} = user, %App{} = app, requested_scopes) when is_list(requested
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Special case: Local MastodonFE
|
|
||||||
defp redirect_uri(%Plug.Conn{} = conn, "."), do: Routes.auth_url(conn, :login)
|
|
||||||
|
|
||||||
defp redirect_uri(%Plug.Conn{}, redirect_uri), do: redirect_uri
|
defp redirect_uri(%Plug.Conn{}, redirect_uri), do: redirect_uri
|
||||||
|
|
||||||
defp get_session_registration_id(%Plug.Conn{} = conn), do: get_session(conn, :registration_id)
|
defp get_session_registration_id(%Plug.Conn{} = conn), do: get_session(conn, :registration_id)
|
||||||
|
|
23
lib/pleroma/web/plugs/user_is_staff_plug.ex
Normal file
23
lib/pleroma/web/plugs/user_is_staff_plug.ex
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.Plugs.UserIsStaffPlug do
|
||||||
|
import Pleroma.Web.TranslationHelpers
|
||||||
|
import Plug.Conn
|
||||||
|
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
|
def init(options) do
|
||||||
|
options
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(%{assigns: %{user: %User{is_admin: true}}} = conn, _), do: conn
|
||||||
|
def call(%{assigns: %{user: %User{is_moderator: true}}} = conn, _), do: conn
|
||||||
|
|
||||||
|
def call(conn, _) do
|
||||||
|
conn
|
||||||
|
|> render_error(:forbidden, "User is not a staff member.")
|
||||||
|
|> halt()
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.Preload do
|
defmodule Pleroma.Web.Preload do
|
||||||
alias Phoenix.HTML
|
alias Phoenix.HTML
|
||||||
require Logger
|
|
||||||
|
|
||||||
def build_tags(_conn, params) do
|
def build_tags(_conn, params) do
|
||||||
preload_data =
|
preload_data =
|
||||||
|
|
|
@ -124,8 +124,8 @@ def build_content(notification, actor, object, mastodon_type) do
|
||||||
|
|
||||||
def format_body(activity, actor, object, mastodon_type \\ nil)
|
def format_body(activity, actor, object, mastodon_type \\ nil)
|
||||||
|
|
||||||
def format_body(_activity, actor, %{data: %{"type" => "ChatMessage", "content" => content}}, _) do
|
def format_body(_activity, actor, %{data: %{"type" => "ChatMessage"} = data}, _) do
|
||||||
case content do
|
case data["content"] do
|
||||||
nil -> "@#{actor.nickname}: (Attachment)"
|
nil -> "@#{actor.nickname}: (Attachment)"
|
||||||
content -> "@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
|
content -> "@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,7 +26,7 @@ defmodule Pleroma.Web.Push.Subscription do
|
||||||
end
|
end
|
||||||
|
|
||||||
# credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
|
# credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
|
||||||
@supported_alert_types ~w[follow favourite mention reblog pleroma:chat_mention pleroma:emoji_reaction]a
|
@supported_alert_types ~w[follow favourite mention reblog poll pleroma:chat_mention pleroma:emoji_reaction]a
|
||||||
|
|
||||||
defp alerts(%{data: %{alerts: alerts}}) do
|
defp alerts(%{data: %{alerts: alerts}}) do
|
||||||
alerts = Map.take(alerts, @supported_alert_types)
|
alerts = Map.take(alerts, @supported_alert_types)
|
||||||
|
|
|
@ -96,14 +96,12 @@ defmodule Pleroma.Web.Router do
|
||||||
plug(Pleroma.Web.Plugs.AdminSecretAuthenticationPlug)
|
plug(Pleroma.Web.Plugs.AdminSecretAuthenticationPlug)
|
||||||
plug(:after_auth)
|
plug(:after_auth)
|
||||||
plug(Pleroma.Web.Plugs.EnsureAuthenticatedPlug)
|
plug(Pleroma.Web.Plugs.EnsureAuthenticatedPlug)
|
||||||
plug(Pleroma.Web.Plugs.UserIsAdminPlug)
|
plug(Pleroma.Web.Plugs.UserIsStaffPlug)
|
||||||
plug(Pleroma.Web.Plugs.IdempotencyPlug)
|
plug(Pleroma.Web.Plugs.IdempotencyPlug)
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :mastodon_html do
|
pipeline :require_admin do
|
||||||
plug(:browser)
|
plug(Pleroma.Web.Plugs.UserIsAdminPlug)
|
||||||
plug(:authenticate)
|
|
||||||
plug(:after_auth)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :pleroma_html do
|
pipeline :pleroma_html do
|
||||||
|
@ -160,7 +158,7 @@ defmodule Pleroma.Web.Router do
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do
|
scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do
|
||||||
pipe_through(:admin_api)
|
pipe_through([:admin_api, :require_admin])
|
||||||
|
|
||||||
put("/users/disable_mfa", AdminAPIController, :disable_mfa)
|
put("/users/disable_mfa", AdminAPIController, :disable_mfa)
|
||||||
put("/users/tag", AdminAPIController, :tag_users)
|
put("/users/tag", AdminAPIController, :tag_users)
|
||||||
|
@ -213,7 +211,8 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses)
|
get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses)
|
||||||
get("/users/:nickname/chats", AdminAPIController, :list_user_chats)
|
get("/users/:nickname/chats", AdminAPIController, :list_user_chats)
|
||||||
|
|
||||||
get("/instances/:instance/statuses", AdminAPIController, :list_instance_statuses)
|
get("/instances/:instance/statuses", InstanceController, :list_statuses)
|
||||||
|
delete("/instances/:instance", InstanceController, :delete)
|
||||||
|
|
||||||
get("/instance_document/:name", InstanceDocumentController, :show)
|
get("/instance_document/:name", InstanceDocumentController, :show)
|
||||||
patch("/instance_document/:name", InstanceDocumentController, :update)
|
patch("/instance_document/:name", InstanceDocumentController, :update)
|
||||||
|
@ -265,7 +264,7 @@ defmodule Pleroma.Web.Router do
|
||||||
|
|
||||||
scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do
|
scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do
|
||||||
scope "/pack" do
|
scope "/pack" do
|
||||||
pipe_through(:admin_api)
|
pipe_through([:admin_api, :require_admin])
|
||||||
|
|
||||||
post("/", EmojiPackController, :create)
|
post("/", EmojiPackController, :create)
|
||||||
patch("/", EmojiPackController, :update)
|
patch("/", EmojiPackController, :update)
|
||||||
|
@ -280,7 +279,7 @@ defmodule Pleroma.Web.Router do
|
||||||
|
|
||||||
# Modifying packs
|
# Modifying packs
|
||||||
scope "/packs" do
|
scope "/packs" do
|
||||||
pipe_through(:admin_api)
|
pipe_through([:admin_api, :require_admin])
|
||||||
|
|
||||||
get("/import", EmojiPackController, :import_from_filesystem)
|
get("/import", EmojiPackController, :import_from_filesystem)
|
||||||
get("/remote", EmojiPackController, :remote)
|
get("/remote", EmojiPackController, :remote)
|
||||||
|
@ -542,13 +541,6 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/timelines/list/:list_id", TimelineController, :list)
|
get("/timelines/list/:list_id", TimelineController, :list)
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/api/web", Pleroma.Web do
|
|
||||||
pipe_through(:authenticated_api)
|
|
||||||
|
|
||||||
# Backend-obscure settings blob for MastoFE, don't parse/reuse elsewhere
|
|
||||||
put("/settings", MastoFEController, :put_settings)
|
|
||||||
end
|
|
||||||
|
|
||||||
scope "/api/v1", Pleroma.Web.MastodonAPI do
|
scope "/api/v1", Pleroma.Web.MastodonAPI do
|
||||||
pipe_through(:app_api)
|
pipe_through(:app_api)
|
||||||
|
|
||||||
|
@ -744,31 +736,12 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/:version", Nodeinfo.NodeinfoController, :nodeinfo)
|
get("/:version", Nodeinfo.NodeinfoController, :nodeinfo)
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", Pleroma.Web do
|
|
||||||
pipe_through(:api)
|
|
||||||
|
|
||||||
get("/web/manifest.json", MastoFEController, :manifest)
|
|
||||||
end
|
|
||||||
|
|
||||||
scope "/", Pleroma.Web do
|
scope "/", Pleroma.Web do
|
||||||
pipe_through(:api)
|
pipe_through(:api)
|
||||||
|
|
||||||
get("/manifest.json", ManifestController, :show)
|
get("/manifest.json", ManifestController, :show)
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", Pleroma.Web do
|
|
||||||
pipe_through(:mastodon_html)
|
|
||||||
|
|
||||||
get("/web/login", MastodonAPI.AuthController, :login)
|
|
||||||
delete("/auth/sign_out", MastodonAPI.AuthController, :logout)
|
|
||||||
|
|
||||||
post("/auth/password", MastodonAPI.AuthController, :password_reset)
|
|
||||||
|
|
||||||
get("/web/*path", MastoFEController, :index)
|
|
||||||
|
|
||||||
get("/embed/:id", EmbedController, :show)
|
|
||||||
end
|
|
||||||
|
|
||||||
scope "/proxy/", Pleroma.Web do
|
scope "/proxy/", Pleroma.Web do
|
||||||
get("/preview/:sig/:url", MediaProxy.MediaProxyController, :preview)
|
get("/preview/:sig/:url", MediaProxy.MediaProxyController, :preview)
|
||||||
get("/preview/:sig/:url/:filename", MediaProxy.MediaProxyController, :preview)
|
get("/preview/:sig/:url/:filename", MediaProxy.MediaProxyController, :preview)
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang='en'>
|
|
||||||
<head>
|
|
||||||
<meta charset='utf-8'>
|
|
||||||
<meta content='width=device-width, initial-scale=1' name='viewport'>
|
|
||||||
<title>
|
|
||||||
<%= Config.get([:instance, :name]) %>
|
|
||||||
</title>
|
|
||||||
<link rel="icon" type="image/png" href="/favicon.png"/>
|
|
||||||
<link rel="manifest" type="applicaton/manifest+json" href="<%= Routes.masto_fe_path(Pleroma.Web.Endpoint, :manifest) %>" />
|
|
||||||
|
|
||||||
<meta name="theme-color" content="<%= Config.get([:manifest, :theme_color]) %>" />
|
|
||||||
|
|
||||||
<script crossorigin='anonymous' src="/packs/locales.js"></script>
|
|
||||||
<script crossorigin='anonymous' src="/packs/locales/glitch/en.js"></script>
|
|
||||||
|
|
||||||
<link rel='preload' as='script' crossorigin='anonymous' href='/packs/features/getting_started.js'>
|
|
||||||
<link rel='preload' as='script' crossorigin='anonymous' href='/packs/features/compose.js'>
|
|
||||||
<link rel='preload' as='script' crossorigin='anonymous' href='/packs/features/home_timeline.js'>
|
|
||||||
<link rel='preload' as='script' crossorigin='anonymous' href='/packs/features/notifications.js'>
|
|
||||||
<script id='initial-state' type='application/json'><%= initial_state(@token, @user, @custom_emojis) %></script>
|
|
||||||
|
|
||||||
<script src="/packs/core/common.js"></script>
|
|
||||||
<link rel="stylesheet" media="all" href="/packs/core/common.css" />
|
|
||||||
|
|
||||||
<script src="/packs/flavours/glitch/common.js"></script>
|
|
||||||
<link rel="stylesheet" media="all" href="/packs/flavours/glitch/common.css" />
|
|
||||||
|
|
||||||
<script src="/packs/flavours/glitch/home.js"></script>
|
|
||||||
</head>
|
|
||||||
<body class='app-body no-reduce-motion system-font'>
|
|
||||||
<div class='app-holder' data-props='{"locale":"en"}' id='mastodon'>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,91 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.MastoFEView do
|
|
||||||
use Pleroma.Web, :view
|
|
||||||
alias Pleroma.Config
|
|
||||||
alias Pleroma.User
|
|
||||||
alias Pleroma.Web.MastodonAPI.AccountView
|
|
||||||
alias Pleroma.Web.MastodonAPI.CustomEmojiView
|
|
||||||
|
|
||||||
def initial_state(token, user, custom_emojis) do
|
|
||||||
limit = Config.get([:instance, :limit])
|
|
||||||
|
|
||||||
%{
|
|
||||||
meta: %{
|
|
||||||
streaming_api_base_url: Pleroma.Web.Endpoint.websocket_url(),
|
|
||||||
access_token: token,
|
|
||||||
locale: "en",
|
|
||||||
domain: Pleroma.Web.Endpoint.host(),
|
|
||||||
admin: "1",
|
|
||||||
me: "#{user.id}",
|
|
||||||
unfollow_modal: false,
|
|
||||||
boost_modal: false,
|
|
||||||
delete_modal: true,
|
|
||||||
auto_play_gif: false,
|
|
||||||
display_sensitive_media: false,
|
|
||||||
reduce_motion: false,
|
|
||||||
max_toot_chars: limit,
|
|
||||||
mascot: User.get_mascot(user)["url"]
|
|
||||||
},
|
|
||||||
poll_limits: Config.get([:instance, :poll_limits]),
|
|
||||||
rights: %{
|
|
||||||
delete_others_notice: present?(user.is_moderator),
|
|
||||||
admin: present?(user.is_admin)
|
|
||||||
},
|
|
||||||
compose: %{
|
|
||||||
me: "#{user.id}",
|
|
||||||
default_privacy: user.default_scope,
|
|
||||||
default_sensitive: false,
|
|
||||||
allow_content_types: Config.get([:instance, :allowed_post_formats])
|
|
||||||
},
|
|
||||||
media_attachments: %{
|
|
||||||
accept_content_types: [
|
|
||||||
".jpg",
|
|
||||||
".jpeg",
|
|
||||||
".png",
|
|
||||||
".gif",
|
|
||||||
".webm",
|
|
||||||
".mp4",
|
|
||||||
".m4v",
|
|
||||||
"image\/jpeg",
|
|
||||||
"image\/png",
|
|
||||||
"image\/gif",
|
|
||||||
"video\/webm",
|
|
||||||
"video\/mp4"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
settings: user.mastofe_settings || %{},
|
|
||||||
push_subscription: nil,
|
|
||||||
accounts: %{user.id => render(AccountView, "show.json", user: user, for: user)},
|
|
||||||
custom_emojis: render(CustomEmojiView, "index.json", custom_emojis: custom_emojis),
|
|
||||||
char_limit: limit
|
|
||||||
}
|
|
||||||
|> Jason.encode!()
|
|
||||||
|> Phoenix.HTML.raw()
|
|
||||||
end
|
|
||||||
|
|
||||||
defp present?(nil), do: false
|
|
||||||
defp present?(false), do: false
|
|
||||||
defp present?(_), do: true
|
|
||||||
|
|
||||||
def render("manifest.json", _params) do
|
|
||||||
%{
|
|
||||||
name: Config.get([:instance, :name]),
|
|
||||||
description: Config.get([:instance, :description]),
|
|
||||||
icons: Config.get([:manifest, :icons]),
|
|
||||||
theme_color: Config.get([:manifest, :theme_color]),
|
|
||||||
background_color: Config.get([:manifest, :background_color]),
|
|
||||||
display: "standalone",
|
|
||||||
scope: Pleroma.Web.Endpoint.url(),
|
|
||||||
start_url: Routes.masto_fe_path(Pleroma.Web.Endpoint, :index, ["getting-started"]),
|
|
||||||
categories: [
|
|
||||||
"social"
|
|
||||||
],
|
|
||||||
serviceworker: %{
|
|
||||||
src: "/sw.js"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -3,6 +3,7 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Workers.BackgroundWorker do
|
defmodule Pleroma.Workers.BackgroundWorker do
|
||||||
|
alias Pleroma.Instances.Instance
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
use Pleroma.Workers.WorkerHelper, queue: "background"
|
use Pleroma.Workers.WorkerHelper, queue: "background"
|
||||||
|
@ -38,4 +39,8 @@ def perform(%Job{
|
||||||
|
|
||||||
Pleroma.FollowingRelationship.move_following(origin, target)
|
Pleroma.FollowingRelationship.move_following(origin, target)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def perform(%Job{args: %{"op" => "delete_instance", "host" => host}}) do
|
||||||
|
Instance.perform(:delete_instance, host)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
45
lib/pleroma/workers/poll_worker.ex
Normal file
45
lib/pleroma/workers/poll_worker.ex
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Workers.PollWorker do
|
||||||
|
@moduledoc """
|
||||||
|
Generates notifications when a poll ends.
|
||||||
|
"""
|
||||||
|
use Pleroma.Workers.WorkerHelper, queue: "poll_notifications"
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Notification
|
||||||
|
alias Pleroma.Object
|
||||||
|
|
||||||
|
@impl Oban.Worker
|
||||||
|
def perform(%Job{args: %{"op" => "poll_end", "activity_id" => activity_id}}) do
|
||||||
|
with %Activity{} = activity <- find_poll_activity(activity_id) do
|
||||||
|
Notification.create_poll_notifications(activity)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp find_poll_activity(activity_id) do
|
||||||
|
with nil <- Activity.get_by_id(activity_id) do
|
||||||
|
{:error, :poll_activity_not_found}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def schedule_poll_end(%Activity{data: %{"type" => "Create"}, id: activity_id} = activity) do
|
||||||
|
with %Object{data: %{"type" => "Question", "closed" => closed}} when is_binary(closed) <-
|
||||||
|
Object.normalize(activity),
|
||||||
|
{:ok, end_time} <- NaiveDateTime.from_iso8601(closed),
|
||||||
|
:gt <- NaiveDateTime.compare(end_time, NaiveDateTime.utc_now()) do
|
||||||
|
%{
|
||||||
|
op: "poll_end",
|
||||||
|
activity_id: activity_id
|
||||||
|
}
|
||||||
|
|> new(scheduled_at: end_time)
|
||||||
|
|> Oban.insert()
|
||||||
|
else
|
||||||
|
_ -> {:error, activity}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def schedule_poll_end(activity), do: {:error, activity}
|
||||||
|
end
|
12
mix.exs
12
mix.exs
|
@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
|
||||||
def project do
|
def project do
|
||||||
[
|
[
|
||||||
app: :pleroma,
|
app: :pleroma,
|
||||||
version: version("2.4.1"),
|
version: version("2.4.51"),
|
||||||
elixir: "~> 1.9",
|
elixir: "~> 1.9",
|
||||||
elixirc_paths: elixirc_paths(Mix.env()),
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
||||||
|
@ -138,15 +138,15 @@ defp deps do
|
||||||
{:cowlib, "~> 2.9", override: true},
|
{:cowlib, "~> 2.9", override: true},
|
||||||
{:gun, "~> 2.0.0-rc.1", override: true},
|
{:gun, "~> 2.0.0-rc.1", override: true},
|
||||||
{:jason, "~> 1.2"},
|
{:jason, "~> 1.2"},
|
||||||
{:mogrify, "~> 0.7.4"},
|
{:mogrify, "~> 0.9.1"},
|
||||||
{:ex_aws, "~> 2.1.6"},
|
{:ex_aws, "~> 2.1.6"},
|
||||||
{:ex_aws_s3, "~> 2.0"},
|
{:ex_aws_s3, "~> 2.0"},
|
||||||
{:sweet_xml, "~> 0.6.6"},
|
{:sweet_xml, "~> 0.6.6"},
|
||||||
{:earmark, "1.4.15"},
|
{:earmark, "~> 1.4.15"},
|
||||||
{:bbcode_pleroma, "~> 0.2.0"},
|
{:bbcode_pleroma, "~> 0.2.0"},
|
||||||
{:crypt,
|
{:crypt,
|
||||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/crypt.git",
|
git: "https://github.com/msantos/crypt.git",
|
||||||
ref: "cf2aa3f11632e8b0634810a15b3e612c7526f6a3"},
|
ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"},
|
||||||
{:cors_plug, "~> 2.0"},
|
{:cors_plug, "~> 2.0"},
|
||||||
{:web_push_encryption,
|
{:web_push_encryption,
|
||||||
git: "https://github.com/lanodan/elixir-web-push-encryption.git", branch: "bugfix/otp-24"},
|
git: "https://github.com/lanodan/elixir-web-push-encryption.git", branch: "bugfix/otp-24"},
|
||||||
|
@ -158,7 +158,7 @@ defp deps do
|
||||||
{:timex, "~> 3.6"},
|
{:timex, "~> 3.6"},
|
||||||
{:ueberauth, "~> 0.4"},
|
{:ueberauth, "~> 0.4"},
|
||||||
{:linkify, "~> 0.5.1"},
|
{:linkify, "~> 0.5.1"},
|
||||||
{:http_signatures, "~> 0.1.0"},
|
{:http_signatures, "~> 0.1.1"},
|
||||||
{:telemetry, "~> 0.3"},
|
{:telemetry, "~> 0.3"},
|
||||||
{:poolboy, "~> 1.5"},
|
{:poolboy, "~> 1.5"},
|
||||||
{:prometheus, "~> 4.6"},
|
{:prometheus, "~> 4.6"},
|
||||||
|
|
10
mix.lock
10
mix.lock
|
@ -22,13 +22,13 @@
|
||||||
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
|
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
|
||||||
"credo": {:hex, :credo, "1.5.5", "e8f422026f553bc3bebb81c8e8bf1932f498ca03339856c7fec63d3faac8424b", [:mix], [{:bunt, "~> 0.2.0", [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", "dd8623ab7091956a855dc9f3062486add9c52d310dfd62748779c4315d8247de"},
|
"credo": {:hex, :credo, "1.5.5", "e8f422026f553bc3bebb81c8e8bf1932f498ca03339856c7fec63d3faac8424b", [:mix], [{:bunt, "~> 0.2.0", [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", "dd8623ab7091956a855dc9f3062486add9c52d310dfd62748779c4315d8247de"},
|
||||||
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
|
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
"crypt": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/crypt.git", "cf2aa3f11632e8b0634810a15b3e612c7526f6a3", [ref: "cf2aa3f11632e8b0634810a15b3e612c7526f6a3"]},
|
"crypt": {:git, "https://github.com/msantos/crypt.git", "f75cd55325e33cbea198fb41fe41871392f8fb76", [ref: "f75cd55325e33cbea198fb41fe41871392f8fb76"]},
|
||||||
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
|
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
|
||||||
"db_connection": {:hex, :db_connection, "2.4.0", "d04b1b73795dae60cead94189f1b8a51cc9e1f911c234cc23074017c43c031e5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad416c21ad9f61b3103d254a71b63696ecadb6a917b36f563921e0de00d7d7c8"},
|
"db_connection": {:hex, :db_connection, "2.4.0", "d04b1b73795dae60cead94189f1b8a51cc9e1f911c234cc23074017c43c031e5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad416c21ad9f61b3103d254a71b63696ecadb6a917b36f563921e0de00d7d7c8"},
|
||||||
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
|
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
|
||||||
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
|
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
|
||||||
"earmark": {:hex, :earmark, "1.4.15", "2c7f924bf495ec1f65bd144b355d0949a05a254d0ec561740308a54946a67888", [:mix], [{:earmark_parser, ">= 1.4.13", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "3b1209b85bc9f3586f370f7c363f6533788fb4e51db23aa79565875e7f9999ee"},
|
"earmark": {:hex, :earmark, "1.4.18", "618c4ff1563450d1832b7fb41dc6755e470f91a6fd4c70f350a58b14f64a7db8", [:mix], [{:earmark_parser, ">= 1.4.17", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "57ac3b6da3958ed09c669a9b159e86377fcccda56bacde8a209fa4dcdef52560"},
|
||||||
"earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"},
|
"earmark_parser": {:hex, :earmark_parser, "1.4.17", "6f3c7e94170377ba45241d394389e800fb15adc5de51d0a3cd52ae766aafd63f", [:mix], [], "hexpm", "f93ac89c9feca61c165b264b5837bf82344d13bebc634cd575cb711e2e342023"},
|
||||||
"eblurhash": {:hex, :eblurhash, "1.1.0", "e10ccae762598507ebfacf0b645ed49520f2afa3e7e9943e73a91117dffce415", [:rebar3], [], "hexpm", "2e6b889d09fddd374e3c5ac57c486138768763264e99ac1074ae5fa7fc9ab51d"},
|
"eblurhash": {:hex, :eblurhash, "1.1.0", "e10ccae762598507ebfacf0b645ed49520f2afa3e7e9943e73a91117dffce415", [:rebar3], [], "hexpm", "2e6b889d09fddd374e3c5ac57c486138768763264e99ac1074ae5fa7fc9ab51d"},
|
||||||
"ecto": {:hex, :ecto, "3.6.2", "efdf52acfc4ce29249bab5417415bd50abd62db7b0603b8bab0d7b996548c2bc", [: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", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "efad6dfb04e6f986b8a3047822b0f826d9affe8e4ebdd2aeedbfcb14fd48884e"},
|
"ecto": {:hex, :ecto, "3.6.2", "efdf52acfc4ce29249bab5417415bd50abd62db7b0603b8bab0d7b996548c2bc", [: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", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "efad6dfb04e6f986b8a3047822b0f826d9affe8e4ebdd2aeedbfcb14fd48884e"},
|
||||||
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
"hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [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", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"},
|
"hackney": {:hex, :hackney, "1.17.4", "99da4674592504d3fb0cfef0db84c3ba02b4508bae2dff8c0108baa0d6e0977c", [:rebar3], [{:certifi, "~>2.6.1", [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", "de16ff4996556c8548d512f4dbe22dd58a587bf3332e7fd362430a7ef3986b16"},
|
||||||
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
|
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
|
||||||
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
|
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"http_signatures": {:hex, :http_signatures, "0.1.0", "4e4b501a936dbf4cb5222597038a89ea10781776770d2e185849fa829686b34c", [:mix], [], "hexpm", "f8a7b3731e3fd17d38fa6e343fcad7b03d6874a3b0a108c8568a71ed9c2cf824"},
|
"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.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"},
|
||||||
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
"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"},
|
"inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"},
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
|
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
|
||||||
"mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
|
"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"},
|
"mock": {:hex, :mock, "0.3.7", "75b3bbf1466d7e486ea2052a73c6e062c6256fb429d6797999ab02fa32f29e03", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "4da49a4609e41fd99b7836945c26f373623ea968cfb6282742bcb94440cf7e5c"},
|
||||||
"mogrify": {:hex, :mogrify, "0.7.4", "9b2496dde44b1ce12676f85d7dc531900939e6367bc537c7243a1b089435b32d", [:mix], [], "hexpm", "50d79e337fba6bc95bfbef918058c90f50b17eed9537771e61d4619488f099c3"},
|
"mogrify": {:hex, :mogrify, "0.9.1", "a26f107c4987477769f272bd0f7e3ac4b7b75b11ba597fd001b877beffa9c068", [:mix], [], "hexpm", "134edf189337d2125c0948bf0c228fdeef975c594317452d536224069a5b7f05"},
|
||||||
"mox": {:hex, :mox, "1.0.0", "4b3c7005173f47ff30641ba044eb0fe67287743eec9bd9545e37f3002b0a9f8b", [:mix], [], "hexpm", "201b0a20b7abdaaab083e9cf97884950f8a30a1350a1da403b3145e213c6f4df"},
|
"mox": {:hex, :mox, "1.0.0", "4b3c7005173f47ff30641ba044eb0fe67287743eec9bd9545e37f3002b0a9f8b", [:mix], [], "hexpm", "201b0a20b7abdaaab083e9cf97884950f8a30a1350a1da403b3145e213c6f4df"},
|
||||||
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
|
"myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
|
||||||
"nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm", "5c040b8469c1ff1b10093d3186e2e10dbe483cd73d79ec017993fb3985b8a9b3"},
|
"nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm", "5c040b8469c1ff1b10093d3186e2e10dbe483cd73d79ec017993fb3985b8a9b3"},
|
||||||
|
|
580
priv/gettext/id/LC_MESSAGES/errors.po
Normal file
580
priv/gettext/id/LC_MESSAGES/errors.po
Normal file
|
@ -0,0 +1,580 @@
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2021-08-15 15:40+0000\n"
|
||||||
|
"PO-Revision-Date: 2021-09-03 06:45+0000\n"
|
||||||
|
"Last-Translator: @liimee <alt3753.7@gmail.com>\n"
|
||||||
|
"Language-Team: Indonesian <https://translate.pleroma.social/projects/pleroma/"
|
||||||
|
"pleroma/id/>\n"
|
||||||
|
"Language: id\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
|
"X-Generator: Weblate 4.6.2\n"
|
||||||
|
|
||||||
|
## 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 as no
|
||||||
|
## effect: edit them in PO (`.po`) files instead.
|
||||||
|
## From Ecto.Changeset.cast/4
|
||||||
|
msgid "can't be blank"
|
||||||
|
msgstr "tidak boleh kosong"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.unique_constraint/3
|
||||||
|
msgid "has already been taken"
|
||||||
|
msgstr "sudah diambil"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.put_change/3
|
||||||
|
msgid "is invalid"
|
||||||
|
msgstr "tidak valid"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_format/3
|
||||||
|
msgid "has invalid format"
|
||||||
|
msgstr "memiliki format yang tidak valid"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_subset/3
|
||||||
|
msgid "has an invalid entry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_exclusion/3
|
||||||
|
msgid "is reserved"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_confirmation/3
|
||||||
|
msgid "does not match confirmation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.no_assoc_constraint/3
|
||||||
|
msgid "is still associated with this entry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "are still associated with this entry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_length/3
|
||||||
|
msgid "should be %{count} character(s)"
|
||||||
|
msgid_plural "should be %{count} character(s)"
|
||||||
|
msgstr[0] "harus memiliki %{count} karakter"
|
||||||
|
|
||||||
|
msgid "should have %{count} item(s)"
|
||||||
|
msgid_plural "should have %{count} item(s)"
|
||||||
|
msgstr[0] "harus memiliki %{count} item"
|
||||||
|
|
||||||
|
msgid "should be at least %{count} character(s)"
|
||||||
|
msgid_plural "should be at least %{count} character(s)"
|
||||||
|
msgstr[0] "harus memiliki sekurang-kurangnya %{count} karakter"
|
||||||
|
|
||||||
|
msgid "should have at least %{count} item(s)"
|
||||||
|
msgid_plural "should have at least %{count} item(s)"
|
||||||
|
msgstr[0] "harus memiliki sekurang-kurangnya %{count} item"
|
||||||
|
|
||||||
|
msgid "should be at most %{count} character(s)"
|
||||||
|
msgid_plural "should be at most %{count} character(s)"
|
||||||
|
msgstr[0] ""
|
||||||
|
|
||||||
|
msgid "should have at most %{count} item(s)"
|
||||||
|
msgid_plural "should have at most %{count} item(s)"
|
||||||
|
msgstr[0] ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_number/3
|
||||||
|
msgid "must be less than %{number}"
|
||||||
|
msgstr "harus kurang dari %{number}"
|
||||||
|
|
||||||
|
msgid "must be greater than %{number}"
|
||||||
|
msgstr "harus lebih dari %{number}"
|
||||||
|
|
||||||
|
msgid "must be less than or equal to %{number}"
|
||||||
|
msgstr "harus kurang dari atau sama dengan %{number}"
|
||||||
|
|
||||||
|
msgid "must be greater than or equal to %{number}"
|
||||||
|
msgstr "harus lebih dari atau sama dengan %{number}"
|
||||||
|
|
||||||
|
msgid "must be equal to %{number}"
|
||||||
|
msgstr "harus sama dengan %{number}"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:505
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Account not found"
|
||||||
|
msgstr "Akun tidak ditemukan"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:339
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Already voted"
|
||||||
|
msgstr "Sudah memilih"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:359
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Bad request"
|
||||||
|
msgstr "Permintaan buruk (bad request)"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:426
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't delete object"
|
||||||
|
msgstr "Tidak dapat menghapus objek"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/controller_helper.ex:105
|
||||||
|
#: lib/pleroma/web/controller_helper.ex:111
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't display this activity"
|
||||||
|
msgstr "Tidak dapat menampilkan aktivitas ini"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:285
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't find user"
|
||||||
|
msgstr "Tidak dapat mencari pengguna"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:61
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't get favorites"
|
||||||
|
msgstr "Tidak dapat mendapatkan favorit"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:438
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't like object"
|
||||||
|
msgstr "Tidak dapat menyukai objek"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:563
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Cannot post an empty status without attachments"
|
||||||
|
msgstr "Tidak dapat memposting status kosong tanpa lampiran"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:511
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Comment must be up to %{max_size} characters"
|
||||||
|
msgstr "Komentar tidak boleh lebih dari %{max_size} karakter"
|
||||||
|
|
||||||
|
#: lib/pleroma/config/config_db.ex:191
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Config with params %{params} not found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:181
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:185
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not delete"
|
||||||
|
msgstr "Tidak dapat menghapus"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:231
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not favorite"
|
||||||
|
msgstr "Tidak dapat memfavoritkan"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:453
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not pin"
|
||||||
|
msgstr "Tidak dapat menyematkan"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:278
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not unfavorite"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:463
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not unpin"
|
||||||
|
msgstr "Tidak dapat berhenti menyematkan"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:216
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not unrepeat"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:512
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:521
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not update state"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:207
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Error."
|
||||||
|
msgstr "Kesalahan."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:106
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid CAPTCHA"
|
||||||
|
msgstr "CAPTCHA tidak valid"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:116
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:568
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid credentials"
|
||||||
|
msgstr "Kredensian tidak valid"
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid credentials."
|
||||||
|
msgstr "Kredensial tidak valid."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:355
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid indices"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:29
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid parameters"
|
||||||
|
msgstr "Parameter tidak valid"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:414
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid password."
|
||||||
|
msgstr "Kata sandi tidak valid."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:220
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid request"
|
||||||
|
msgstr "Permintaan tidak valid"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:109
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Kocaptcha service unavailable"
|
||||||
|
msgstr "Layanan Kocaptcha tidak tersedia"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:112
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Missing parameters"
|
||||||
|
msgstr "Parameter kurang"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:547
|
||||||
|
#, elixir-format
|
||||||
|
msgid "No such conversation"
|
||||||
|
msgstr "Tidak ada percakapan ini"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:388
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:414 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:456
|
||||||
|
#, elixir-format
|
||||||
|
msgid "No such permission_group"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/uploaded_media.ex:84
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:486 lib/pleroma/web/admin_api/controllers/fallback_controller.ex:11
|
||||||
|
#: lib/pleroma/web/feed/user_controller.ex:71 lib/pleroma/web/ostatus/ostatus_controller.ex:143
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Not found"
|
||||||
|
msgstr "Tidak ditemukan"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:331
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Poll's author can't vote"
|
||||||
|
msgstr "Pembuat japat tidak boleh memilih"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:20
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:37 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:49
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:50 lib/pleroma/web/mastodon_api/controllers/status_controller.ex:306
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:71
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Record not found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:35
|
||||||
|
#: lib/pleroma/web/feed/user_controller.ex:77 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:36
|
||||||
|
#: lib/pleroma/web/ostatus/ostatus_controller.ex:149
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Something went wrong"
|
||||||
|
msgstr "Sesuatu yang salah terjadi"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/activity_draft.ex:107
|
||||||
|
#, elixir-format
|
||||||
|
msgid "The message visibility must be direct"
|
||||||
|
msgstr "Visibilitas pesan harus langsung"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:573
|
||||||
|
#, elixir-format
|
||||||
|
msgid "The status is over the character limit"
|
||||||
|
msgstr "Status lebih dari batas karakter"
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
|
||||||
|
#, elixir-format
|
||||||
|
msgid "This resource requires authentication."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Throttled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:356
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Too many choices"
|
||||||
|
msgstr "Terlalu banyak pilihan"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:443
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unhandled activity type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:485
|
||||||
|
#, elixir-format
|
||||||
|
msgid "You can't revoke your own admin status."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:221
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:308
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Your account is currently disabled"
|
||||||
|
msgstr "Akun Anda saat ini dinonaktifkan"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:183
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:331
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Your login is missing a confirmed e-mail address"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:390
|
||||||
|
#, elixir-format
|
||||||
|
msgid "can't read inbox of %{nickname} as %{as_nickname}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:473
|
||||||
|
#, elixir-format
|
||||||
|
msgid "can't update outbox of %{nickname} as %{as_nickname}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:471
|
||||||
|
#, elixir-format
|
||||||
|
msgid "conversation is already muted"
|
||||||
|
msgstr "percakapan sudah dibisukan"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:314
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:492
|
||||||
|
#, elixir-format
|
||||||
|
msgid "error"
|
||||||
|
msgstr "kesalahan"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:32
|
||||||
|
#, elixir-format
|
||||||
|
msgid "mascots can only be images"
|
||||||
|
msgstr "maskot hanya dapat berbentuk gambar"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:62
|
||||||
|
#, elixir-format
|
||||||
|
msgid "not found"
|
||||||
|
msgstr "tidak ditemukan"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:394
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Bad OAuth request."
|
||||||
|
msgstr "Permintaan OAuth buruk."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:115
|
||||||
|
#, elixir-format
|
||||||
|
msgid "CAPTCHA already used"
|
||||||
|
msgstr "CAPTCHA sudah digunakan"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:112
|
||||||
|
#, elixir-format
|
||||||
|
msgid "CAPTCHA expired"
|
||||||
|
msgstr "CAPTCHA kedaluwarsa"
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/uploaded_media.ex:57
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Failed"
|
||||||
|
msgstr "Gagal"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:410
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Failed to authenticate: %{message}."
|
||||||
|
msgstr "Gagal mengotentikasi: %{message}."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:441
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Failed to set up user account."
|
||||||
|
msgstr "Gagal menyiapkan akun pengguna."
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Insufficient permissions: %{permissions}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/uploaded_media.ex:104
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Internal Error"
|
||||||
|
msgstr "Kesalahan Internal"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/fallback_controller.ex:22
|
||||||
|
#: lib/pleroma/web/oauth/fallback_controller.ex:29
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid Username/Password"
|
||||||
|
msgstr "Nama Pengguna/Kata Sandi Tidak Valid"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:118
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid answer data"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:33
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Nodeinfo schema version not handled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:172
|
||||||
|
#, elixir-format
|
||||||
|
msgid "This action is outside the authorized scopes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/fallback_controller.ex:14
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unknown error, please check the details and try again."
|
||||||
|
msgstr "Kesalahan tidak dikenal, harap periksa keterangannya dan coba lagi."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:119
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:158
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unlisted redirect_uri."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:390
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unsupported OAuth provider: %{provider}."
|
||||||
|
msgstr "Penyedia OAuth tidak didukung: %{provider}."
|
||||||
|
|
||||||
|
#: lib/pleroma/uploaders/uploader.ex:72
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Uploader callback timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/uploader_controller.ex:23
|
||||||
|
#, elixir-format
|
||||||
|
msgid "bad request"
|
||||||
|
msgstr "permintaan buruk (bad request)"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:103
|
||||||
|
#, elixir-format
|
||||||
|
msgid "CAPTCHA Error"
|
||||||
|
msgstr "Kesalahan CAPTCHA"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:290
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not add reaction emoji"
|
||||||
|
msgstr "Tidak dapat menambahkan emoji reaksi"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:301
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not remove reaction emoji"
|
||||||
|
msgstr "Tidak dapat menghapus reaksi emoji"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:129
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid CAPTCHA (Missing parameter: %{name})"
|
||||||
|
msgstr "CAPTCHA Tidak Valid (Parameter kurang: %{name})"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:92
|
||||||
|
#, elixir-format
|
||||||
|
msgid "List not found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:123
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Missing parameter: %{name}"
|
||||||
|
msgstr "Parameter kurang: %{name}"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:210
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:321
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Password reset is required"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/tests/auth_test_controller.ex:9
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:6 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/config_controller.ex:6 lib/pleroma/web/admin_api/controllers/fallback_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/invite_controller.ex:6 lib/pleroma/web/admin_api/controllers/media_proxy_cache_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/oauth_app_controller.ex:6 lib/pleroma/web/admin_api/controllers/relay_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/report_controller.ex:6 lib/pleroma/web/admin_api/controllers/status_controller.ex:6
|
||||||
|
#: lib/pleroma/web/controller_helper.ex:6 lib/pleroma/web/embed_controller.ex:6
|
||||||
|
#: lib/pleroma/web/fallback_redirect_controller.ex:6 lib/pleroma/web/feed/tag_controller.ex:6
|
||||||
|
#: lib/pleroma/web/feed/user_controller.ex:6 lib/pleroma/web/mailer/subscription_controller.ex:2
|
||||||
|
#: lib/pleroma/web/masto_fe_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/account_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/app_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/auth_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/filter_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/instance_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/list_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/marker_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex:14
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/media_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/notification_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/report_controller.ex:8
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/search_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/status_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:7
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:6
|
||||||
|
#: lib/pleroma/web/media_proxy/media_proxy_controller.ex:6 lib/pleroma/web/mongooseim/mongoose_im_controller.ex:6
|
||||||
|
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:6 lib/pleroma/web/oauth/fallback_controller.ex:6
|
||||||
|
#: lib/pleroma/web/oauth/mfa_controller.ex:10 lib/pleroma/web/oauth/oauth_controller.ex:6
|
||||||
|
#: lib/pleroma/web/ostatus/ostatus_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/account_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/chat_controller.ex:5 lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:2 lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/notification_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex:7 lib/pleroma/web/static_fe/static_fe_controller.ex:6
|
||||||
|
#: lib/pleroma/web/twitter_api/controllers/password_controller.ex:10 lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex:6
|
||||||
|
#: lib/pleroma/web/twitter_api/controllers/util_controller.ex:6 lib/pleroma/web/twitter_api/twitter_api_controller.ex:6
|
||||||
|
#: lib/pleroma/web/uploader_controller.ex:6 lib/pleroma/web/web_finger/web_finger_controller.ex:6
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Two-factor authentication enabled, you must use a access token."
|
||||||
|
msgstr "Otentikasi dua-faktor diaktifkan, Anda harus menggunakan token akses."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:210
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while adding file to pack."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:138
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while creating pack."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:278
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while removing file from pack."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:250
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while updating file in pack."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:179
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while updating pack metadata."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Web push subscription is disabled on this Pleroma instance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:451
|
||||||
|
#, elixir-format
|
||||||
|
msgid "You can't revoke your own admin/moderator status."
|
||||||
|
msgstr "Anda tidak bisa mencabut status admin/moderator Anda sendiri."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:126
|
||||||
|
#, elixir-format
|
||||||
|
msgid "authorization required for timeline view"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:24
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Access denied"
|
||||||
|
msgstr "Akses ditolak"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:282
|
||||||
|
#, elixir-format
|
||||||
|
msgid "This API requires an authenticated user"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/user_is_admin_plug.ex:21
|
||||||
|
#, elixir-format
|
||||||
|
msgid "User is not an admin."
|
||||||
|
msgstr "Pengguna bukan seorang admin."
|
580
priv/gettext/ja/LC_MESSAGES/errors.po
Normal file
580
priv/gettext/ja/LC_MESSAGES/errors.po
Normal file
|
@ -0,0 +1,580 @@
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2021-09-18 09:07+0000\n"
|
||||||
|
"PO-Revision-Date: 2021-09-19 09:45+0000\n"
|
||||||
|
"Last-Translator: Ryo Ueno <r.ueno.nfive@gmail.com>\n"
|
||||||
|
"Language-Team: Japanese <https://translate.pleroma.social/projects/pleroma/"
|
||||||
|
"pleroma/ja/>\n"
|
||||||
|
"Language: ja\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
|
"X-Generator: Weblate 4.6.2\n"
|
||||||
|
|
||||||
|
## 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 as no
|
||||||
|
## effect: edit them in PO (`.po`) files instead.
|
||||||
|
## From Ecto.Changeset.cast/4
|
||||||
|
msgid "can't be blank"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.unique_constraint/3
|
||||||
|
msgid "has already been taken"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.put_change/3
|
||||||
|
msgid "is invalid"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_format/3
|
||||||
|
msgid "has invalid format"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_subset/3
|
||||||
|
msgid "has an invalid entry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_exclusion/3
|
||||||
|
msgid "is reserved"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_confirmation/3
|
||||||
|
msgid "does not match confirmation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.no_assoc_constraint/3
|
||||||
|
msgid "is still associated with this entry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "are still associated with this entry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_length/3
|
||||||
|
msgid "should be %{count} character(s)"
|
||||||
|
msgid_plural "should be %{count} character(s)"
|
||||||
|
msgstr[0] ""
|
||||||
|
|
||||||
|
msgid "should have %{count} item(s)"
|
||||||
|
msgid_plural "should have %{count} item(s)"
|
||||||
|
msgstr[0] ""
|
||||||
|
|
||||||
|
msgid "should be at least %{count} character(s)"
|
||||||
|
msgid_plural "should be at least %{count} character(s)"
|
||||||
|
msgstr[0] ""
|
||||||
|
|
||||||
|
msgid "should have at least %{count} item(s)"
|
||||||
|
msgid_plural "should have at least %{count} item(s)"
|
||||||
|
msgstr[0] ""
|
||||||
|
|
||||||
|
msgid "should be at most %{count} character(s)"
|
||||||
|
msgid_plural "should be at most %{count} character(s)"
|
||||||
|
msgstr[0] ""
|
||||||
|
|
||||||
|
msgid "should have at most %{count} item(s)"
|
||||||
|
msgid_plural "should have at most %{count} item(s)"
|
||||||
|
msgstr[0] ""
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_number/3
|
||||||
|
msgid "must be less than %{number}"
|
||||||
|
msgstr "%{number}未満でなければなりません"
|
||||||
|
|
||||||
|
msgid "must be greater than %{number}"
|
||||||
|
msgstr "%{number}より大きくなければなりません"
|
||||||
|
|
||||||
|
msgid "must be less than or equal to %{number}"
|
||||||
|
msgstr "%{number}以下でなければなりません"
|
||||||
|
|
||||||
|
msgid "must be greater than or equal to %{number}"
|
||||||
|
msgstr "%{number}以上でなければなりません"
|
||||||
|
|
||||||
|
msgid "must be equal to %{number}"
|
||||||
|
msgstr "%{number}でなければなりません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:505
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Account not found"
|
||||||
|
msgstr "アカウントがありません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:339
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Already voted"
|
||||||
|
msgstr "投票済みです"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:359
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Bad request"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:426
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't delete object"
|
||||||
|
msgstr "オブジェクトを削除できません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/controller_helper.ex:105
|
||||||
|
#: lib/pleroma/web/controller_helper.ex:111
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't display this activity"
|
||||||
|
msgstr "このアクティビティを表示できません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:285
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't find user"
|
||||||
|
msgstr "ユーザーが見つかりません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:61
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't get favorites"
|
||||||
|
msgstr "お気に入りを取得できません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:438
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't like object"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:563
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Cannot post an empty status without attachments"
|
||||||
|
msgstr "本文または添付ファイルを追加してください"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:511
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Comment must be up to %{max_size} characters"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/config/config_db.ex:191
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Config with params %{params} not found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:181
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:185
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not delete"
|
||||||
|
msgstr "削除できません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:231
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not favorite"
|
||||||
|
msgstr "お気に入り登録できません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:453
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not pin"
|
||||||
|
msgstr "ピン留めできません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:278
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not unfavorite"
|
||||||
|
msgstr "お気に入り解除できません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:463
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not unpin"
|
||||||
|
msgstr "ピン留め解除できません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:216
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not unrepeat"
|
||||||
|
msgstr "リピート解除できません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:512
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:521
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not update state"
|
||||||
|
msgstr "状態を更新できません"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:207
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Error."
|
||||||
|
msgstr "エラー。"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:106
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid CAPTCHA"
|
||||||
|
msgstr "CAPTCHAが間違っています"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:116
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:568
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid credentials"
|
||||||
|
msgstr "認証情報が間違っています"
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid credentials."
|
||||||
|
msgstr "認証情報が間違っています。"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:355
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid indices"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:29
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid parameters"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:414
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid password."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:220
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid request"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:109
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Kocaptcha service unavailable"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:112
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Missing parameters"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:547
|
||||||
|
#, elixir-format
|
||||||
|
msgid "No such conversation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:388
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:414 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:456
|
||||||
|
#, elixir-format
|
||||||
|
msgid "No such permission_group"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/uploaded_media.ex:84
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:486 lib/pleroma/web/admin_api/controllers/fallback_controller.ex:11
|
||||||
|
#: lib/pleroma/web/feed/user_controller.ex:71 lib/pleroma/web/ostatus/ostatus_controller.ex:143
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Not found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:331
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Poll's author can't vote"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:20
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:37 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:49
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:50 lib/pleroma/web/mastodon_api/controllers/status_controller.ex:306
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:71
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Record not found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:35
|
||||||
|
#: lib/pleroma/web/feed/user_controller.ex:77 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:36
|
||||||
|
#: lib/pleroma/web/ostatus/ostatus_controller.ex:149
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Something went wrong"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/activity_draft.ex:107
|
||||||
|
#, elixir-format
|
||||||
|
msgid "The message visibility must be direct"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:573
|
||||||
|
#, elixir-format
|
||||||
|
msgid "The status is over the character limit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
|
||||||
|
#, elixir-format
|
||||||
|
msgid "This resource requires authentication."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Throttled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:356
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Too many choices"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:443
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unhandled activity type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:485
|
||||||
|
#, elixir-format
|
||||||
|
msgid "You can't revoke your own admin status."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:221
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:308
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Your account is currently disabled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:183
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:331
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Your login is missing a confirmed e-mail address"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:390
|
||||||
|
#, elixir-format
|
||||||
|
msgid "can't read inbox of %{nickname} as %{as_nickname}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:473
|
||||||
|
#, elixir-format
|
||||||
|
msgid "can't update outbox of %{nickname} as %{as_nickname}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:471
|
||||||
|
#, elixir-format
|
||||||
|
msgid "conversation is already muted"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:314
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:492
|
||||||
|
#, elixir-format
|
||||||
|
msgid "error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:32
|
||||||
|
#, elixir-format
|
||||||
|
msgid "mascots can only be images"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:62
|
||||||
|
#, elixir-format
|
||||||
|
msgid "not found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:394
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Bad OAuth request."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:115
|
||||||
|
#, elixir-format
|
||||||
|
msgid "CAPTCHA already used"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:112
|
||||||
|
#, elixir-format
|
||||||
|
msgid "CAPTCHA expired"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/uploaded_media.ex:57
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:410
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Failed to authenticate: %{message}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:441
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Failed to set up user account."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Insufficient permissions: %{permissions}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/uploaded_media.ex:104
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Internal Error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/fallback_controller.ex:22
|
||||||
|
#: lib/pleroma/web/oauth/fallback_controller.ex:29
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid Username/Password"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:118
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid answer data"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:33
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Nodeinfo schema version not handled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:172
|
||||||
|
#, elixir-format
|
||||||
|
msgid "This action is outside the authorized scopes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/fallback_controller.ex:14
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unknown error, please check the details and try again."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:119
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:158
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unlisted redirect_uri."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:390
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unsupported OAuth provider: %{provider}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/uploaders/uploader.ex:72
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Uploader callback timeout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/uploader_controller.ex:23
|
||||||
|
#, elixir-format
|
||||||
|
msgid "bad request"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:103
|
||||||
|
#, elixir-format
|
||||||
|
msgid "CAPTCHA Error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:290
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not add reaction emoji"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:301
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not remove reaction emoji"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:129
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid CAPTCHA (Missing parameter: %{name})"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:92
|
||||||
|
#, elixir-format
|
||||||
|
msgid "List not found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:123
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Missing parameter: %{name}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:210
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:321
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Password reset is required"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/tests/auth_test_controller.ex:9
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:6 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/config_controller.ex:6 lib/pleroma/web/admin_api/controllers/fallback_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/invite_controller.ex:6 lib/pleroma/web/admin_api/controllers/media_proxy_cache_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/oauth_app_controller.ex:6 lib/pleroma/web/admin_api/controllers/relay_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/report_controller.ex:6 lib/pleroma/web/admin_api/controllers/status_controller.ex:6
|
||||||
|
#: lib/pleroma/web/controller_helper.ex:6 lib/pleroma/web/embed_controller.ex:6
|
||||||
|
#: lib/pleroma/web/fallback_redirect_controller.ex:6 lib/pleroma/web/feed/tag_controller.ex:6
|
||||||
|
#: lib/pleroma/web/feed/user_controller.ex:6 lib/pleroma/web/mailer/subscription_controller.ex:2
|
||||||
|
#: lib/pleroma/web/masto_fe_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/account_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/app_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/auth_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/filter_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/instance_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/list_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/marker_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex:14
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/media_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/notification_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/report_controller.ex:8
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/search_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/status_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:7
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:6
|
||||||
|
#: lib/pleroma/web/media_proxy/media_proxy_controller.ex:6 lib/pleroma/web/mongooseim/mongoose_im_controller.ex:6
|
||||||
|
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:6 lib/pleroma/web/oauth/fallback_controller.ex:6
|
||||||
|
#: lib/pleroma/web/oauth/mfa_controller.ex:10 lib/pleroma/web/oauth/oauth_controller.ex:6
|
||||||
|
#: lib/pleroma/web/ostatus/ostatus_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/account_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/chat_controller.ex:5 lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:2 lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/notification_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex:7 lib/pleroma/web/static_fe/static_fe_controller.ex:6
|
||||||
|
#: lib/pleroma/web/twitter_api/controllers/password_controller.ex:10 lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex:6
|
||||||
|
#: lib/pleroma/web/twitter_api/controllers/util_controller.ex:6 lib/pleroma/web/twitter_api/twitter_api_controller.ex:6
|
||||||
|
#: lib/pleroma/web/uploader_controller.ex:6 lib/pleroma/web/web_finger/web_finger_controller.ex:6
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Two-factor authentication enabled, you must use a access token."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:210
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while adding file to pack."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:138
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while creating pack."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:278
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while removing file from pack."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:250
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while updating file in pack."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:179
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while updating pack metadata."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Web push subscription is disabled on this Pleroma instance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:451
|
||||||
|
#, elixir-format
|
||||||
|
msgid "You can't revoke your own admin/moderator status."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:126
|
||||||
|
#, elixir-format
|
||||||
|
msgid "authorization required for timeline view"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:24
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Access denied"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:282
|
||||||
|
#, elixir-format
|
||||||
|
msgid "This API requires an authenticated user"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/user_is_admin_plug.ex:21
|
||||||
|
#, elixir-format
|
||||||
|
msgid "User is not an admin."
|
||||||
|
msgstr ""
|
|
@ -3,8 +3,8 @@ msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2020-05-13 16:37+0000\n"
|
"POT-Creation-Date: 2020-05-13 16:37+0000\n"
|
||||||
"PO-Revision-Date: 2020-07-09 14:40+0000\n"
|
"PO-Revision-Date: 2021-08-15 08:45+0000\n"
|
||||||
"Last-Translator: Ben Is <srsbzns@cock.li>\n"
|
"Last-Translator: marcin mikołajczak <me@mkljczk.pl>\n"
|
||||||
"Language-Team: Polish <https://translate.pleroma.social/projects/pleroma/"
|
"Language-Team: Polish <https://translate.pleroma.social/projects/pleroma/"
|
||||||
"pleroma/pl/>\n"
|
"pleroma/pl/>\n"
|
||||||
"Language: pl\n"
|
"Language: pl\n"
|
||||||
|
@ -13,7 +13,7 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||||
"|| n%100>=20) ? 1 : 2;\n"
|
"|| n%100>=20) ? 1 : 2;\n"
|
||||||
"X-Generator: Weblate 4.0.4\n"
|
"X-Generator: Weblate 4.6.2\n"
|
||||||
|
|
||||||
## This file is a PO Template file.
|
## This file is a PO Template file.
|
||||||
##
|
##
|
||||||
|
@ -68,49 +68,49 @@ msgstr[2] "powinno mieć %{count} znaków"
|
||||||
|
|
||||||
msgid "should have %{count} item(s)"
|
msgid "should have %{count} item(s)"
|
||||||
msgid_plural "should have %{count} item(s)"
|
msgid_plural "should have %{count} item(s)"
|
||||||
msgstr[0] ""
|
msgstr[0] "powinno zawierać %{count} element"
|
||||||
msgstr[1] ""
|
msgstr[1] "powinno zawierać %{count} elementy"
|
||||||
msgstr[2] ""
|
msgstr[2] "powinno zawierać %{count} elementów"
|
||||||
|
|
||||||
msgid "should be at least %{count} character(s)"
|
msgid "should be at least %{count} character(s)"
|
||||||
msgid_plural "should be at least %{count} character(s)"
|
msgid_plural "should be at least %{count} character(s)"
|
||||||
msgstr[0] ""
|
msgstr[0] "powinno zawierać przynajmniej %{count} znak"
|
||||||
msgstr[1] ""
|
msgstr[1] "powinno zawierać przynajmniej %{count} znaki"
|
||||||
msgstr[2] ""
|
msgstr[2] "powinno zawierać przynajmniej %{count} znaków"
|
||||||
|
|
||||||
msgid "should have at least %{count} item(s)"
|
msgid "should have at least %{count} item(s)"
|
||||||
msgid_plural "should have at least %{count} item(s)"
|
msgid_plural "should have at least %{count} item(s)"
|
||||||
msgstr[0] ""
|
msgstr[0] "powinno zawierać przynajmniej %{count} element"
|
||||||
msgstr[1] ""
|
msgstr[1] "powinno zawierać przynajmniej %{count} elementy"
|
||||||
msgstr[2] ""
|
msgstr[2] "powinno zawierać przynajmniej %{count} elementów"
|
||||||
|
|
||||||
msgid "should be at most %{count} character(s)"
|
msgid "should be at most %{count} character(s)"
|
||||||
msgid_plural "should be at most %{count} character(s)"
|
msgid_plural "should be at most %{count} character(s)"
|
||||||
msgstr[0] ""
|
msgstr[0] "powinno zawierać najwyżej %{count} znak"
|
||||||
msgstr[1] ""
|
msgstr[1] "powinno zawierać najwyżej %{count} znaki"
|
||||||
msgstr[2] ""
|
msgstr[2] "powinno zawierać najwyżej %{count} znaków"
|
||||||
|
|
||||||
msgid "should have at most %{count} item(s)"
|
msgid "should have at most %{count} item(s)"
|
||||||
msgid_plural "should have at most %{count} item(s)"
|
msgid_plural "should have at most %{count} item(s)"
|
||||||
msgstr[0] ""
|
msgstr[0] "powinno zawierać najwyżej %{count} element"
|
||||||
msgstr[1] ""
|
msgstr[1] "powinno zawierać najwyżej %{count} elementy"
|
||||||
msgstr[2] ""
|
msgstr[2] "powinno zawierać najwyżej %{count} elementów"
|
||||||
|
|
||||||
## From Ecto.Changeset.validate_number/3
|
## From Ecto.Changeset.validate_number/3
|
||||||
msgid "must be less than %{number}"
|
msgid "must be less than %{number}"
|
||||||
msgstr ""
|
msgstr "musi wynosić mniej niż %{number}"
|
||||||
|
|
||||||
msgid "must be greater than %{number}"
|
msgid "must be greater than %{number}"
|
||||||
msgstr ""
|
msgstr "musi wynosić więcej niż %{number}"
|
||||||
|
|
||||||
msgid "must be less than or equal to %{number}"
|
msgid "must be less than or equal to %{number}"
|
||||||
msgstr ""
|
msgstr "musi być mniejsze lub równe %{number}"
|
||||||
|
|
||||||
msgid "must be greater than or equal to %{number}"
|
msgid "must be greater than or equal to %{number}"
|
||||||
msgstr ""
|
msgstr "musi być większe lub równe %{number}"
|
||||||
|
|
||||||
msgid "must be equal to %{number}"
|
msgid "must be equal to %{number}"
|
||||||
msgstr ""
|
msgstr "musi być równe %{number}"
|
||||||
|
|
||||||
#: lib/pleroma/web/common_api/common_api.ex:421
|
#: lib/pleroma/web/common_api/common_api.ex:421
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -152,7 +152,7 @@ msgstr "Nie znaleziono użytkownika"
|
||||||
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:114
|
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:114
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Can't get favorites"
|
msgid "Can't get favorites"
|
||||||
msgstr ""
|
msgstr "Nie można uzyskać ulubionych"
|
||||||
|
|
||||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:437
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:437
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -172,7 +172,7 @@ msgstr "Komentarz może mieć co najwyżej %{max_size} znaków"
|
||||||
#: lib/pleroma/config/config_db.ex:222
|
#: lib/pleroma/config/config_db.ex:222
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Config with params %{params} not found"
|
msgid "Config with params %{params} not found"
|
||||||
msgstr ""
|
msgstr "Nie znaleziono konfiguracji z parametrami %{params}"
|
||||||
|
|
||||||
#: lib/pleroma/web/common_api/common_api.ex:95
|
#: lib/pleroma/web/common_api/common_api.ex:95
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -213,38 +213,38 @@ msgstr "Nie udało się cofnąć powtórzenia"
|
||||||
#: lib/pleroma/web/common_api/common_api.ex:437
|
#: lib/pleroma/web/common_api/common_api.ex:437
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Could not update state"
|
msgid "Could not update state"
|
||||||
msgstr ""
|
msgstr "Nie można zaktualizować stanu"
|
||||||
|
|
||||||
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:202
|
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:202
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Error."
|
msgid "Error."
|
||||||
msgstr ""
|
msgstr "Błąd."
|
||||||
|
|
||||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:106
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:106
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Invalid CAPTCHA"
|
msgid "Invalid CAPTCHA"
|
||||||
msgstr ""
|
msgstr "Niewłaściwa CAPTCHA"
|
||||||
|
|
||||||
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:117
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:117
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:569
|
#: lib/pleroma/web/oauth/oauth_controller.ex:569
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Invalid credentials"
|
msgid "Invalid credentials"
|
||||||
msgstr ""
|
msgstr "Nieprawidłowe dane uwierzytelniania"
|
||||||
|
|
||||||
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
|
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Invalid credentials."
|
msgid "Invalid credentials."
|
||||||
msgstr ""
|
msgstr "Nieprawidłowe dane uwierzytelniania."
|
||||||
|
|
||||||
#: lib/pleroma/web/common_api/common_api.ex:265
|
#: lib/pleroma/web/common_api/common_api.ex:265
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Invalid indices"
|
msgid "Invalid indices"
|
||||||
msgstr ""
|
msgstr "Nieprawidłowe indeksy"
|
||||||
|
|
||||||
#: lib/pleroma/web/admin_api/admin_api_controller.ex:1147
|
#: lib/pleroma/web/admin_api/admin_api_controller.ex:1147
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Invalid parameters"
|
msgid "Invalid parameters"
|
||||||
msgstr ""
|
msgstr "Nieprawidłowe parametry"
|
||||||
|
|
||||||
#: lib/pleroma/web/common_api/utils.ex:411
|
#: lib/pleroma/web/common_api/utils.ex:411
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -307,7 +307,7 @@ msgstr "Coś się zepsuło"
|
||||||
#: lib/pleroma/web/common_api/activity_draft.ex:107
|
#: lib/pleroma/web/common_api/activity_draft.ex:107
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "The message visibility must be direct"
|
msgid "The message visibility must be direct"
|
||||||
msgstr ""
|
msgstr "Widoczność wiadomości musi być „Bezpośrednia”"
|
||||||
|
|
||||||
#: lib/pleroma/web/common_api/utils.ex:566
|
#: lib/pleroma/web/common_api/utils.ex:566
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -317,17 +317,17 @@ msgstr "Ten status przekracza limit znaków"
|
||||||
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
|
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "This resource requires authentication."
|
msgid "This resource requires authentication."
|
||||||
msgstr ""
|
msgstr "Ten zasób wymaga uwierzytelnienia."
|
||||||
|
|
||||||
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
|
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Throttled"
|
msgid "Throttled"
|
||||||
msgstr ""
|
msgstr "Ograniczono"
|
||||||
|
|
||||||
#: lib/pleroma/web/common_api/common_api.ex:266
|
#: lib/pleroma/web/common_api/common_api.ex:266
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Too many choices"
|
msgid "Too many choices"
|
||||||
msgstr ""
|
msgstr "Zbyt wiele wyborów"
|
||||||
|
|
||||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:442
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:442
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -349,17 +349,18 @@ msgstr "Twoje konto jest obecnie nieaktywne"
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:332
|
#: lib/pleroma/web/oauth/oauth_controller.ex:332
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Your login is missing a confirmed e-mail address"
|
msgid "Your login is missing a confirmed e-mail address"
|
||||||
msgstr ""
|
msgstr "Twój adres e-mail nie został potwierdzony"
|
||||||
|
|
||||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:389
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:389
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "can't read inbox of %{nickname} as %{as_nickname}"
|
msgid "can't read inbox of %{nickname} as %{as_nickname}"
|
||||||
msgstr ""
|
msgstr "Nie można odczytać skrzynki odbiorczej %{nickname} jako %{as_nickname}"
|
||||||
|
|
||||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:472
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:472
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "can't update outbox of %{nickname} as %{as_nickname}"
|
msgid "can't update outbox of %{nickname} as %{as_nickname}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Nie można zaktualizować skrzynki nadawczcej %{nickname} jako %{as_nickname}"
|
||||||
|
|
||||||
#: lib/pleroma/web/common_api/common_api.ex:388
|
#: lib/pleroma/web/common_api/common_api.ex:388
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -405,12 +406,12 @@ msgstr "Nie udało się"
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:411
|
#: lib/pleroma/web/oauth/oauth_controller.ex:411
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Failed to authenticate: %{message}."
|
msgid "Failed to authenticate: %{message}."
|
||||||
msgstr ""
|
msgstr "Nie udało się uwierzytelnić: %{message}."
|
||||||
|
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:442
|
#: lib/pleroma/web/oauth/oauth_controller.ex:442
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Failed to set up user account."
|
msgid "Failed to set up user account."
|
||||||
msgstr ""
|
msgstr "Nie udało się skonfigurować konta użytkownika."
|
||||||
|
|
||||||
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
|
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -431,7 +432,7 @@ msgstr "Nieprawidłowa nazwa użytkownika lub hasło"
|
||||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:118
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:118
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Invalid answer data"
|
msgid "Invalid answer data"
|
||||||
msgstr ""
|
msgstr "Nieprawidłowe dane odpowiedzi"
|
||||||
|
|
||||||
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:128
|
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:128
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -441,7 +442,7 @@ msgstr "Nieobsługiwana wersja schematu Nodeinfo"
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:169
|
#: lib/pleroma/web/oauth/oauth_controller.ex:169
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "This action is outside the authorized scopes"
|
msgid "This action is outside the authorized scopes"
|
||||||
msgstr ""
|
msgstr "Ta akcja wykracza poza dozwolone zakresy"
|
||||||
|
|
||||||
#: lib/pleroma/web/oauth/fallback_controller.ex:14
|
#: lib/pleroma/web/oauth/fallback_controller.ex:14
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -452,7 +453,7 @@ msgstr "Nieznany błąd, sprawdź szczegóły i spróbuj ponownie."
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:155
|
#: lib/pleroma/web/oauth/oauth_controller.ex:155
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Unlisted redirect_uri."
|
msgid "Unlisted redirect_uri."
|
||||||
msgstr ""
|
msgstr "Niewypisany redirect_uri."
|
||||||
|
|
||||||
#: lib/pleroma/web/oauth/oauth_controller.ex:391
|
#: lib/pleroma/web/oauth/oauth_controller.ex:391
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -462,7 +463,7 @@ msgstr "Nieobsługiwany dostawca OAuth: %{provider}."
|
||||||
#: lib/pleroma/uploaders/uploader.ex:72
|
#: lib/pleroma/uploaders/uploader.ex:72
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Uploader callback timeout"
|
msgid "Uploader callback timeout"
|
||||||
msgstr ""
|
msgstr "Przekroczono czas wysyłania pliku"
|
||||||
|
|
||||||
#: lib/pleroma/web/uploader_controller.ex:23
|
#: lib/pleroma/web/uploader_controller.ex:23
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -477,12 +478,12 @@ msgstr "Błąd CAPTCHA"
|
||||||
#: lib/pleroma/web/common_api/common_api.ex:200
|
#: lib/pleroma/web/common_api/common_api.ex:200
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Could not add reaction emoji"
|
msgid "Could not add reaction emoji"
|
||||||
msgstr ""
|
msgstr "Nie można dodać reakcji emoji"
|
||||||
|
|
||||||
#: lib/pleroma/web/common_api/common_api.ex:211
|
#: lib/pleroma/web/common_api/common_api.ex:211
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Could not remove reaction emoji"
|
msgid "Could not remove reaction emoji"
|
||||||
msgstr ""
|
msgstr "Nie można usunąć reakcji emoji"
|
||||||
|
|
||||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:129
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:129
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -535,6 +536,8 @@ msgstr "Wymagany reset hasła"
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
|
msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Naruszenie bezpieczeństwa: sprawdzanie zakresów OAuth nie zostało ani "
|
||||||
|
"wykonane, ani celowo pominięte."
|
||||||
|
|
||||||
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
|
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
@ -569,7 +572,7 @@ msgstr "Nieoczekiwany błąd podczas zmieniania metadanych paczki."
|
||||||
#: lib/pleroma/plugs/user_is_admin_plug.ex:21
|
#: lib/pleroma/plugs/user_is_admin_plug.ex:21
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
msgid "User is not an admin."
|
msgid "User is not an admin."
|
||||||
msgstr ""
|
msgstr "Użytkownik nie jest administratorem."
|
||||||
|
|
||||||
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
|
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
|
||||||
#, elixir-format
|
#, elixir-format
|
||||||
|
|
580
priv/gettext/vi/LC_MESSAGES/errors.po
Normal file
580
priv/gettext/vi/LC_MESSAGES/errors.po
Normal file
|
@ -0,0 +1,580 @@
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2021-09-06 11:13+0000\n"
|
||||||
|
"PO-Revision-Date: 2021-09-07 16:42+0000\n"
|
||||||
|
"Last-Translator: Hồ Nhất Duy <kantcer@gmail.com>\n"
|
||||||
|
"Language-Team: Vietnamese <https://translate.pleroma.social/projects/pleroma/"
|
||||||
|
"pleroma/vi/>\n"
|
||||||
|
"Language: vi\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
|
"X-Generator: Weblate 4.6.2\n"
|
||||||
|
|
||||||
|
## 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 as no
|
||||||
|
## effect: edit them in PO (`.po`) files instead.
|
||||||
|
## From Ecto.Changeset.cast/4
|
||||||
|
msgid "can't be blank"
|
||||||
|
msgstr "không được để trống"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.unique_constraint/3
|
||||||
|
msgid "has already been taken"
|
||||||
|
msgstr "đã có người sử dụng"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.put_change/3
|
||||||
|
msgid "is invalid"
|
||||||
|
msgstr "không khớp"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_format/3
|
||||||
|
msgid "has invalid format"
|
||||||
|
msgstr "định dạng không hợp lệ"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_subset/3
|
||||||
|
msgid "has an invalid entry"
|
||||||
|
msgstr "có mục sai"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_exclusion/3
|
||||||
|
msgid "is reserved"
|
||||||
|
msgstr "đảo ngược"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_confirmation/3
|
||||||
|
msgid "does not match confirmation"
|
||||||
|
msgstr "không trùng khớp"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.no_assoc_constraint/3
|
||||||
|
msgid "is still associated with this entry"
|
||||||
|
msgstr "vẫn liên kết với mục này"
|
||||||
|
|
||||||
|
msgid "are still associated with this entry"
|
||||||
|
msgstr "vẫn liên kết với mục này"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_length/3
|
||||||
|
msgid "should be %{count} character(s)"
|
||||||
|
msgid_plural "should be %{count} character(s)"
|
||||||
|
msgstr[0] "tối thiểu %{count} ký tự"
|
||||||
|
|
||||||
|
msgid "should have %{count} item(s)"
|
||||||
|
msgid_plural "should have %{count} item(s)"
|
||||||
|
msgstr[0] "tối thiểu %{count} mục"
|
||||||
|
|
||||||
|
msgid "should be at least %{count} character(s)"
|
||||||
|
msgid_plural "should be at least %{count} character(s)"
|
||||||
|
msgstr[0] "tối thiểu %{count} ký tự"
|
||||||
|
|
||||||
|
msgid "should have at least %{count} item(s)"
|
||||||
|
msgid_plural "should have at least %{count} item(s)"
|
||||||
|
msgstr[0] "tối thiểu %{count} mục"
|
||||||
|
|
||||||
|
msgid "should be at most %{count} character(s)"
|
||||||
|
msgid_plural "should be at most %{count} character(s)"
|
||||||
|
msgstr[0] "tối đa %{count} ký tự"
|
||||||
|
|
||||||
|
msgid "should have at most %{count} item(s)"
|
||||||
|
msgid_plural "should have at most %{count} item(s)"
|
||||||
|
msgstr[0] "tối đa %{count} mục"
|
||||||
|
|
||||||
|
## From Ecto.Changeset.validate_number/3
|
||||||
|
msgid "must be less than %{number}"
|
||||||
|
msgstr "phải nhỏ hơn %{number}"
|
||||||
|
|
||||||
|
msgid "must be greater than %{number}"
|
||||||
|
msgstr "phải lớn hơn %{number}"
|
||||||
|
|
||||||
|
msgid "must be less than or equal to %{number}"
|
||||||
|
msgstr "phải nhỏ hơn hoặc bằng %{number}"
|
||||||
|
|
||||||
|
msgid "must be greater than or equal to %{number}"
|
||||||
|
msgstr "phải lớn hơn hoặc bằng %{number}"
|
||||||
|
|
||||||
|
msgid "must be equal to %{number}"
|
||||||
|
msgstr "phải là %{number}"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:505
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Account not found"
|
||||||
|
msgstr "Không tìm thấy tài khoản"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:339
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Already voted"
|
||||||
|
msgstr "Đã bình chọn"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:359
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Bad request"
|
||||||
|
msgstr "Lỗi truy vấn"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:426
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't delete object"
|
||||||
|
msgstr "Không thể xóa đối tượng"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/controller_helper.ex:105
|
||||||
|
#: lib/pleroma/web/controller_helper.ex:111
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't display this activity"
|
||||||
|
msgstr "Không thể hiển thị hoạt động này"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:285
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't find user"
|
||||||
|
msgstr "Không tìm thấy người dùng"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:61
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't get favorites"
|
||||||
|
msgstr "Không thể tải lượt thích"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:438
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Can't like object"
|
||||||
|
msgstr "Không thể thích đối tượng"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:563
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Cannot post an empty status without attachments"
|
||||||
|
msgstr "Không thể đăng một tút trống trơn"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:511
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Comment must be up to %{max_size} characters"
|
||||||
|
msgstr "Bình luận tối đa %{max_size} ký tự"
|
||||||
|
|
||||||
|
#: lib/pleroma/config/config_db.ex:191
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Config with params %{params} not found"
|
||||||
|
msgstr "Không tìm thấy cấu hình %{params}"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:181
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:185
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not delete"
|
||||||
|
msgstr "Không thể xóa"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:231
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not favorite"
|
||||||
|
msgstr "Không thể thích"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:453
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not pin"
|
||||||
|
msgstr "Không thể ghim"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:278
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not unfavorite"
|
||||||
|
msgstr "Không thể bỏ thích"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:463
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not unpin"
|
||||||
|
msgstr "Không thể bỏ ghim"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:216
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not unrepeat"
|
||||||
|
msgstr "Không thể hủy chia sẻ"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:512
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:521
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not update state"
|
||||||
|
msgstr "Không thể cập nhật trạng thái"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:207
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Error."
|
||||||
|
msgstr "Lỗi."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:106
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid CAPTCHA"
|
||||||
|
msgstr "CAPTCHA không hợp lệ"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:116
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:568
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid credentials"
|
||||||
|
msgstr "Danh tính không hợp lệ"
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid credentials."
|
||||||
|
msgstr "Danh tính không hợp lệ."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:355
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid indices"
|
||||||
|
msgstr "Sai dấu hiệu"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:29
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid parameters"
|
||||||
|
msgstr "Sai tham số"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:414
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid password."
|
||||||
|
msgstr "Sai mật khẩu."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:220
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid request"
|
||||||
|
msgstr "Yêu cầu không hợp lệ"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:109
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Kocaptcha service unavailable"
|
||||||
|
msgstr "Dịch vụ Kocaptcha chưa sẵn sàng"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:112
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Missing parameters"
|
||||||
|
msgstr "Thiếu tham số"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:547
|
||||||
|
#, elixir-format
|
||||||
|
msgid "No such conversation"
|
||||||
|
msgstr "Không chuyển đổi"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:388
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:414 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:456
|
||||||
|
#, elixir-format
|
||||||
|
msgid "No such permission_group"
|
||||||
|
msgstr "Không permission_group"
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/uploaded_media.ex:84
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:486 lib/pleroma/web/admin_api/controllers/fallback_controller.ex:11
|
||||||
|
#: lib/pleroma/web/feed/user_controller.ex:71 lib/pleroma/web/ostatus/ostatus_controller.ex:143
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Not found"
|
||||||
|
msgstr "Không tìm thấy"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:331
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Poll's author can't vote"
|
||||||
|
msgstr "Người tạo bình chọn không thể bình chọn"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:20
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:37 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:49
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:50 lib/pleroma/web/mastodon_api/controllers/status_controller.ex:306
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:71
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Record not found"
|
||||||
|
msgstr "Không tìm thấy gì hết"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:35
|
||||||
|
#: lib/pleroma/web/feed/user_controller.ex:77 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:36
|
||||||
|
#: lib/pleroma/web/ostatus/ostatus_controller.ex:149
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Something went wrong"
|
||||||
|
msgstr "Có lỗi xảy ra"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/activity_draft.ex:107
|
||||||
|
#, elixir-format
|
||||||
|
msgid "The message visibility must be direct"
|
||||||
|
msgstr "Tin nhắn phải là trực tiếp"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/utils.ex:573
|
||||||
|
#, elixir-format
|
||||||
|
msgid "The status is over the character limit"
|
||||||
|
msgstr "Tút vượt quá giới hạn ký tự"
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
|
||||||
|
#, elixir-format
|
||||||
|
msgid "This resource requires authentication."
|
||||||
|
msgstr "Tài nguyên này yêu cầu xác thực."
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Throttled"
|
||||||
|
msgstr "Đã điều tiết"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:356
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Too many choices"
|
||||||
|
msgstr "Quá nhiều lựa chọn"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:443
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unhandled activity type"
|
||||||
|
msgstr "Không thể xử lý loại hoạt động"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:485
|
||||||
|
#, elixir-format
|
||||||
|
msgid "You can't revoke your own admin status."
|
||||||
|
msgstr "Không thể tự gỡ chức vụ quản trị viên"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:221
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:308
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Your account is currently disabled"
|
||||||
|
msgstr "Tài khoản của bạn bị ẩn"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:183
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:331
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Your login is missing a confirmed e-mail address"
|
||||||
|
msgstr "Bạn chưa xác thực địa chỉ email"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:390
|
||||||
|
#, elixir-format
|
||||||
|
msgid "can't read inbox of %{nickname} as %{as_nickname}"
|
||||||
|
msgstr "không thể đọc hộp thư đến của %{nickname} như %{as_nickname}"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:473
|
||||||
|
#, elixir-format
|
||||||
|
msgid "can't update outbox of %{nickname} as %{as_nickname}"
|
||||||
|
msgstr "không thể cập nhật hộp thư đi của %{nickname} như %{as_nickname}"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:471
|
||||||
|
#, elixir-format
|
||||||
|
msgid "conversation is already muted"
|
||||||
|
msgstr "bạn đã bỏ quan tâm cuộc đối thoại này"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:314
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:492
|
||||||
|
#, elixir-format
|
||||||
|
msgid "error"
|
||||||
|
msgstr "lỗi"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:32
|
||||||
|
#, elixir-format
|
||||||
|
msgid "mascots can only be images"
|
||||||
|
msgstr "linh vật chỉ được là hình ảnh"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:62
|
||||||
|
#, elixir-format
|
||||||
|
msgid "not found"
|
||||||
|
msgstr "không tìm thấy"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:394
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Bad OAuth request."
|
||||||
|
msgstr "Không thể kết nối OAuth."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:115
|
||||||
|
#, elixir-format
|
||||||
|
msgid "CAPTCHA already used"
|
||||||
|
msgstr "CAPTCHA đã dùng rồi"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:112
|
||||||
|
#, elixir-format
|
||||||
|
msgid "CAPTCHA expired"
|
||||||
|
msgstr "CAPTCHA đã hết hạn"
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/uploaded_media.ex:57
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Failed"
|
||||||
|
msgstr "Thất bại"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:410
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Failed to authenticate: %{message}."
|
||||||
|
msgstr "Xác thực thất bại: %{message}."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:441
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Failed to set up user account."
|
||||||
|
msgstr "Tạo tài khoản không thành công."
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Insufficient permissions: %{permissions}."
|
||||||
|
msgstr "Không có quyền: %{permissions}."
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/uploaded_media.ex:104
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Internal Error"
|
||||||
|
msgstr "Lỗi nội bộ"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/fallback_controller.ex:22
|
||||||
|
#: lib/pleroma/web/oauth/fallback_controller.ex:29
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid Username/Password"
|
||||||
|
msgstr "Tên người dùng/mật khẩu không đúng"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:118
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid answer data"
|
||||||
|
msgstr "sai dữ liệu trả lời"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:33
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Nodeinfo schema version not handled"
|
||||||
|
msgstr "Chưa nạp Nodeinfo"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:172
|
||||||
|
#, elixir-format
|
||||||
|
msgid "This action is outside the authorized scopes"
|
||||||
|
msgstr "Hành động này nằm ngoài phạm vi cho phép"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/fallback_controller.ex:14
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unknown error, please check the details and try again."
|
||||||
|
msgstr "Lỗi chưa biết, xin kiểm tra chi tiết và thử lại sau."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:119
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:158
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unlisted redirect_uri."
|
||||||
|
msgstr "Hạn chế redirect_uri."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:390
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unsupported OAuth provider: %{provider}."
|
||||||
|
msgstr "Không hỗ trợ nhà cung cấp OAuth: %{provider}."
|
||||||
|
|
||||||
|
#: lib/pleroma/uploaders/uploader.ex:72
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Uploader callback timeout"
|
||||||
|
msgstr "Hết hạn tải lên"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/uploader_controller.ex:23
|
||||||
|
#, elixir-format
|
||||||
|
msgid "bad request"
|
||||||
|
msgstr "lỗi kết nối"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:103
|
||||||
|
#, elixir-format
|
||||||
|
msgid "CAPTCHA Error"
|
||||||
|
msgstr "Lỗi CAPTCHA"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:290
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not add reaction emoji"
|
||||||
|
msgstr "Không thể thêm tương tác emoji"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/common_api/common_api.ex:301
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Could not remove reaction emoji"
|
||||||
|
msgstr "Không thể xóa tương tác emoji"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/twitter_api/twitter_api.ex:129
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Invalid CAPTCHA (Missing parameter: %{name})"
|
||||||
|
msgstr "CAPTCHA sai (Thiếu tham số: %{name})"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:92
|
||||||
|
#, elixir-format
|
||||||
|
msgid "List not found"
|
||||||
|
msgstr "Không tìm thấy danh sách"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:123
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Missing parameter: %{name}"
|
||||||
|
msgstr "Thiếu tham số: %{name}"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:210
|
||||||
|
#: lib/pleroma/web/oauth/oauth_controller.ex:321
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Password reset is required"
|
||||||
|
msgstr "Yêu cầu đổi mật khẩu"
|
||||||
|
|
||||||
|
#: lib/pleroma/tests/auth_test_controller.ex:9
|
||||||
|
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:6 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/config_controller.ex:6 lib/pleroma/web/admin_api/controllers/fallback_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/invite_controller.ex:6 lib/pleroma/web/admin_api/controllers/media_proxy_cache_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/oauth_app_controller.ex:6 lib/pleroma/web/admin_api/controllers/relay_controller.ex:6
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/report_controller.ex:6 lib/pleroma/web/admin_api/controllers/status_controller.ex:6
|
||||||
|
#: lib/pleroma/web/controller_helper.ex:6 lib/pleroma/web/embed_controller.ex:6
|
||||||
|
#: lib/pleroma/web/fallback_redirect_controller.ex:6 lib/pleroma/web/feed/tag_controller.ex:6
|
||||||
|
#: lib/pleroma/web/feed/user_controller.ex:6 lib/pleroma/web/mailer/subscription_controller.ex:2
|
||||||
|
#: lib/pleroma/web/masto_fe_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/account_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/app_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/auth_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/filter_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/instance_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/list_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/marker_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex:14
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/media_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/notification_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/report_controller.ex:8
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/search_controller.ex:6
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/status_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:7
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:6
|
||||||
|
#: lib/pleroma/web/media_proxy/media_proxy_controller.ex:6 lib/pleroma/web/mongooseim/mongoose_im_controller.ex:6
|
||||||
|
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:6 lib/pleroma/web/oauth/fallback_controller.ex:6
|
||||||
|
#: lib/pleroma/web/oauth/mfa_controller.ex:10 lib/pleroma/web/oauth/oauth_controller.ex:6
|
||||||
|
#: lib/pleroma/web/ostatus/ostatus_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/account_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/chat_controller.ex:5 lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:2 lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/notification_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex:6
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex:7 lib/pleroma/web/static_fe/static_fe_controller.ex:6
|
||||||
|
#: lib/pleroma/web/twitter_api/controllers/password_controller.ex:10 lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex:6
|
||||||
|
#: lib/pleroma/web/twitter_api/controllers/util_controller.ex:6 lib/pleroma/web/twitter_api/twitter_api_controller.ex:6
|
||||||
|
#: lib/pleroma/web/uploader_controller.ex:6 lib/pleroma/web/web_finger/web_finger_controller.ex:6
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
|
||||||
|
msgstr "Vi phạm bảo mật: phạm vi OAuth bị bỏ qua hoặc vượt quá giới hạn."
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Two-factor authentication enabled, you must use a access token."
|
||||||
|
msgstr "Đã bật xác thực hai bước, bạn phải sử dụng token truy cập."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:210
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while adding file to pack."
|
||||||
|
msgstr "Xảy ra lỗi chưa biết khi nén tập tin."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:138
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while creating pack."
|
||||||
|
msgstr "Xảy ra lỗi chưa biết khi tạo tập tin."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:278
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while removing file from pack."
|
||||||
|
msgstr "Xảy ra lỗi chưa biết khi giải nén tập tin."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:250
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while updating file in pack."
|
||||||
|
msgstr "Xảy ra lỗi chưa biết khi cập nhật tập tin."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:179
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Unexpected error occurred while updating pack metadata."
|
||||||
|
msgstr "Xảy ra lỗi chưa biết khi cập nhật metadata tập tin."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Web push subscription is disabled on this Pleroma instance"
|
||||||
|
msgstr "Máy chủ Pleroma này tắt thông báo đẩy trên web"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:451
|
||||||
|
#, elixir-format
|
||||||
|
msgid "You can't revoke your own admin/moderator status."
|
||||||
|
msgstr "Bạn không thể tự gỡ chức vụ."
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:126
|
||||||
|
#, elixir-format
|
||||||
|
msgid "authorization required for timeline view"
|
||||||
|
msgstr "yêu cầu xác thực để xem bảng tin"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:24
|
||||||
|
#, elixir-format
|
||||||
|
msgid "Access denied"
|
||||||
|
msgstr "Truy cập bị từ chối"
|
||||||
|
|
||||||
|
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:282
|
||||||
|
#, elixir-format
|
||||||
|
msgid "This API requires an authenticated user"
|
||||||
|
msgstr "API yêu cầu một người dùng đã xác thực"
|
||||||
|
|
||||||
|
#: lib/pleroma/plugs/user_is_admin_plug.ex:21
|
||||||
|
#, elixir-format
|
||||||
|
msgid "User is not an admin."
|
||||||
|
msgstr "Người này không phải quản trị viên."
|
|
@ -14,9 +14,7 @@ def up do
|
||||||
max = min + 10_000
|
max = min + 10_000
|
||||||
|
|
||||||
execute("""
|
execute("""
|
||||||
update activities set recipients = array(select jsonb_array_elements_text(data->'to')) where id > #{
|
update activities set recipients = array(select jsonb_array_elements_text(data->'to')) where id > #{min} and id <= #{max};
|
||||||
min
|
|
||||||
} and id <= #{max};
|
|
||||||
""")
|
""")
|
||||||
|> IO.inspect()
|
|> IO.inspect()
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -28,9 +28,7 @@ def change do
|
||||||
{:ok, %{rows: ap_ids}} =
|
{:ok, %{rows: ap_ids}} =
|
||||||
Ecto.Adapters.SQL.query(
|
Ecto.Adapters.SQL.query(
|
||||||
Repo,
|
Repo,
|
||||||
"select distinct unnest(nonexistent_locals.recipients) from activities, lateral (select array_agg(recipient) as recipients from unnest(activities.recipients) as recipient where recipient similar to '#{
|
"select distinct unnest(nonexistent_locals.recipients) from activities, lateral (select array_agg(recipient) as recipients from unnest(activities.recipients) as recipient where recipient similar to '#{instance_uri}/users/[A-Za-z0-9]*' and not(recipient in (select ap_id from users))) nonexistent_locals;",
|
||||||
instance_uri
|
|
||||||
}/users/[A-Za-z0-9]*' and not(recipient in (select ap_id from users))) nonexistent_locals;",
|
|
||||||
[],
|
[],
|
||||||
timeout: :infinity
|
timeout: :infinity
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.SimplePolicyStringToTuple do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
alias Pleroma.ConfigDB
|
||||||
|
|
||||||
|
def up, do: ConfigDB.get_by_params(%{group: :pleroma, key: :mrf_simple}) |> update_to_tuples
|
||||||
|
def down, do: ConfigDB.get_by_params(%{group: :pleroma, key: :mrf_simple}) |> update_to_strings
|
||||||
|
|
||||||
|
defp update_to_tuples(%{value: value}) do
|
||||||
|
new_value =
|
||||||
|
value
|
||||||
|
|> Enum.map(fn {k, v} ->
|
||||||
|
{k,
|
||||||
|
Enum.map(v, fn
|
||||||
|
{instance, reason} -> {instance, reason}
|
||||||
|
instance -> {instance, ""}
|
||||||
|
end)}
|
||||||
|
end)
|
||||||
|
|
||||||
|
ConfigDB.update_or_create(%{group: :pleroma, key: :mrf_simple, value: new_value})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_to_tuples(nil), do: {:ok, nil}
|
||||||
|
|
||||||
|
defp update_to_strings(%{value: value}) do
|
||||||
|
new_value =
|
||||||
|
value
|
||||||
|
|> Enum.map(fn {k, v} ->
|
||||||
|
{k,
|
||||||
|
Enum.map(v, fn
|
||||||
|
{instance, _} -> instance
|
||||||
|
instance -> instance
|
||||||
|
end)}
|
||||||
|
end)
|
||||||
|
|
||||||
|
ConfigDB.update_or_create(%{group: :pleroma, key: :mrf_simple, value: new_value})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_to_strings(nil), do: {:ok, nil}
|
||||||
|
end
|
|
@ -0,0 +1,61 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.QuarantainedStringToTuple do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
alias Pleroma.ConfigDB
|
||||||
|
|
||||||
|
def up,
|
||||||
|
do:
|
||||||
|
ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
|
||||||
|
|> update_quarantined_instances_to_tuples
|
||||||
|
|
||||||
|
def down,
|
||||||
|
do:
|
||||||
|
ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
|
||||||
|
|> update_quarantined_instances_to_strings
|
||||||
|
|
||||||
|
defp update_quarantined_instances_to_tuples(%{value: settings}) do
|
||||||
|
settings |> List.keyfind(:quarantined_instances, 0) |> update_to_tuples
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_quarantined_instances_to_tuples(nil), do: {:ok, nil}
|
||||||
|
|
||||||
|
defp update_to_tuples({:quarantined_instances, instance_list}) do
|
||||||
|
new_value =
|
||||||
|
instance_list
|
||||||
|
|> Enum.map(fn
|
||||||
|
{v, r} -> {v, r}
|
||||||
|
v -> {v, ""}
|
||||||
|
end)
|
||||||
|
|
||||||
|
ConfigDB.update_or_create(%{
|
||||||
|
group: :pleroma,
|
||||||
|
key: :instance,
|
||||||
|
value: [quarantined_instances: new_value]
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_to_tuples(nil), do: {:ok, nil}
|
||||||
|
|
||||||
|
defp update_quarantined_instances_to_strings(%{value: settings}) do
|
||||||
|
settings |> List.keyfind(:quarantined_instances, 0) |> update_to_strings
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_quarantined_instances_to_strings(nil), do: {:ok, nil}
|
||||||
|
|
||||||
|
defp update_to_strings({:quarantined_instances, instance_list}) do
|
||||||
|
new_value =
|
||||||
|
instance_list
|
||||||
|
|> Enum.map(fn
|
||||||
|
{v, _} -> v
|
||||||
|
v -> v
|
||||||
|
end)
|
||||||
|
|
||||||
|
ConfigDB.update_or_create(%{
|
||||||
|
group: :pleroma,
|
||||||
|
key: :instance,
|
||||||
|
value: [quarantined_instances: new_value]
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_to_strings(nil), do: {:ok, nil}
|
||||||
|
end
|
|
@ -0,0 +1,61 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.TransparencyExclusionsStringToTuple do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
alias Pleroma.ConfigDB
|
||||||
|
|
||||||
|
def up,
|
||||||
|
do:
|
||||||
|
ConfigDB.get_by_params(%{group: :pleroma, key: :mrf})
|
||||||
|
|> update_transparency_exclusions_instances_to_tuples
|
||||||
|
|
||||||
|
def down,
|
||||||
|
do:
|
||||||
|
ConfigDB.get_by_params(%{group: :pleroma, key: :mrf})
|
||||||
|
|> update_transparency_exclusions_instances_to_strings
|
||||||
|
|
||||||
|
defp update_transparency_exclusions_instances_to_tuples(%{value: settings}) do
|
||||||
|
settings |> List.keyfind(:transparency_exclusions, 0) |> update_to_tuples
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_transparency_exclusions_instances_to_tuples(nil), do: {:ok, nil}
|
||||||
|
|
||||||
|
defp update_to_tuples({:transparency_exclusions, instance_list}) do
|
||||||
|
new_value =
|
||||||
|
instance_list
|
||||||
|
|> Enum.map(fn
|
||||||
|
{v, r} -> {v, r}
|
||||||
|
v -> {v, ""}
|
||||||
|
end)
|
||||||
|
|
||||||
|
ConfigDB.update_or_create(%{
|
||||||
|
group: :pleroma,
|
||||||
|
key: :mrf,
|
||||||
|
value: [transparency_exclusions: new_value]
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_to_tuples(nil), do: {:ok, nil}
|
||||||
|
|
||||||
|
defp update_transparency_exclusions_instances_to_strings(%{value: settings}) do
|
||||||
|
settings |> List.keyfind(:transparency_exclusions, 0) |> update_to_strings
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_transparency_exclusions_instances_to_strings(nil), do: {:ok, nil}
|
||||||
|
|
||||||
|
defp update_to_strings({:transparency_exclusions, instance_list}) do
|
||||||
|
new_value =
|
||||||
|
instance_list
|
||||||
|
|> Enum.map(fn
|
||||||
|
{v, _} -> v
|
||||||
|
v -> v
|
||||||
|
end)
|
||||||
|
|
||||||
|
ConfigDB.update_or_create(%{
|
||||||
|
group: :pleroma,
|
||||||
|
key: :mrf,
|
||||||
|
value: [transparency_exclusions: new_value]
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_to_strings(nil), do: {:ok, nil}
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.RemoveMastofeSettingsFromUsers do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
alter table(:users) do
|
||||||
|
remove_if_exists(:mastofe_settings, :map)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,49 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.AddPollToNotificationsEnum do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
@disable_ddl_transaction true
|
||||||
|
|
||||||
|
def up do
|
||||||
|
"""
|
||||||
|
alter type notification_type add value 'poll'
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
alter table(:notifications) do
|
||||||
|
modify(:type, :string)
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
delete from notifications where type = 'poll'
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
|
||||||
|
"""
|
||||||
|
drop type if exists notification_type
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
|
||||||
|
"""
|
||||||
|
create type notification_type as enum (
|
||||||
|
'follow',
|
||||||
|
'follow_request',
|
||||||
|
'mention',
|
||||||
|
'move',
|
||||||
|
'pleroma:emoji_reaction',
|
||||||
|
'pleroma:chat_mention',
|
||||||
|
'reblog',
|
||||||
|
'favourite',
|
||||||
|
'pleroma:report'
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
|
||||||
|
"""
|
||||||
|
alter table notifications
|
||||||
|
alter column type type notification_type using (type::notification_type)
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
end
|
||||||
|
end
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#E6E7E8" d="M32 32c0 2.209-1.791 4-4 4H8c-2.209 0-4-1.791-4-4V4c0-2.209 1.791-4 4-4h20c2.209 0 4 1.791 4 4v28z"/><path fill="#BE1931" d="M8.397 11.891c.53 0 .996.078 1.392.232.244.066.453.143.63.231.796-.044 1.612-.122 2.453-.231 1.104-.134 2.463-.297 4.076-.497V9.307c0-1.613-.188-2.948-.563-4.01-.155-.332-.233-.552-.233-.662 0-.331.133-.498.398-.498.706 0 1.359.089 1.954.266.686.198 1.028.453 1.028.761 0 .111-.042.342-.134.696-.265.685-.395 1.955-.395 3.811v1.723c1.299-.132 2.723-.276 4.271-.43.706-.045 1.381-.166 2.023-.366.463-.088.739-.132.83-.132.264 0 .837.222 1.72.662.928.553 1.394.984 1.394 1.293 0 .242-.12.486-.362.729-.819.881-1.408 1.809-1.759 2.782l-.798 1.691c-.13.329-.276.583-.426.76l.128.067c.508.311.761.586.761.829 0 .198-.183.309-.56.332-1.699 0-3.236.088-4.606.266l-2.614.196-.034 4.442c0 2.009-.069 3.62-.198 4.838-.133 1.368-.333 2.341-.598 2.914-.245.488-.445.733-.598.733-.089 0-.232-.266-.431-.798-.132-.617-.198-1.687-.198-3.214v-8.749l-1.789.167c-1.194.111-2.111.168-2.75.168-.266 0-.488-.024-.664-.069-.044.2-.11.376-.198.533-.133.287-.277.43-.432.43-.198 0-.385-.154-.562-.465-.287-.438-.442-.892-.464-1.358l-.398-2.585c-.155-1.348-.332-2.286-.531-2.818-.111-.551-.409-1.081-.894-1.59-.177-.11-.266-.186-.266-.23 0-.354.133-.531.397-.531zm3.347 7.221c1.812-.085 3.545-.196 5.203-.328v-6.132c-1.702.199-3.347.464-4.937.796-.31.111-.597.188-.862.232 0 .265.022.53.067.793.265 2.013.441 3.561.529 4.639zm7.259-6.69v6.163c.728-.087 1.435-.179 2.119-.265 1.326-.178 2.286-.286 2.879-.331.048-.11.103-.232.168-.363.199-.641.463-1.646.798-3.016.264-1.084.394-1.768.394-2.056 0-.353-.339-.529-1.024-.529-1.041 0-2.696.121-4.973.363-.13-.001-.254.012-.361.034z"/></svg>
|
|
Before Width: | Height: | Size: 1.7 KiB |
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#E6E7E8" d="M32 32c0 2.209-1.791 4-4 4H8c-2.209 0-4-1.791-4-4V4c0-2.209 1.791-4 4-4h20c2.209 0 4 1.791 4 4v28z"/><path fill="#DD2E44" d="M11 7c-2.519 0-4.583 1.87-4.929 4.293C6.802 10.503 7.839 10 9 10c2.209 0 4 1.791 4 4 0 2 1.497 2.198.707 2.929C16.13 16.583 16 14.519 16 12c0-2.761-2.239-5-5-5z"/><path fill="#55ACEE" d="M23 14c0-2.209 1.791-4 4-4 1.161 0 2.198.503 2.929 1.293C29.583 8.87 27.52 7 25 7c-2.762 0-5 2.239-5 5 0 2.519-.131 4.583 2.293 4.929C21.503 16.198 23 16 23 14z"/><path fill="#FFAC33" d="M14 12c0-4.971 4-9 4-9s4 4.029 4 9-1.791 9-4 9-4-4.029-4-9z"/><path fill="#553788" d="M11.707 21.071C12.497 21.802 13 22.839 13 24c0 2.209-1.791 4-4 4-1.161 0-2.198-.503-2.929-1.293C6.417 29.131 8.481 31 11 31c2.761 0 5-2.238 5-5 0-2.52-1.87-4.583-4.293-4.929zM27 28c-2.209 0-4-1.791-4-4 0-1.161.503-2.198 1.293-2.929C21.869 21.417 20 23.48 20 26c0 2.762 2.238 5 5 5 2.52 0 4.583-1.869 4.929-4.293C29.198 27.497 28.161 28 27 28z"/><path fill="#9266CC" d="M14 24c0 4.971 3 9 4 9s4-4.029 4-9c0-.874-.055-1.719-.159-2.519C21.357 17.737 19.82 15 18 15c-1.82 0-3.357 2.737-3.841 6.481-.104.8-.159 1.645-.159 2.519z"/><path fill="#EDBB9F" d="M13 17c0-3.866 3-4 5-4s5 .134 5 4c0 3.865-2.238 7-5 7-2.761 0-5-3.135-5-7z"/><circle fill="#662113" cx="16" cy="17" r="1"/><circle fill="#662113" cx="20" cy="17" r="1"/><path fill="#662113" d="M18 22c1.104 0 2-.896 2-2h-4c0 1.104.896 2 2 2z"/><circle fill="#A0041E" cx="6" cy="11" r="1"/><circle fill="#269" cx="30" cy="11" r="1"/><circle fill="#DD2E44" cx="18" cy="3" r="1"/></svg>
|
|
Before Width: | Height: | Size: 1.6 KiB |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue