diff --git a/.formatter.exs b/.formatter.exs index abd91dbbe..a96afe758 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,3 +1,14 @@ [ - inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}", "priv/repo/migrations/*.exs", "priv/repo/optional_migrations/**/*.exs", "priv/scrubbers/*.ex"] + import_deps: [:ecto, :ecto_sql, :phoenix], + subdirectories: ["priv/*/migrations"], + plugins: [Phoenix.LiveView.HTMLFormatter], + inputs: [ + "mix.exs", + "*.{heex,ex,exs}", + "{config,lib,test}/**/*.{heex,ex,exs}", + "priv/*/seeds.exs", + "priv/repo/migrations/*.exs", + "priv/repo/optional_migrations/**/*.exs", + "priv/scrubbers/*.ex" + ] ] diff --git a/.woodpecker/build-amd64.yml b/.woodpecker/build-amd64.yml index c90d7f394..f7d2ae7d8 100644 --- a/.woodpecker/build-amd64.yml +++ b/.woodpecker/build-amd64.yml @@ -37,7 +37,7 @@ variables: pipeline: # Canonical amd64 debian-bookworm: - image: hexpm/elixir:1.15.4-erlang-25.3.2.5-debian-bookworm-20230612 + image: hexpm/elixir:1.15.4-erlang-26.0.2-debian-bookworm-20230612 <<: *on-release environment: MIX_ENV: prod @@ -66,7 +66,7 @@ pipeline: - /bin/sh /entrypoint.sh debian-bullseye: - image: hexpm/elixir:1.15.4-erlang-25.3.2.5-debian-bullseye-20230612 + image: hexpm/elixir:1.15.4-erlang-26.0.2-debian-bullseye-20230612 <<: *on-release environment: MIX_ENV: prod @@ -94,7 +94,7 @@ pipeline: # Canonical amd64-musl musl: - image: hexpm/elixir:1.14.3-erlang-25.2.2-alpine-3.18.0 + image: hexpm/elixir:1.15.4-erlang-26.0.2-alpine-3.18.2 <<: *on-stable environment: MIX_ENV: prod diff --git a/.woodpecker/build-arm64.yml b/.woodpecker/build-arm64.yml index d923e5847..1ce1fac44 100644 --- a/.woodpecker/build-arm64.yml +++ b/.woodpecker/build-arm64.yml @@ -37,7 +37,7 @@ variables: pipeline: # Canonical arm64 debian-bookworm: - image: hexpm/elixir:1.15.4-erlang-25.3.2.5-debian-bookworm-20230612 + image: hexpm/elixir:1.15.4-erlang-26.0.2-debian-bookworm-20230612 <<: *on-release environment: MIX_ENV: prod @@ -65,7 +65,7 @@ pipeline: # Canonical arm64-musl musl: - image: hexpm/elixir:1.15.4-erlang-25.3.2.5-alpine-3.18.2 + image: hexpm/elixir:1.15.4-erlang-26.0.2-alpine-3.18.2 <<: *on-stable environment: MIX_ENV: prod diff --git a/.woodpecker/lint.yml b/.woodpecker/lint.yml new file mode 100644 index 000000000..8308e57d7 --- /dev/null +++ b/.woodpecker/lint.yml @@ -0,0 +1,55 @@ +platform: linux/amd64 + +variables: + - &scw-secrets + - SCW_ACCESS_KEY + - SCW_SECRET_KEY + - SCW_DEFAULT_ORGANIZATION_ID + - &setup-hex "mix local.hex --force && mix local.rebar --force" + - &on-release + when: + event: + - push + - tag + branch: + - develop + - stable + - refs/tags/v* + - refs/tags/stable-* + - &on-stable + when: + event: + - push + - tag + branch: + - stable + - refs/tags/stable-* + - &on-point-release + when: + event: + - push + branch: + - develop + - stable + - &on-pr-open + when: + event: + - pull_request + + - &tag-build "export BUILD_TAG=$${CI_COMMIT_TAG:-\"$CI_COMMIT_BRANCH\"} && export PLEROMA_BUILD_BRANCH=$BUILD_TAG" + + - &clean "(rm -rf release || true) && (rm -rf _build || true) && (rm -rf /root/.mix)" + - &mix-clean "mix deps.clean --all && mix clean" + +pipeline: + lint: + image: akkoma/ci-base:1.15-otp26 + <<: *on-pr-open + environment: + MIX_ENV: test + commands: + - mix local.hex --force + - mix local.rebar --force + - mix deps.get + - mix compile + - mix format --check-formatted diff --git a/.woodpecker/test.yml b/.woodpecker/test.yml index be8ea0dfa..16a4067fe 100644 --- a/.woodpecker/test.yml +++ b/.woodpecker/test.yml @@ -1,5 +1,8 @@ platform: linux/amd64 +depends_on: + - lint + matrix: ELIXIR_VERSION: - 1.14 @@ -12,9 +15,8 @@ matrix: OTP_VERSION: 25 - ELIXIR_VERSION: 1.15 OTP_VERSION: 25 - # Soon - #- ELIXIR_VERSION: 1.15 - # OTP_VERSION: 26 + - ELIXIR_VERSION: 1.15 + OTP_VERSION: 26 variables: - &scw-secrets @@ -69,15 +71,7 @@ services: POSTGRES_PASSWORD: postgres pipeline: - lint: - <<: *on-pr-open - image: akkoma/ci-base:1.15 - commands: - - mix local.hex --force - - mix local.rebar --force - - mix format --check-formatted - - build: + test: image: akkoma/ci-base:${ELIXIR_VERSION}-otp${OTP_VERSION} <<: *on-pr-open environment: @@ -91,24 +85,9 @@ pipeline: - mix local.rebar --force - mix deps.get - mix compile - - test: - image: akkoma/ci-base:${ELIXIR_VERSION}-otp${OTP_VERSION} - <<: *on-pr-open - environment: - MIX_ENV: test - POSTGRES_DB: pleroma_test_${ELIXIR_VERSION}_${OTP_VERSION} - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - DB_HOST: postgres - commands: - - mix local.hex --force - - mix local.rebar --force - - mix deps.get - - mix compile - - mix ecto.drop -f -q - - mix ecto.create - - mix ecto.migrate - - mkdir -p test/tmp - - mix test --preload-modules --exclude erratic --exclude federated --exclude mocked - - mix test --preload-modules --only mocked + - mix ecto.drop -f -q + - mix ecto.create + - mix ecto.migrate + - mkdir -p test/tmp + - mix test --preload-modules --exclude erratic --exclude federated --exclude mocked + - mix test --preload-modules --only mocked diff --git a/CHANGELOG.md b/CHANGELOG.md index 92b3d1a71..84bb53820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## Unreleased +## 2024.02 + +## Added +- Full compatibility with Erlang OTP26 +- handling of GET /api/v1/preferences +- Akkoma API is now documented +- ability to auto-approve follow requests from users you are already following +- The SimplePolicy MRF can now strip user backgrounds from selected remote hosts + +## Changed +- OTP builds are now built on erlang OTP26 +- The base Phoenix framework is now updated to 1.7 +- An `outbox` field has been added to actor profiles to comply with AP spec +- User profile backgrounds do now federate with other Akkoma instances and Sharkey ## Fixed +- Documentation issue in which a non-existing nginx file was referenced - Issue where a bad inbox URL could break federation +- Issue where hashtag rel values would be scrubbed +- Issue where short domains listed in `transparency_obfuscate_domains` were not actually obfuscated ## 2023.08 diff --git a/Dockerfile b/Dockerfile index f695322e5..aadd08f7a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM hexpm/elixir:1.15.4-erlang-25.3.2.5-alpine-3.18.2 +FROM hexpm/elixir:1.15.4-erlang-26.0.2-alpine-3.18.2 ENV MIX_ENV=prod ENV ERL_EPMD_ADDRESS=127.0.0.1 diff --git a/config/config.exs b/config/config.exs index 3430ee4d7..1c531344c 100644 --- a/config/config.exs +++ b/config/config.exs @@ -110,17 +110,6 @@ "xmpp" ] -websocket_config = [ - path: "/websocket", - serializer: [ - {Phoenix.Socket.V1.JSONSerializer, "~> 1.0.0"}, - {Phoenix.Socket.V2.JSONSerializer, "~> 2.0.0"} - ], - timeout: 60_000, - transport_log: false, - compress: false -] - # Configures the endpoint config :pleroma, Pleroma.Web.Endpoint, url: [host: "localhost"], @@ -130,10 +119,7 @@ {:_, [ {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, - {"/websocket", Phoenix.Endpoint.CowboyWebSocket, - {Phoenix.Transports.WebSocket, - {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, websocket_config}}}, - {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}} + {:_, Plug.Cowboy.Handler, {Pleroma.Web.Endpoint, []}} ]} ] ], @@ -170,6 +156,10 @@ "application/ld+json" => ["activity+json"] } +config :mime, :extensions, %{ + "activity+json" => "application/activity+json" +} + config :tesla, :adapter, {Tesla.Adapter.Finch, name: MyFinch} # Configures http settings, upstream proxy etc. @@ -300,7 +290,6 @@ alwaysShowSubjectInput: true, background: "/images/city.jpg", collapseMessageWithSubject: false, - disableChat: false, greentext: false, hideFilteredStatuses: false, hideMutedPosts: false, @@ -388,6 +377,7 @@ accept: [], avatar_removal: [], banner_removal: [], + background_removal: [], reject_deletes: [], handle_threads: true @@ -416,8 +406,6 @@ threshold: 604_800, actions: [:delist, :strip_followers] -config :pleroma, :mrf_follow_bot, follower_nickname: nil - config :pleroma, :mrf_reject_newly_created_account_notes, age: 86_400 config :pleroma, :rich_media, @@ -463,10 +451,6 @@ image_quality: 85, min_content_length: 100 * 1024 -config :pleroma, :shout, - enabled: true, - limit: 5_000 - config :phoenix, :format_encoders, json: Jason, "activity+json": Jason config :phoenix, :json_library, Jason diff --git a/docker-compose.yml b/docker-compose.yml index 0dedbc87e..58abf189d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,6 +4,7 @@ services: db: image: akkoma-db:latest build: ./docker-resources/database + shm_size: 4gb restart: unless-stopped user: ${DOCKER_USER} environment: { diff --git a/docs/docs/administration/CLI_tasks/robots_txt.md b/docs/docs/administration/CLI_tasks/robots_txt.md index 924f2e319..de27e5dca 100644 --- a/docs/docs/administration/CLI_tasks/robots_txt.md +++ b/docs/docs/administration/CLI_tasks/robots_txt.md @@ -17,5 +17,5 @@ If you want to generate a restrictive `robots.txt`, you can run the following mi === "From Source" ```sh - mix pleroma.robotstxt disallow_all + mix pleroma.robots_txt disallow_all ``` diff --git a/docs/docs/administration/backup.md b/docs/docs/administration/backup.md index 5c5df88ce..6aa79043c 100644 --- a/docs/docs/administration/backup.md +++ b/docs/docs/administration/backup.md @@ -45,3 +45,16 @@ 8. Remove the dependencies that you don't need anymore (see installation guide). Make sure you don't remove packages that are still needed for other software that you have running! [¹]: We assume the database name and user are both "akkoma". If not, you can find the correct name in your config files. + +## Docker installations + +If running behind Docker, it is required to run the above commands inside of a running database container. + +### Example +Running `docker compose run --rm db pg_dump <...>` will fail and return: +``` +pg_dump: error: connection to server on socket "/run/postgresql/.s.PGSQL.5432" failed: No such file or directory +Is the server running locally and accepting connections on that socket?" +``` +However, first starting just the database container with `docker compose up db -d`, and then running `docker compose exec db pg_dump -d akkoma --format=custom -f ` will successfully generate a database dump. +Then to make the file accessible on the host system you can run `docker compose cp db: ` to copy if from the container. diff --git a/docs/docs/administration/monitoring.md b/docs/docs/administration/monitoring.md index 9233fbe34..b7a748731 100644 --- a/docs/docs/administration/monitoring.md +++ b/docs/docs/administration/monitoring.md @@ -3,7 +3,7 @@ If you run akkoma, you may be inclined to collect metrics to ensure your instance is running smoothly, and that there's nothing quietly failing in the background. -To facilitate this, akkoma exposes prometheus metrics to be scraped. +To facilitate this, akkoma exposes a dashboard and prometheus metrics to be scraped. ## Prometheus @@ -31,3 +31,15 @@ Once you have your token of the form `Bearer $ACCESS_TOKEN`, you can use that in - targets: - example.com ``` + +## Dashboard + +Administrators can access a live dashboard under `/phoenix/live_dashboard` +giving an overview of uptime, software versions, database stats and more. + +The dashboard also includes a variation of the prometheus metrics, however +they do not exactly match due to respective limitations of the dashboard +and the prometheus exporter. +Even more important, the dashboard collects metrics locally in the browser +only while the page is open and cannot give a view on their past history. +For proper monitoring it is recommended to set up prometheus. diff --git a/docs/docs/configuration/cheatsheet.md b/docs/docs/configuration/cheatsheet.md index 73fdf9eea..3c9113f88 100644 --- a/docs/docs/configuration/cheatsheet.md +++ b/docs/docs/configuration/cheatsheet.md @@ -104,31 +104,60 @@ To add configuration to your config file, you can copy it from the base config. ## Message rewrite facility ### :mrf -* `policies`: Message Rewrite Policy, either one or a list. Here are the ones available by default: - * `Pleroma.Web.ActivityPub.MRF.NoOpPolicy`: Doesn’t modify activities (default). - * `Pleroma.Web.ActivityPub.MRF.DropPolicy`: Drops all activities. It generally doesn’t makes sense to use in production. - * `Pleroma.Web.ActivityPub.MRF.SimplePolicy`: Restrict the visibility of activities from certains instances (See [`:mrf_simple`](#mrf_simple)). - * `Pleroma.Web.ActivityPub.MRF.TagPolicy`: Applies policies to individual users based on tags, which can be set using pleroma-fe/admin-fe/any other app that supports Pleroma Admin API. For example it allows marking posts from individual users nsfw (sensitive). - * `Pleroma.Web.ActivityPub.MRF.SubchainPolicy`: Selectively runs other MRF policies when messages match (See [`:mrf_subchain`](#mrf_subchain)). - * `Pleroma.Web.ActivityPub.MRF.RejectNonPublic`: Drops posts with non-public visibility settings (See [`:mrf_rejectnonpublic`](#mrf_rejectnonpublic)). - * `Pleroma.Web.ActivityPub.MRF.EnsureRePrepended`: Rewrites posts to ensure that replies to posts with subjects do not have an identical subject and instead begin with re:. - * `Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy`: Rejects posts from likely spambots by rejecting posts from new users that contain links. - * `Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`: Crawls attachments using their MediaProxy URLs so that the MediaProxy cache is primed. - * `Pleroma.Web.ActivityPub.MRF.MentionPolicy`: Drops posts mentioning configurable users. (See [`:mrf_mention`](#mrf_mention)). - * `Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`: Restricts activities to a configured set of vocabulary. (See [`:mrf_vocabulary`](#mrf_vocabulary)). - * `Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy`: Rejects or delists posts based on their age when received. (See [`:mrf_object_age`](#mrf_object_age)). - * `Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy`: Sets a default expiration on all posts made by users of the local instance. Requires `Pleroma.Workers.PurgeExpiredActivity` to be enabled for processing the scheduled delections. - * `Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy`: Makes all bot posts to disappear from public timelines. - * `Pleroma.Web.ActivityPub.MRF.FollowBotPolicy`: Automatically follows newly discovered users from the specified bot account. Local accounts, locked accounts, and users with "#nobot" in their bio are respected and excluded from being followed. - * `Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy`: Drops follow requests from followbots. Users can still allow bots to follow them by first following the bot. - * `Pleroma.Web.ActivityPub.MRF.KeywordPolicy`: Rejects or removes from the federated timeline or replaces keywords. (See [`:mrf_keyword`](#mrf_keyword)). - * `Pleroma.Web.ActivityPub.MRF.NormalizeMarkup`: Pass inbound HTML through a scrubber to make sure it doesn't have anything unusual in it. On by default, cannot be turned off. - * `Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy`: Append a link to a post that quotes another post with the link to the quoted post, to ensure that software that does not understand quotes can have full context. On by default, cannot be turned off. * `transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo). * `transparency_exclusions`: Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value. * `transparency_obfuscate_domains`: Show domains with `*` in the middle, to censor them if needed. For example, `ridingho.me` will show as `rid*****.me` +* `policies`: Message Rewrite Policy, either one or a list. Here are the ones available by default: + * `Pleroma.Web.ActivityPub.MRF.NoOpPolicy`: Doesn’t modify activities (default). + * `Pleroma.Web.ActivityPub.MRF.DropPolicy`: Drops all activities. It generally doesn’t makes sense to use in production. + * `Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy`: Sets a default expiration on all posts made by users of the local instance. Requires `Pleroma.Workers.PurgeExpiredActivity` to be enabled for processing the scheduled delections. + (See [`:mrf_activity_expiration`](#mrf_activity_expiration)) + * `Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy`: Drops follow requests from followbots. Users can still allow bots to follow them by first following the bot. + * `Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy`: Rejects posts from likely spambots by rejecting posts from new users that contain links. + * `Pleroma.Web.ActivityPub.MRF.EnsureRePrepended`: Rewrites posts to ensure that replies to posts with subjects do not have an identical subject and instead begin with re:. + * `Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy`: Makes all bot posts to disappear from public timelines. + * `Pleroma.Web.ActivityPub.MRF.HellthreadPolicy`: Blocks messages with too many mentions. + (See [`mrf_hellthread`](#mrf_hellthread)) + * `Pleroma.Web.ActivityPub.MRF.KeywordPolicy`: Rejects or removes from the federated timeline or replaces keywords. (See [`:mrf_keyword`](#mrf_keyword)). + * `Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`: Crawls attachments using their MediaProxy URLs so that the MediaProxy cache is primed. + * `Pleroma.Web.ActivityPub.MRF.MentionPolicy`: Drops posts mentioning configurable users. (See [`:mrf_mention`](#mrf_mention)). + * `Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy`: Drops local activities which have no actual content. + (e.g. no attachments and only consists of mentions) + * `Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy`: Strips content placeholders from posts + (such as the dot from mastodon) + * `Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy`: Rejects or delists posts based on their age when received. (See [`:mrf_object_age`](#mrf_object_age)). + * `Pleroma.Web.ActivityPub.MRF.RejectNewlyCreatedAccountNotesPolicy`: Rejects posts of users the server only recently learned about for a while. Great to block spam accounts. (See [`:mrf_reject_newly_created_account_notes`](#mrf_reject_newly_created_account_notes)) + * `Pleroma.Web.ActivityPub.MRF.RejectNonPublic`: Drops posts with non-public visibility settings (See [`:mrf_rejectnonpublic`](#mrf_rejectnonpublic)). + * `Pleroma.Web.ActivityPub.MRF.SimplePolicy`: Restrict the visibility of activities from certains instances (See [`:mrf_simple`](#mrf_simple)). + * `Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy`: Steals all eligible emoji encountered in posts from remote instances + (See [`:mrf_steal_emoji`](#mrf_steal_emoji)) + * `Pleroma.Web.ActivityPub.MRF.SubchainPolicy`: Selectively runs other MRF policies when messages match (See [`:mrf_subchain`](#mrf_subchain)). + * `Pleroma.Web.ActivityPub.MRF.TagPolicy`: Applies policies to individual users based on tags, which can be set using pleroma-fe/admin-fe/any other app that supports Pleroma Admin API. For example it allows marking posts from individual users nsfw (sensitive). + * `Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy`: Drops all posts except from users specified in a list. + (See [`:mrf_user_allowlist`](#mrf_user_allowlist)) + * `Pleroma.Web.ActivityPub.MRF.VocabularyPolicy`: Restricts activities to a configured set of vocabulary. (See [`:mrf_vocabulary`](#mrf_vocabulary)). + +Additionally the following MRFs will *always* be aplied and cannot be disabled: + +* `Pleroma.Web.ActivityPub.MRF.DirectMessageDisabledPolicy`: Strips users limiting who can send them DMs from the recipients of non-eligible DMs +* `Pleroma.Web.ActivityPub.MRF.HashtagPolicy`: Depending on a post’s hashtags it can be rejected, get its sensitive flags force-enabled or removed from the global timeline + (See [`:mrf_hashtag`](#mrf_hashtag)) +* `Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy`: Append a link to a post that quotes another post with the link to the quoted post, to ensure that software that does not understand quotes can have full context. + (See [`:mrf_inline_quote`](#mrf_inline_quote)) +* `Pleroma.Web.ActivityPub.MRF.NormalizeMarkup`: Pass inbound HTML through a scrubber to make sure it doesn't have anything unusual in it. + (See [`:mrf_normalize_markup`](#mrf_normalize_markup)) + ## Federation +### :activitypub +* `unfollow_blocked`: Whether blocks result in people getting unfollowed +* `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 +* `sign_object_fetches`: Sign object fetches with HTTP signatures +* `authorized_fetch_mode`: Require HTTP signatures for AP fetches +* `max_collection_objects`: The maximum number of objects to fetch from a remote AP collection. + ### MRF policies !!! note @@ -144,6 +173,7 @@ To add configuration to your config file, you can copy it from the base config. * `report_removal`: List of instances to reject reports from and the reason for doing so. * `avatar_removal`: List of instances to strip avatars from and the reason for doing so. * `banner_removal`: List of instances to strip banners from and the reason for doing so. +* `background_removal`: List of instances to strip user backgrounds from and the reason for doing so. * `reject_deletes`: List of instances to reject deletions from and the reason for doing so. #### :mrf_subchain @@ -222,14 +252,24 @@ Notes: - The hashtags in the configuration do not have a leading `#`. - This MRF Policy is always enabled, if you want to disable it you have to set empty lists -### :activitypub -* `unfollow_blocked`: Whether blocks result in people getting unfollowed -* `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 -* `sign_object_fetches`: Sign object fetches with HTTP signatures -* `authorized_fetch_mode`: Require HTTP signatures for AP fetches -* `max_collection_objects`: The maximum number of objects to fetch from a remote AP collection. +#### :mrf_reject_newly_created_account_notes +After initially encountering an user, all their posts +will be rejected for the configured time (in seconds). +Only drops posts. Follows, reposts, etc. are not affected. + +* `age`: Time below which to reject (in seconds) + +An example: (86400 seconds = 24 hours) + +```elixir +config :pleroma, :mrf_reject_newly_created_account_notes, age: 86400 +``` + +#### :mrf_inline_quote +* `prefix`: what prefix to prepend to quoted URLs + +#### :mrf_normalize_markup +* `scrub_policy`: the scrubbing module to use (by default a built-in HTML sanitiser) ## Pleroma.User @@ -958,6 +998,15 @@ config :ueberauth, Ueberauth, ] ``` +You may also need to set up your frontend to use oauth logins. For example, for `akkoma-fe`: + +```elixir +config :pleroma, :frontend_configurations, + pleroma_fe: %{ + loginMethod: "token" + } +``` + ## Link parsing ### :uri_schemes diff --git a/docs/docs/configuration/howto_theming_your_instance.md b/docs/docs/configuration/howto_theming_your_instance.md index 093c12763..e29143db8 100644 --- a/docs/docs/configuration/howto_theming_your_instance.md +++ b/docs/docs/configuration/howto_theming_your_instance.md @@ -60,7 +60,7 @@ Example of `my-awesome-theme.json` where we add the name "My Awesome Theme" ### Set as default theme -Now we can set the new theme as default in the [Pleroma FE configuration](https://docs-fe.akkoma.dev/stable/CONFIGURATION). +Now we can set the new theme as default in the [Pleroma FE configuration](https://docs-fe.akkoma.dev/stable/CONFIGURATION/). Example of adding the new theme in the back-end config files ```elixir diff --git a/docs/docs/configuration/mrf.md b/docs/docs/configuration/mrf.md index a74cfa90d..0a17b3112 100644 --- a/docs/docs/configuration/mrf.md +++ b/docs/docs/configuration/mrf.md @@ -35,6 +35,7 @@ Once `SimplePolicy` is enabled, you can configure various groups in the `:mrf_si * `media_removal`: Servers in this group will have media stripped from incoming messages. * `avatar_removal`: Avatars from these servers will be stripped from incoming messages. * `banner_removal`: Banner images from these servers will be stripped from incoming messages. +* `background_removal`: User background images from these servers will be stripped from incoming messages. * `report_removal`: Servers in this group will have their reports (flags) rejected. * `federated_timeline_removal`: Servers in this group will have their messages unlisted from the public timelines by flipping the `to` and `cc` fields. * `reject_deletes`: Deletion requests will be rejected from these servers. @@ -61,6 +62,32 @@ config :pleroma, :mrf_simple, The effects of MRF policies can be very drastic. It is important to use this functionality carefully. Always try to talk to an admin before writing an MRF policy concerning their instance. +## Hiding or Obfuscating Policies + +You can opt out of publicly displaying all MRF policies or only hide or obfuscate selected domains. + +To just hide everything set: + +```elixir +config :pleroma, :mrf, + ... + transparency: false, +``` + +To hide or obfuscate only select entries, use: + +```elixir +config :pleroma, :mrf, + ... + transparency_obfuscate_domains: ["handholdi.ng", "badword.com"], + transparency_exclusions: [{"ghost.club", "even a fragment is too spoopy for humans"}] +``` + +## More MRF Policies + +See the [documentation cheatsheet](cheatsheet.md) +for all available MRF policies and their options. + ## Writing your own MRF Policy As discussed above, the MRF system is a modular system that supports pluggable policies. This means that an admin may write a custom MRF policy in Elixir or any other language that runs on the Erlang VM, by specifying the module name in the `policies` config setting. diff --git a/docs/docs/configuration/optimisation/optimizing_beam.md b/docs/docs/configuration/optimisation/optimizing_beam.md index bbdc49725..747773f3e 100644 --- a/docs/docs/configuration/optimisation/optimizing_beam.md +++ b/docs/docs/configuration/optimisation/optimizing_beam.md @@ -25,11 +25,14 @@ Tuning the BEAM requires you provide a config file normally called [vm.args](htt `ExecStart=/usr/bin/elixir --erl '-args_file /opt/akkoma/config/vm.args' -S /usr/bin/mix phx.server` +If using an OTP release, set the `RELEASE_VM_ARGS` environment variable to the path to the vm.args file. + Check your OS documentation to adopt a similar strategy on other platforms. ### Virtual Machine and/or few CPU cores -Disable the busy-waiting. This should generally only be done if you're on a platform that does burst scheduling, like AWS. +Disable the busy-waiting. This should generally be done if you're on a platform that does burst scheduling, like AWS, or if you're running other +services on the same machine. **vm.args:** @@ -39,6 +42,8 @@ Disable the busy-waiting. This should generally only be done if you're on a plat +sbwtdio none ``` +These settings are enabled by default for OTP releases + ### Dedicated Hardware Enable more busy waiting, increase the internal maximum limit of BEAM processes and ports. You can use this if you run on dedicated hardware, but it is not necessary. diff --git a/docs/docs/development/API/akkoma_api.md b/docs/docs/development/API/akkoma_api.md new file mode 100644 index 000000000..cc3f7ddec --- /dev/null +++ b/docs/docs/development/API/akkoma_api.md @@ -0,0 +1,146 @@ +# Akkoma API + +Request authentication (if required) and parameters work the same as for [Pleroma API](pleroma_api.md). + +## `/api/v1/akkoma/preferred_frontend/available` +### Returns the available frontends which can be picked as the preferred choice +* Method: `GET` +* Authentication: not required +* Params: none +* Response: JSON +* Example response: +```json +["pleroma-fe/stable"] +``` + +!!! note + There’s also a browser UI under `/akkoma/frontend` + for interactively querying and changing this. + +## `/api/v1/akkoma/preferred_frontend` +### Configures the preferred frontend of this session +* Method: `PUT` +* Authentication: not required +* Params: + * `frontend_name`: STRING containing one of the available frontends +* Response: JSON +* Example response: +```json +{"frontend_name":"pleroma-fe/stable"} +``` + +!!! note + There’s also a browser UI under `/akkoma/frontend` + for interactively querying and changing this. + +## `/api/v1/akkoma/metrics` +### Provides metrics for Prometheus to scrape +* Method: `GET` +* Authentication: required (admin:metrics) +* Params: none +* Response: text +* Example response: +``` +# HELP pleroma_remote_users_total +# TYPE pleroma_remote_users_total gauge +pleroma_remote_users_total 25 +# HELP pleroma_local_statuses_total +# TYPE pleroma_local_statuses_total gauge +pleroma_local_statuses_total 17 +# HELP pleroma_domains_total +# TYPE pleroma_domains_total gauge +pleroma_domains_total 4 +# HELP pleroma_local_users_total +# TYPE pleroma_local_users_total gauge +pleroma_local_users_total 3 +... +``` + +## `/api/v1/akkoma/translation/languages` +### Returns available source and target languages for automated text translation +* Method: `GET` +* Authentication: required +* Params: none +* Response: JSON +* Example response: +```json +{ + "source": [ + {"code":"LV", "name":"Latvian"}, + {"code":"ZH", "name":"Chinese (traditional)"}, + {"code":"EN-US", "name":"English (American)"} + ], + "target": [ + {"code":"EN-GB", "name":"English (British)"}, + {"code":"JP", "name":"Japanese"} + ] +} +``` + +## `/api/v1/akkoma/frontend_settings/:frontend_name` +### Lists all configuration profiles of the selected frontend for the current user +* Method: `GET` +* Authentication: required +* Params: none +* Response: JSON +* Example response: +```json +[ + {"name":"default","version":31} +] +``` + +## `/api/v1/akkoma/frontend_settings/:frontend_name/:profile_name` +### Returns the full selected frontend settings profile of the current user +* Method: `GET` +* Authentication: required +* Params: none +* Response: JSON +* Example response: +```json +{ + "version": 31, + "settings": { + "streaming": true, + "conversationDisplay": "tree", + ... + } +} +``` + +## `/api/v1/akkoma/frontend_settings/:frontend_name/:profile_name` +### Updates the frontend settings profile +* Method: `PUT` +* Authentication: required +* Params: + * `version`: INTEGER + * `settings`: JSON object containing the entire new settings +* Response: JSON +* Example response: +```json +{ + "streaming": false, + "conversationDisplay": "tree", + ... +} +``` + +!!! note + The `version` field must be increased by exactly one on each update + +## `/api/v1/akkoma/frontend_settings/:frontend_name/:profile_name` +### Drops the specified frontend settings profile +* Method: `DELETE` +* Authentication: required +* Params: none +* Response: JSON +* Example response: +```json +{"deleted":"ok"} +``` + + +## `/api/v1/timelines/bubble` +### Returns a timeline for the local and closely related instances +Works like all other Mastodon-API timeline queries with the documented +[Akkoma-specific additions and tweaks](./differences_in_mastoapi_responses.md#timelines). diff --git a/docs/docs/development/API/differences_in_mastoapi_responses.md b/docs/docs/development/API/differences_in_mastoapi_responses.md index 053dc9663..990806cea 100644 --- a/docs/docs/development/API/differences_in_mastoapi_responses.md +++ b/docs/docs/development/API/differences_in_mastoapi_responses.md @@ -1,6 +1,6 @@ # Differences in Mastodon API responses from vanilla Mastodon -A Akkoma instance can be identified by " (compatible; Pleroma )" present in `version` field in response from `/api/v1/instance` +A Akkoma instance can be identified by " (compatible; Akkoma )" present in `version` field in response from `/api/v1/instance` ## Flake IDs @@ -8,20 +8,28 @@ Akkoma uses 128-bit ids as opposed to Mastodon's 64 bits. However, just like Mas ## Timelines +In addition to Mastodon’s timelines, there is also a “bubble timeline” showing +posts from the local instance and a set of closely related instances as chosen +by the administrator. It is available under `/api/v1/timelines/bubble`. + Adding the parameter `with_muted=true` to the timeline queries will also return activities by muted (not by blocked!) users. Adding the parameter `exclude_visibilities` to the timeline queries will exclude the statuses with the given visibilities. The parameter accepts an array of visibility types (`public`, `unlisted`, `private`, `direct`), e.g., `exclude_visibilities[]=direct&exclude_visibilities[]=private`. -Adding the parameter `reply_visibility` to the public and home timelines queries will filter replies. Possible values: without parameter (default) shows all replies, `following` - replies directed to you or users you follow, `self` - replies directed to you. +Adding the parameter `reply_visibility` to the public, bubble or home timelines queries will filter replies. Possible values: without parameter (default) shows all replies, `following` - replies directed to you or users you follow, `self` - replies directed to you. Adding the parameter `instance=lain.com` to the public timeline will show only statuses originating from `lain.com` (or any remote instance). -Home, public, hashtag & list timelines accept these parameters: +All but the direct timeline accept these parameters: - `only_media`: show only statuses with media attached -- `local`: show only local statuses - `remote`: show only remote statuses +Home, public, hashtag & list timelines further accept: + +- `local`: show only local statuses + + ## Statuses - `visibility`: has additional possible values `list` and `local` (for local-only statuses) @@ -113,6 +121,12 @@ Has these additional fields under the `pleroma` object: - `notification_settings`: object, can be absent. See `/api/v1/pleroma/notification_settings` for the parameters/keys returned. - `favicon`: nullable URL string, Favicon image of the user's instance +Has these additional fields under the `akkoma` object: + +- `instance`: nullable object with metadata about the user’s instance +- `status_ttl_days`: nullable int, default time after which statuses are deleted +- `permit_followback`: boolean, whether follows from followed accounts are auto-approved + ### Source Has these additional fields under the `pleroma` object: diff --git a/docs/docs/installation/generic_dependencies.include b/docs/docs/installation/generic_dependencies.include index d8cf9f9da..b23736d85 100644 --- a/docs/docs/installation/generic_dependencies.include +++ b/docs/docs/installation/generic_dependencies.include @@ -2,7 +2,7 @@ * PostgreSQL 9.6+ * Elixir 1.14+ -* Erlang OTP 24+ +* Erlang OTP 25+ * git * file / libmagic * gcc (clang might also work) diff --git a/docs/docs/installation/migrating_to_akkoma.md b/docs/docs/installation/migrating_to_akkoma.md index 4a58e836e..bf6eeebc7 100644 --- a/docs/docs/installation/migrating_to_akkoma.md +++ b/docs/docs/installation/migrating_to_akkoma.md @@ -21,6 +21,33 @@ fork of Akkoma - luckily this isn't very hard. You'll need to update the backend, then possibly the frontend, depending on your setup. +## Backup diverging features + +As time goes on Akkoma and Pleroma added or removed different features +and reorganised the database in a different way. If you want to be able to +migrate back to Pleroma without losing any affected data, you’ll want to +make a backup before starting the migration. +If you're not interested in migrating back, skip this section +*(although it might be a good idea to temporarily keep a full DB backup +just in case something unexpected happens during migration)* + +As of 2024-02 you will want to keep a backup of: + +- the entire `chats` and `chat_message_references` tables + +The following columns are not deleted by a migration to Akkoma, but a migration +back to Pleroma or future Akkoma upgrades might affect them, so perhaps back them up as well: + +- the `birthday` of users and their `show_birthday` setting +- the `expires_at` key of in the `user_relationships` table + *(used by temporary mutes)* + +The way cached instance metadata is stored differs, but since those +will be refetched and updated anyway, there’s no need for a backup. + +Best check all newer migrations unique to Akkoma/Pleroma +to get an up-to-date picture of what needs to be kept. + ## From Source If you're running the source Akkoma install, you'll need to set the @@ -34,16 +61,7 @@ git pull -r # to run "git merge stable" instead (or develop if you want) ``` -### WARNING - Migrating from Pleroma Develop -If you are on pleroma develop, and have updated since 2022-08, you may have issues with database migrations. - -Please roll back the given migrations: - -```bash -MIX_ENV=prod mix ecto.rollback --migrations-path priv/repo/optional_migrations/pleroma_develop_rollbacks -n3 -``` - -Then compile, migrate and restart as usual. +And compile as usual. ## From OTP @@ -53,15 +71,44 @@ This will just be setting the update URL - find your flavour from the [mapping o export FLAVOUR=[the flavour you found above] ./bin/pleroma_ctl update --zip-url https://akkoma-updates.s3-website.fr-par.scw.cloud/stable/akkoma-$FLAVOUR.zip -./bin/pleroma_ctl migrate ``` -Then restart. When updating in the future, you canjust use +When updating in the future, you can just use ```bash ./bin/pleroma_ctl update --branch stable ``` + +## Database Migrations +### WARNING - Migrating from Pleroma past 2022-08 +If you are on Pleroma stable >= 2.5.0 or Pleroma develop, and +have updated since 2022-08, you may have issues with database migrations. + +Please first roll back the given migrations: + +=== "OTP" + ```bash + ./bin/pleroma_ctl rollback --migrations-path priv/repo/optional_migrations/pleroma_develop_rollbacks -n5 + ``` +=== "From Source" + ```bash + MIX_ENV=prod mix ecto.rollback --migrations-path priv/repo/optional_migrations/pleroma_develop_rollbacks -n5 + ``` + +### Applying Akkoma Database Migrations + +Just run + +=== "OTP" + ```bash + ./bin/pleroma_ctl migrate + ``` +=== "From Source" + ```bash + MIX_ENV=prod mix ecto.migrate + ``` + ## Frontend changes Akkoma comes with a few frontend changes as well as backend ones, @@ -130,3 +177,4 @@ MIX_ENV=prod mix ecto.rollback --to 20210416051708 ``` Then switch back to Pleroma for updates (similar to how was done to migrate to Akkoma), and remove the front-ends. The front-ends are installed in the `frontends` folder in the [static directory](../configuration/static_dir.md). Once you are back to Pleroma, you will need to run the database migrations again. See the Pleroma documentation for this. +After this use your previous backups to restore data from diverging features. diff --git a/docs/docs/installation/otp_en.md b/docs/docs/installation/otp_en.md index b613e17b2..8a8ae077b 100644 --- a/docs/docs/installation/otp_en.md +++ b/docs/docs/installation/otp_en.md @@ -5,7 +5,7 @@ This guide covers a installation using an OTP release. To install Akkoma from source, please check out the corresponding guide for your distro. ## Pre-requisites -* A machine running Linux with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and an `x86_64` CPU you have root access to. If you are not sure if it's compatible see [Detecting flavour section](#detecting-flavour) below +* A machine running Linux with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and an `x86_64` or `arm64` CPU you have root access to. If you are not sure if it's compatible see [Detecting flavour section](#detecting-flavour) below * For installing OTP releases on RedHat-based distros like Fedora and Centos Stream, please follow [this guide](./otp_redhat_en.md) instead. * A (sub)domain pointed to the machine @@ -187,18 +187,18 @@ The location of nginx configs is dependent on the distro === "Alpine" ``` - cp /opt/akkoma/installation/nginx/akkoma.nginx /etc/nginx/conf.d/akkoma.conf + cp /opt/akkoma/installation/akkoma.nginx /etc/nginx/conf.d/akkoma.conf ``` === "Debian/Ubuntu" ``` - cp /opt/akkoma/installation/nginx/akkoma.nginx /etc/nginx/sites-available/akkoma.conf + cp /opt/akkoma/installation/akkoma.nginx /etc/nginx/sites-available/akkoma.conf ln -s /etc/nginx/sites-available/akkoma.conf /etc/nginx/sites-enabled/akkoma.conf ``` If your distro does not have either of those you can append `include /etc/nginx/akkoma.conf` to the end of the http section in /etc/nginx/nginx.conf and ```sh -cp /opt/akkoma/installation/nginx/akkoma.nginx /etc/nginx/akkoma.conf +cp /opt/akkoma/installation/akkoma.nginx /etc/nginx/akkoma.conf ``` #### Edit the nginx config diff --git a/docs/docs/installation/otp_redhat_en.md b/docs/docs/installation/otp_redhat_en.md index 1490d3139..ea27af6f4 100644 --- a/docs/docs/installation/otp_redhat_en.md +++ b/docs/docs/installation/otp_redhat_en.md @@ -178,7 +178,7 @@ certbot certonly --standalone --preferred-challenges http -d yourinstance.tld #### Copy Akkoma nginx configuration to the nginx folder ```shell -cp /opt/akkoma/installation/nginx/akkoma.nginx /etc/nginx/conf.d/akkoma.conf +cp /opt/akkoma/installation/akkoma.nginx /etc/nginx/conf.d/akkoma.conf ``` #### Edit the nginx config diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex index 5dedf276a..8dda1512d 100644 --- a/lib/mix/tasks/pleroma/emoji.ex +++ b/lib/mix/tasks/pleroma/emoji.ex @@ -130,6 +130,7 @@ def run(["get-packs" | args]) do } File.write!(Path.join(pack_path, "pack.json"), Jason.encode!(pack_json, pretty: true)) + Pleroma.Emoji.reload() else IO.puts(IO.ANSI.format([:bright, :red, "No pack named \"#{pack_name}\" found"])) end @@ -235,6 +236,8 @@ def run(["gen-pack" | args]) do IO.puts("#{pack_file} has been created with the #{name} pack") end + + Pleroma.Emoji.reload() end def run(["reload"]) do diff --git a/lib/mix/tasks/pleroma/search/meilisearch.ex b/lib/mix/tasks/pleroma/search/meilisearch.ex index 27a31afcf..299fb5b14 100644 --- a/lib/mix/tasks/pleroma/search/meilisearch.ex +++ b/lib/mix/tasks/pleroma/search/meilisearch.ex @@ -30,12 +30,12 @@ def run(["index"]) do meili_put( "/indexes/objects/settings/ranking-rules", [ - "published:desc", "words", - "exactness", "proximity", "typo", + "exactness", "attribute", + "published:desc", "sort" ] ) diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 4ca1c28eb..1a8e866ef 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -11,6 +11,7 @@ defmodule Mix.Tasks.Pleroma.User do alias Pleroma.UserInviteToken alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.Pipeline + use Pleroma.Web, :verified_routes @shortdoc "Manages Pleroma users" @moduledoc File.read!("docs/docs/administration/CLI_tasks/user.md") @@ -113,11 +114,7 @@ def run(["reset_password", nickname]) do {:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do shell_info("Generated password reset token for #{user.nickname}") - IO.puts( - "URL: #{Pleroma.Web.Router.Helpers.reset_password_url(Pleroma.Web.Endpoint, - :reset, - token.token)}" - ) + IO.puts("URL: #{~p[/api/v1/pleroma/password_reset/#{token.token}]}") else _ -> shell_error("No local user #{nickname}") @@ -303,13 +300,7 @@ def run(["invite" | rest]) do {:ok, invite} <- UserInviteToken.create_invite(options) do shell_info("Generated user invite token " <> String.replace(invite.invite_type, "_", " ")) - url = - Pleroma.Web.Router.Helpers.redirect_url( - Pleroma.Web.Endpoint, - :registration_page, - invite.token - ) - + url = url(~p[/registration/#{invite.token}]) IO.puts(url) else error -> diff --git a/lib/phoenix/transports/web_socket/raw.ex b/lib/phoenix/transports/web_socket/raw.ex index 8ed64eb16..72def9dff 100644 --- a/lib/phoenix/transports/web_socket/raw.ex +++ b/lib/phoenix/transports/web_socket/raw.ex @@ -26,7 +26,6 @@ def init(%Plug.Conn{method: "GET"} = conn, {endpoint, handler, transport}) do conn |> fetch_query_params |> Transport.transport_log(opts[:transport_log]) - |> Transport.force_ssl(handler, endpoint, opts) |> Transport.check_origin(handler, endpoint, opts) case conn do diff --git a/lib/pleroma/activity/pruner.ex b/lib/pleroma/activity/pruner.ex index 7f561ebae..54a40b534 100644 --- a/lib/pleroma/activity/pruner.ex +++ b/lib/pleroma/activity/pruner.ex @@ -26,6 +26,15 @@ def prune_undos do |> Repo.delete_all(timeout: :infinity) end + def prune_updates do + before_time = cutoff() + + from(a in Activity, + where: fragment("?->>'type' = ?", a.data, "Update") and a.inserted_at < ^before_time + ) + |> Repo.delete_all(timeout: :infinity) + end + def prune_removes do before_time = cutoff() diff --git a/lib/pleroma/config/release_runtime_provider.ex b/lib/pleroma/config/release_runtime_provider.ex index a829a0206..d8818dfee 100644 --- a/lib/pleroma/config/release_runtime_provider.ex +++ b/lib/pleroma/config/release_runtime_provider.ex @@ -23,7 +23,7 @@ def load(config, opts) do with_runtime_config = if File.exists?(config_path) do # - %File.Stat{mode: mode} = File.lstat!(config_path) + %File.Stat{mode: mode} = File.stat!(config_path) if Bitwise.band(mode, 0o007) > 0 do raise "Configuration at #{config_path} has world-permissions, execute the following: chmod o= #{config_path}" diff --git a/lib/pleroma/emails/admin_email.ex b/lib/pleroma/emails/admin_email.ex index 88bc78aec..683de8e3b 100644 --- a/lib/pleroma/emails/admin_email.ex +++ b/lib/pleroma/emails/admin_email.ex @@ -6,10 +6,13 @@ defmodule Pleroma.Emails.AdminEmail do @moduledoc "Admin emails" import Swoosh.Email - + use Pleroma.Web, :mailer alias Pleroma.Config alias Pleroma.HTML - alias Pleroma.Web.Router.Helpers + + use Phoenix.VerifiedRoutes, + endpoint: Pleroma.Web.Endpoint, + router: Pleroma.Web.Router defp instance_config, do: Config.get(:instance) defp instance_name, do: instance_config()[:name] @@ -45,7 +48,7 @@ def report(to, reporter, account, statuses, comment) do statuses |> Enum.map(fn %{id: id} -> - status_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, id) + status_url = url(~p[/notice/#{id}]) "
  • #{status_url}
  • " %{"id" => id} when is_binary(id) -> diff --git a/lib/pleroma/emails/mailer.ex b/lib/pleroma/emails/mailer.ex index d42236c5e..6a79a7694 100644 --- a/lib/pleroma/emails/mailer.ex +++ b/lib/pleroma/emails/mailer.ex @@ -55,12 +55,61 @@ def deliver!(email, config) do @doc false def validate_dependency do - parse_config([]) + parse_config([], defaults: false) |> Keyword.get(:adapter) |> Swoosh.Mailer.validate_dependency() end - defp parse_config(config) do - Swoosh.Mailer.parse_config(@otp_app, __MODULE__, @mailer_config, config) + defp ensure_charlist(input) do + case input do + i when is_binary(i) -> String.to_charlist(input) + i when is_list(i) -> i + end + end + + defp default_config(adapter, conf, opts) + + defp default_config(_, _, defaults: false) do + [] + end + + defp default_config(Swoosh.Adapters.SMTP, conf, _) do + # gen_smtp and Erlang's tls defaults are very barebones, if nothing is set. + # Add sane defaults for our usecase to make config less painful for admins + relay = ensure_charlist(Keyword.get(conf, :relay)) + ssl_disabled = Keyword.get(conf, :ssl) === false + os_cacerts = :public_key.cacerts_get() + + common_tls_opts = [ + cacerts: os_cacerts, + versions: [:"tlsv1.2", :"tlsv1.3"], + verify: :verify_peer, + # some versions have supposedly issues verifying wildcard certs without this + server_name_indication: relay, + # the default of 10 is too restrictive + depth: 32 + ] + + [ + auth: :always, + no_mx_lookups: false, + # Direct SSL/TLS + # (if ssl was explicitly disabled, we must not pass TLS options to the socket) + ssl: true, + sockopts: if(ssl_disabled, do: [], else: common_tls_opts), + # STARTTLS upgrade (can't be set to :always when already using direct TLS) + tls: :if_available, + tls_options: common_tls_opts + ] + end + + defp default_config(_, _, _), do: [] + + defp parse_config(config, opts \\ []) do + conf = Swoosh.Mailer.parse_config(@otp_app, __MODULE__, @mailer_config, config) + adapter = Keyword.get(conf, :adapter) + + default_config(adapter, conf, opts) + |> Keyword.merge(conf) end end diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex index 1588c099c..a7bcc03b6 100644 --- a/lib/pleroma/emails/user_email.ex +++ b/lib/pleroma/emails/user_email.ex @@ -6,12 +6,11 @@ defmodule Pleroma.Emails.UserEmail do @moduledoc "User emails" require Pleroma.Web.Gettext + use Pleroma.Web, :mailer alias Pleroma.Config alias Pleroma.User - alias Pleroma.Web.Endpoint alias Pleroma.Web.Gettext - alias Pleroma.Web.Router import Swoosh.Email import Phoenix.Swoosh, except: [render_body: 3] @@ -75,7 +74,7 @@ def welcome(user, opts \\ %{}) do def password_reset_email(user, token) when is_binary(token) do Gettext.with_locale_or_default user.language do - password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token) + password_reset_url = url(~p[/api/v1/pleroma/password_reset/#{token}]) html_body = Gettext.dpgettext( @@ -108,12 +107,7 @@ def user_invitation_email( to_name \\ nil ) do Gettext.with_locale_or_default user.language do - registration_url = - Router.Helpers.redirect_url( - Endpoint, - :registration_page, - user_invite_token.token - ) + registration_url = url(~p[/registration/#{user_invite_token.token}]) html_body = Gettext.dpgettext( @@ -146,13 +140,7 @@ def user_invitation_email( def account_confirmation_email(user) do Gettext.with_locale_or_default user.language do - confirmation_url = - Router.Helpers.confirm_email_url( - Endpoint, - :confirm_email, - user.id, - to_string(user.confirmation_token) - ) + confirmation_url = url(~p[/api/account/confirm_email/#{user.id}/#{user.confirmation_token}]) html_body = Gettext.dpgettext( @@ -342,7 +330,7 @@ def unsubscribe_url(user, notifications_type) do |> Pleroma.JWT.generate_and_sign!() |> Base.encode64() - Router.Helpers.subscription_url(Endpoint, :unsubscribe, token) + url(~p[/mailer/unsubscribe/#{token}]) end def backup_is_ready_email(backup, admin_user_id \\ nil) do diff --git a/lib/pleroma/job_queue_monitor.ex b/lib/pleroma/job_queue_monitor.ex index b5f124923..8d81ffcac 100644 --- a/lib/pleroma/job_queue_monitor.ex +++ b/lib/pleroma/job_queue_monitor.ex @@ -15,8 +15,19 @@ def start_link(_) do @impl true def init(state) do - :telemetry.attach("oban-monitor-failure", [:oban, :job, :exception], &handle_event/4, nil) - :telemetry.attach("oban-monitor-success", [:oban, :job, :stop], &handle_event/4, nil) + :telemetry.attach( + "oban-monitor-failure", + [:oban, :job, :exception], + &Pleroma.JobQueueMonitor.handle_event/4, + nil + ) + + :telemetry.attach( + "oban-monitor-success", + [:oban, :job, :stop], + &Pleroma.JobQueueMonitor.handle_event/4, + nil + ) {:ok, state} end diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex index b44f0b90a..bb4f4def3 100644 --- a/lib/pleroma/reverse_proxy.ex +++ b/lib/pleroma/reverse_proxy.ex @@ -61,11 +61,14 @@ def default_cache_control_header, do: @default_cache_control_header """ @inline_content_types [ + "image/avif", "image/gif", "image/jpeg", "image/jpg", + "image/jxl", "image/png", "image/svg+xml", + "image/webp", "audio/mpeg", "audio/mp3", "video/webm", diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex index b229e6296..3d33fcd62 100644 --- a/lib/pleroma/signature.ex +++ b/lib/pleroma/signature.ex @@ -76,6 +76,6 @@ def sign(%User{keys: keys} = user, headers) do def signed_date, do: signed_date(NaiveDateTime.utc_now()) def signed_date(%NaiveDateTime{} = date) do - Timex.format!(date, "{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT") + Timex.lformat!(date, "{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT", "en") end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 83b45e3b4..8449af620 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -44,6 +44,8 @@ defmodule Pleroma.User do alias Pleroma.Web.RelMe alias Pleroma.Workers.BackgroundWorker + use Pleroma.Web, :verified_routes + require Logger @type t :: %__MODULE__{} @@ -158,6 +160,7 @@ defmodule Pleroma.User do field(:last_status_at, :naive_datetime) field(:language, :string) field(:status_ttl_days, :integer, default: nil) + field(:permit_followback, :boolean, default: false) field(:accepts_direct_messages_from, Ecto.Enum, values: [:everybody, :people_i_follow, :nobody], @@ -379,6 +382,10 @@ def banner_url(user, options \\ []) do do_optional_url(user.banner, "#{Endpoint.url()}/images/banner.png", options) end + def background_url(user) do + do_optional_url(user.background, nil, no_default: true) + end + defp do_optional_url(field, default, options) do case field do %{"url" => [%{"href" => href} | _]} when is_binary(href) -> @@ -463,6 +470,7 @@ def remote_user_changeset(struct \\ %User{local: false}, params) do :avatar, :ap_enabled, :banner, + :background, :is_locked, :last_refreshed_at, :uri, @@ -542,6 +550,7 @@ def update_changeset(struct, params \\ %{}) do :actor_type, :disclose_client, :status_ttl_days, + :permit_followback, :accepts_direct_messages_from ] ) @@ -970,16 +979,21 @@ def needs_update?(%User{local: false} = user) do def needs_update?(_), do: true + # "Locked" (self-locked) users demand explicit authorization of follow requests + @spec can_direct_follow_local(User.t(), User.t()) :: true | false + def can_direct_follow_local(%User{} = follower, %User{local: true} = followed) do + !followed.is_locked || (followed.permit_followback and is_friend_of(follower, followed)) + end + @spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t(), User.t()} | {:error, String.t()} - # "Locked" (self-locked) users demand explicit authorization of follow requests - def maybe_direct_follow(%User{} = follower, %User{local: true, is_locked: true} = followed) do - follow(follower, followed, :follow_pending) - end - def maybe_direct_follow(%User{} = follower, %User{local: true} = followed) do - follow(follower, followed) + if can_direct_follow_local(follower, followed) do + follow(follower, followed) + else + follow(follower, followed, :follow_pending) + end end def maybe_direct_follow(%User{} = follower, %User{} = followed) do @@ -1329,6 +1343,13 @@ def get_friends_ids(%User{} = user, page \\ nil) do |> Repo.all() end + def is_friend_of(%User{} = potential_friend, %User{local: true} = user) do + user + |> get_friends_query() + |> where(id: ^potential_friend.id) + |> Repo.exists?() + end + def increase_note_count(%User{} = user) do User |> where(id: ^user.id) @@ -1603,9 +1624,13 @@ def blocks_user?(%User{} = user, %User{} = target) do def blocks_user?(_, _), do: false def blocks_domain?(%User{} = user, %User{} = target) do - domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.domain_blocks) %{host: host} = URI.parse(target.ap_id) - Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host) + Enum.member?(user.domain_blocks, host) + # TODO: functionality should probably be changed such that subdomains block as well, + # but as it stands, this just hecks up the relationships endpoint + # domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.domain_blocks) + # %{host: host} = URI.parse(target.ap_id) + # Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host) end def blocks_domain?(_, _), do: false @@ -2447,12 +2472,7 @@ defp validate_rel_me_field(changeset, fields, raw_fields, %User{ end if is_url(raw_value) do - frontend_url = - Pleroma.Web.Router.Helpers.redirect_url( - Pleroma.Web.Endpoint, - :redirector_with_meta, - nickname - ) + frontend_url = url(~p[/#{nickname}]) possible_urls = [ap_id, frontend_url] diff --git a/lib/pleroma/web.ex b/lib/pleroma/web.ex index ecd98b6ca..5422e7896 100644 --- a/lib/pleroma/web.ex +++ b/lib/pleroma/web.ex @@ -27,6 +27,7 @@ defmodule Pleroma.Web do alias Pleroma.Web.Plugs.ExpectPublicOrAuthenticatedCheckPlug alias Pleroma.Web.Plugs.OAuthScopesPlug alias Pleroma.Web.Plugs.PlugHelper + require Pleroma.Constants def controller do quote do @@ -37,7 +38,7 @@ def controller do import Pleroma.Web.Gettext import Pleroma.Web.TranslationHelpers - alias Pleroma.Web.Router.Helpers, as: Routes + unquote(verified_routes()) plug(:set_put_layout) @@ -184,7 +185,10 @@ def view do # Import convenience functions from controllers import Phoenix.Controller, - only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1] + only: [view_module: 1, view_template: 1] + + import Phoenix.Flash + alias Phoenix.Flash # Include shared imports and aliases for views unquote(view_helpers()) @@ -218,7 +222,7 @@ def component do def router do quote do - use Phoenix.Router + use Phoenix.Router, helpers: false import Plug.Conn import Phoenix.Controller @@ -246,7 +250,24 @@ defp view_helpers do import Pleroma.Web.ErrorHelpers import Pleroma.Web.Gettext - alias Pleroma.Web.Router.Helpers, as: Routes + unquote(verified_routes()) + end + end + + def static_paths, do: Pleroma.Constants.static_only_files() + + def verified_routes do + quote do + use Phoenix.VerifiedRoutes, + endpoint: Pleroma.Web.Endpoint, + router: Pleroma.Web.Router, + statics: Pleroma.Web.static_paths() + end + end + + def mailer do + quote do + unquote(verified_routes()) end end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 649bf9095..4a8ce2d3d 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1603,6 +1603,7 @@ defp object_to_user_data(data, additional) do uri: get_actor_url(data["url"]), ap_enabled: true, banner: normalize_image(data["image"]), + background: normalize_image(data["backgroundUrl"]), fields: fields, emoji: emojis, is_locked: is_locked, @@ -1792,6 +1793,11 @@ def pin_data_from_featured_collection( end) end + def pin_data_from_featured_collection(obj) do + Logger.error("Could not parse featured collection #{inspect(obj)}") + %{} + end + def fetch_and_prepare_featured_from_ap_id(nil) do {:ok, %{}} end diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex index 6d39ad3a8..e67a14b58 100644 --- a/lib/pleroma/web/activity_pub/builder.ex +++ b/lib/pleroma/web/activity_pub/builder.ex @@ -18,6 +18,8 @@ defmodule Pleroma.Web.ActivityPub.Builder do alias Pleroma.Web.CommonAPI.ActivityDraft alias Pleroma.Web.Endpoint + use Pleroma.Web, :verified_routes + require Pleroma.Constants def accept_or_reject(actor, activity, type) do @@ -402,6 +404,6 @@ def unpin(%User{} = user, object) do end defp pinned_url(nickname) when is_binary(nickname) do - Pleroma.Web.Router.Helpers.activity_pub_url(Pleroma.Web.Endpoint, :pinned, nickname) + url(~p[/users/#{nickname}/collections/featured]) end end diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index ba54eb674..0b8b846ec 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -178,6 +178,23 @@ defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image defp check_banner_removal(_actor_info, object), do: {:ok, object} + defp check_background_removal( + %{host: actor_host} = _actor_info, + %{"backgroundUrl" => _bg} = object + ) do + background_removal = + instance_list(:background_removal) + |> MRF.subdomains_regex() + + if MRF.subdomain_match?(background_removal, actor_host) do + {:ok, Map.delete(object, "backgroundUrl")} + else + {:ok, object} + end + end + + defp check_background_removal(_actor_info, object), do: {:ok, object} + defp extract_context_uri(%{"conversation" => "tag:" <> rest}) do rest |> String.split(",", parts: 2, trim: true) @@ -283,7 +300,8 @@ def filter(%{"id" => actor, "type" => obj_type} = object) with {:ok, _} <- check_accept(actor_info), {:ok, _} <- check_reject(actor_info), {:ok, object} <- check_avatar_removal(actor_info, object), - {:ok, object} <- check_banner_removal(actor_info, object) do + {:ok, object} <- check_banner_removal(actor_info, object), + {:ok, object} <- check_background_removal(actor_info, object) do {:ok, object} else {:reject, nil} -> {:reject, "[SimplePolicy]"} @@ -314,6 +332,20 @@ def filter(object) when is_binary(object) do def filter(object), do: {:ok, object} defp obfuscate(string) when is_binary(string) do + # Want to strip at least two neighbouring chars + # to ensure at least one non-dot char is in the obfuscation area + stripped = String.length(string) - 6 + + {keepstart, keepend} = + if stripped > 1 do + {3, 3} + else + { + 2 - div(1 - stripped, 2), + 2 + div(stripped, 2) + } + end + string |> to_charlist() |> Enum.with_index() @@ -322,7 +354,7 @@ defp obfuscate(string) when is_binary(string) do ?. {char, index} -> - if 3 <= index && index < String.length(string) - 3, do: ?*, else: char + if keepstart <= index && index < String.length(string) - keepend, do: ?*, else: char end) |> to_string() end @@ -433,6 +465,11 @@ def config_description do key: :banner_removal, description: "List of instances to strip banners from and the reason for doing so" }, + %{ + key: :background_removal, + description: + "List of instances to strip user backgrounds from and the reason for doing so" + }, %{ key: :reject_deletes, description: "List of instances to reject deletions from and the reason for doing so" diff --git a/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex b/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex index 45b2d4ca7..02a107c27 100644 --- a/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex @@ -34,6 +34,7 @@ defp steal_emoji({shortcode, url}, emoji_dir_path) do |> Path.basename() |> Path.extname() + shortcode = Path.basename(shortcode) file_path = Path.join(emoji_dir_path, shortcode <> (extension || ".png")) case File.write(file_path, response.body) do @@ -76,6 +77,9 @@ def filter(%{"object" => %{"emoji" => foreign_emojis, "actor" => actor}} = messa new_emojis = foreign_emojis |> Enum.reject(fn {shortcode, _url} -> shortcode in installed_emoji end) + |> Enum.reject(fn {shortcode, _url} -> + String.contains?(shortcode, ["/", "\\", ".", ":"]) + end) |> Enum.filter(fn {shortcode, _url} -> reject_emoji? = [:mrf_steal_emoji, :rejected_shortcodes] diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 34617a218..963c6d8c6 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -109,7 +109,7 @@ def handle( %User{} = followed <- User.get_cached_by_ap_id(followed_user), {_, {:ok, _, _}, _, _} <- {:following, User.follow(follower, followed, :follow_pending), follower, followed} do - if followed.local && !followed.is_locked do + if followed.local && User.can_direct_follow_local(follower, followed) do {:ok, accept_data, _} = Builder.accept(followed, object) {:ok, _activity, _} = Pipeline.common_pipeline(accept_data, local: true) end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 008aec475..f731b5286 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -16,10 +16,11 @@ defmodule Pleroma.Web.ActivityPub.Utils do alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.Endpoint - alias Pleroma.Web.Router.Helpers import Ecto.Query + use Pleroma.Web, :verified_routes + require Logger require Pleroma.Constants @@ -124,19 +125,15 @@ def make_date do end def generate_activity_id do - generate_id("activities") + url(~p[/activities/#{UUID.generate()}]) end def generate_context_id do - generate_id("contexts") + url(~p[/contexts/#{UUID.generate()}]) end def generate_object_id do - Helpers.o_status_url(Endpoint, :object, UUID.generate()) - end - - def generate_id(type) do - "#{Endpoint.url()}/#{type}/#{UUID.generate()}" + url(~p[/objects/#{UUID.generate()}]) end def get_notified_from_object(%{"type" => type} = object) when type in @supported_object_types do @@ -154,7 +151,7 @@ def get_notified_from_object(object) do Notification.get_notified_from_activity(%Activity{data: object}, false) end - def maybe_create_context(context), do: context || generate_id("contexts") + def maybe_create_context(context), do: context || generate_context_id() @doc """ Enqueues an activity for federation if it's local diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 7333fb2c1..fe70022f1 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -12,24 +12,22 @@ defmodule Pleroma.Web.ActivityPub.UserView do alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils - alias Pleroma.Web.Endpoint - alias Pleroma.Web.Router.Helpers require Pleroma.Web.ActivityPub.Transmogrifier import Ecto.Query def render("endpoints.json", %{user: %User{nickname: nil, local: true} = _user}) do - %{"sharedInbox" => Helpers.activity_pub_url(Endpoint, :inbox)} + %{"sharedInbox" => url(~p"/inbox")} end def render("endpoints.json", %{user: %User{local: true} = _user}) do %{ - "oauthAuthorizationEndpoint" => Helpers.o_auth_url(Endpoint, :authorize), - "oauthRegistrationEndpoint" => Helpers.app_url(Endpoint, :create), - "oauthTokenEndpoint" => Helpers.o_auth_url(Endpoint, :token_exchange), - "sharedInbox" => Helpers.activity_pub_url(Endpoint, :inbox), - "uploadMedia" => Helpers.activity_pub_url(Endpoint, :upload_media) + "oauthAuthorizationEndpoint" => url(~p"/oauth/authorize"), + "oauthRegistrationEndpoint" => url(~p"/api/v1/apps"), + "oauthTokenEndpoint" => url(~p"/oauth/token"), + "sharedInbox" => url(~p"/inbox"), + "uploadMedia" => url(~p"/api/ap/upload_media") } end @@ -48,6 +46,7 @@ def render("service.json", %{user: user}) do "following" => "#{user.ap_id}/following", "followers" => "#{user.ap_id}/followers", "inbox" => "#{user.ap_id}/inbox", + "outbox" => "#{user.ap_id}/outbox", "name" => "Pleroma", "summary" => "An internal service actor for this Pleroma instance. No user-serviceable parts inside.", @@ -113,6 +112,8 @@ def render("user.json", %{user: user}) do } |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user)) |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user)) + # Yes, the key is named ...Url eventhough it is a whole 'Image' object + |> Map.merge(maybe_insert_image("backgroundUrl", User.background_url(user))) |> Map.merge(Utils.make_json_ld_header()) end @@ -288,7 +289,12 @@ def collection(collection, iri, page, show_items \\ true, total \\ nil) do end defp maybe_make_image(func, key, user) do - if image = func.(user, no_default: true) do + image = func.(user, no_default: true) + maybe_insert_image(key, image) + end + + defp maybe_insert_image(key, image) do + if image do %{ key => %{ "type" => "Image", diff --git a/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex b/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex index 1d7ac78a0..7344e1f77 100644 --- a/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex @@ -17,9 +17,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Web.AdminAPI alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.AdminAPI.ModerationLogView - alias Pleroma.Web.Endpoint alias Pleroma.Web.Plugs.OAuthScopesPlug - alias Pleroma.Web.Router @users_page_size 50 @@ -256,7 +254,7 @@ def get_password_reset(conn, %{"nickname" => nickname}) do conn |> json(%{ token: token.token, - link: Router.Helpers.reset_password_url(Endpoint, :reset, token.token) + link: url(~p[/api/v1/pleroma/password_reset/#{token.token}]) }) end diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index 2d14316d1..c15a246f2 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -451,6 +451,20 @@ def endorsements_operation do } end + def preferences_operation do + %Operation{ + tags: ["Account Preferences"], + description: "Preferences defined by the user in their account settings.", + summary: "Preferred common behaviors to be shared across clients.", + operationId: "AccountController.preferences", + security: [%{"oAuth" => ["read:accounts"]}], + responses: %{ + 200 => Operation.response("Preferences", "application/json", Account), + 401 => Operation.response("Error", "application/json", ApiError) + } + } + end + def identity_proofs_operation do %Operation{ tags: ["Retrieve account information"], @@ -709,6 +723,12 @@ defp update_credentials_request do description: "Number of days after which statuses will be deleted. Set to -1 to disable." }, + permit_followback: %Schema{ + allOf: [BooleanLike], + nullable: true, + description: + "Whether follow requests from accounts the user is already following are auto-approved (when locked)." + }, accepts_direct_messages_from: %Schema{ type: :string, enum: [ @@ -740,6 +760,7 @@ defp update_credentials_request do discoverable: false, actor_type: "Person", status_ttl_days: 30, + permit_followback: true, accepts_direct_messages_from: "everybody" } } diff --git a/lib/pleroma/web/api_spec/operations/frontend_settings_operation.ex b/lib/pleroma/web/api_spec/operations/frontend_settings_operation.ex index 867a751b3..ede66709c 100644 --- a/lib/pleroma/web/api_spec/operations/frontend_settings_operation.ex +++ b/lib/pleroma/web/api_spec/operations/frontend_settings_operation.ex @@ -111,9 +111,9 @@ def available_frontends_operation() do def update_preferred_frontend_operation() do %Operation{ tags: ["Frontends"], - summary: "Frontend Settings Profiles", - description: "List frontend setting profiles", - operationId: "AkkomaAPI.FrontendSettingsController.available_frontends", + summary: "Update preferred frontend setting", + description: "Store preferred frontend in cookies", + operationId: "AkkomaAPI.FrontendSettingsController.update_preferred_frontend", requestBody: request_body( "Frontend", @@ -132,9 +132,11 @@ def update_preferred_frontend_operation() do responses: %{ 200 => Operation.response("Frontends", "application/json", %Schema{ - type: :array, - items: %Schema{ - type: :string + type: :object, + properties: %{ + frontend_name: %Schema{ + type: :string + } } }) } diff --git a/lib/pleroma/web/api_spec/operations/instance_operation.ex b/lib/pleroma/web/api_spec/operations/instance_operation.ex index 9384acc32..c72fee197 100644 --- a/lib/pleroma/web/api_spec/operations/instance_operation.ex +++ b/lib/pleroma/web/api_spec/operations/instance_operation.ex @@ -137,7 +137,7 @@ defp instance do "background_upload_limit" => 4_000_000, "background_image" => "/static/image.png", "banner_upload_limit" => 4_000_000, - "description" => "Pleroma: An efficient and flexible fediverse server", + "description" => "Akkoma: The cooler fediverse server", "email" => "lain@lain.com", "languages" => ["en"], "max_toot_chars" => 5000, @@ -160,7 +160,7 @@ defp instance do "urls" => %{ "streaming_api" => "wss://lain.com" }, - "version" => "2.7.2 (compatible; Pleroma 2.0.50-536-g25eec6d7-develop)" + "version" => "2.7.2 (compatible; Akkoma 3.9.3-232-g6fde75e1-develop)" } } end diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex index 2693eaceb..a922f6d1b 100644 --- a/lib/pleroma/web/api_spec/schemas/account.ex +++ b/lib/pleroma/web/api_spec/schemas/account.ex @@ -112,7 +112,18 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do akkoma: %Schema{ type: :object, properties: %{ - note_ttl_days: %Schema{type: :integer} + instance: %Schema{ + type: :object, + nullable: true, + properties: %{ + name: %Schema{type: :string}, + favicon: %Schema{type: :string, format: :uri, nullable: true}, + # XXX: proper nodeinfo schema + nodeinfo: %Schema{type: :object, nullable: true} + } + }, + status_ttl_days: %Schema{type: :integer, nullable: true}, + permit_followback: %Schema{type: :boolean} } }, source: %Schema{ @@ -205,6 +216,18 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do "pleroma-fe" => %{} } }, + "akkoma" => %{ + "instance" => %{ + "name" => "ihatebeinga.live", + "favicon" => "https://ihatebeinga.live/favicon.png", + "nodeinfo" => + %{ + # XXX: nodeinfo schema + } + }, + "status_ttl_days" => nil, + "permit_followback" => true + }, "source" => %{ "fields" => [], "note" => "foobar", diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index e3a251ca1..64593767d 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -97,7 +97,7 @@ defmodule Pleroma.Web.Endpoint do Plug.Static, at: "/", from: :pleroma, - only: Pleroma.Constants.static_only_files(), + only: Pleroma.Web.static_paths(), # credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength gzip: true, cache_control_for_etags: @static_cache_control, diff --git a/lib/pleroma/web/feed/user_controller.ex b/lib/pleroma/web/feed/user_controller.ex index dc3b1f94b..b320c9224 100644 --- a/lib/pleroma/web/feed/user_controller.ex +++ b/lib/pleroma/web/feed/user_controller.ex @@ -30,7 +30,7 @@ def feed_redirect(%{assigns: %{format: format}} = conn, _params) def feed_redirect(conn, %{"nickname" => nickname}) do with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do - redirect(conn, external: "#{Routes.user_feed_url(conn, :feed, user.nickname)}.atom") + redirect(conn, external: "#{url(~p"/users/#{user.nickname}/feed")}.atom") end end diff --git a/lib/pleroma/web/masto_fe_controller.ex b/lib/pleroma/web/masto_fe_controller.ex index 7b6e01aad..b24f00620 100644 --- a/lib/pleroma/web/masto_fe_controller.ex +++ b/lib/pleroma/web/masto_fe_controller.ex @@ -34,9 +34,9 @@ def index(conn, _params) do index = if flavour == "fedibird-fe" do - "fedibird.index.html" + "fedibird.html" else - "glitchsoc.index.html" + "glitchsoc.html" end conn diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 26f46cc1a..2c7d6a893 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -51,7 +51,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do plug( OAuthScopesPlug, %{scopes: ["read:accounts"]} - when action in [:verify_credentials, :endorsements, :identity_proofs] + when action in [:verify_credentials, :endorsements, :identity_proofs, :preferences] ) plug( @@ -222,6 +222,7 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p |> Maps.put_if_present(:language, Pleroma.Web.Gettext.normalize_locale(params[:language])) |> Maps.put_if_present(:status_ttl_days, params[:status_ttl_days], status_ttl_days_value) |> Maps.put_if_present(:accepts_direct_messages_from, params[:accepts_direct_messages_from]) + |> Maps.put_if_present(:permit_followback, params[:permit_followback]) # What happens here: # @@ -544,4 +545,9 @@ def endorsements(conn, params), do: MastodonAPIController.empty_array(conn, para @doc "GET /api/v1/identity_proofs" def identity_proofs(conn, params), do: MastodonAPIController.empty_array(conn, params) + + @doc "GET /api/v1/preferences" + def preferences(%{assigns: %{user: user}} = conn, _params) do + render(conn, "preferences.json", user: user) + end end diff --git a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex index a9ccaa982..30e40ac42 100644 --- a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex @@ -54,12 +54,7 @@ def login(conn, params) do 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, " ") - ) + ~p[/oauth/authorize?#{[response_type: "code", client_id: app.client_id, redirect_uri: ".", scope: Enum.join(app.scopes, " ")]}] redirect(conn, to: path) end @@ -91,7 +86,7 @@ def password_reset(conn, params) do defp local_mastodon_post_login_path(conn) do case get_session(conn, :return_to) do nil -> - Routes.masto_fe_path(conn, :index, ["getting-started"]) + ~p"/web/getting-started" return_to -> delete_session(conn, :return_to) diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index e3f91a4e3..e9c04e927 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -190,6 +190,17 @@ def render("instance.json", %{instance: %Pleroma.Instances.Instance{} = instance def render("instance.json", _), do: nil + def render("preferences.json", %{user: user} = _opts) do + # TODO: Do we expose more settings that make sense to plug in here? + %{ + "posting:default:visibility": user.default_scope, + "posting:default:sensitive": false, + "posting:default:language": nil, + "reading:expand:media": "default", + "reading:expand:spoilers": false + } + end + defp do_render("show.json", %{user: user} = opts) do user = User.sanitize_html(user, User.html_filter_policy(opts[:for])) display_name = user.name || user.nickname @@ -250,6 +261,9 @@ defp do_render("show.json", %{user: user} = opts) do |> MediaProxy.url() end + last_status_at = + if is_nil(user.last_status_at), do: nil, else: NaiveDateTime.to_date(user.last_status_at) + %{ id: to_string(user.id), username: username_from_nickname(user.nickname), @@ -278,10 +292,11 @@ defp do_render("show.json", %{user: user} = opts) do actor_type: user.actor_type } }, - last_status_at: user.last_status_at, + last_status_at: last_status_at, akkoma: %{ instance: render("instance.json", %{instance: instance}), - status_ttl_days: user.status_ttl_days + status_ttl_days: user.status_ttl_days, + permit_followback: user.permit_followback }, # Pleroma extensions # Note: it's insecure to output :email but fully-qualified nickname may serve as safe stub diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 47d1616c4..ac0955534 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -322,7 +322,7 @@ def render("show.json", %{activity: %{id: id, data: %{"object" => _object}} = ac url = if user.local do - Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity) + url(~p[/notice/#{activity}]) else object.data["url"] || object.data["external_url"] || object.data["id"] end diff --git a/lib/pleroma/web/mastodon_api/views/tag_view.ex b/lib/pleroma/web/mastodon_api/views/tag_view.ex index 02108c736..6d3ea3c1a 100644 --- a/lib/pleroma/web/mastodon_api/views/tag_view.ex +++ b/lib/pleroma/web/mastodon_api/views/tag_view.ex @@ -1,7 +1,6 @@ defmodule Pleroma.Web.MastodonAPI.TagView do use Pleroma.Web, :view alias Pleroma.User - alias Pleroma.Web.Router.Helpers def render("index.json", %{tags: tags, for_user: user}) do render_many(tags, __MODULE__, "show.json", %{for_user: user}) @@ -17,7 +16,7 @@ def render("show.json", %{tag: tag, for_user: user}) do %{ name: tag.name, - url: Helpers.tag_feed_url(Pleroma.Web.Endpoint, :feed, tag.name), + url: url(~p[/tags/#{tag.name}]), history: [], following: following } diff --git a/lib/pleroma/web/metadata/providers/feed.ex b/lib/pleroma/web/metadata/providers/feed.ex index d0ab5c19e..15f47b843 100644 --- a/lib/pleroma/web/metadata/providers/feed.ex +++ b/lib/pleroma/web/metadata/providers/feed.ex @@ -3,9 +3,9 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Metadata.Providers.Feed do - alias Pleroma.Web.Endpoint alias Pleroma.Web.Metadata.Providers.Provider - alias Pleroma.Web.Router.Helpers + + use Pleroma.Web, :verified_routes @behaviour Provider @@ -16,7 +16,7 @@ def build_tags(%{user: user}) do [ rel: "alternate", type: "application/atom+xml", - href: Helpers.user_feed_path(Endpoint, :feed, user.nickname) <> ".atom" + href: ~p[/users/#{user.nickname}/feed.atom] ], []} ] end diff --git a/lib/pleroma/web/metadata/providers/twitter_card.ex b/lib/pleroma/web/metadata/providers/twitter_card.ex index b2497d14e..ab48ea272 100644 --- a/lib/pleroma/web/metadata/providers/twitter_card.ex +++ b/lib/pleroma/web/metadata/providers/twitter_card.ex @@ -10,6 +10,8 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do alias Pleroma.Web.Metadata.Providers.Provider alias Pleroma.Web.Metadata.Utils + use Pleroma.Web, :verified_routes + @behaviour Provider @media_types ["image", "audio", "video"] @@ -112,7 +114,7 @@ defp build_attachments(id, %{data: %{"attachment" => attachments}}) do defp build_attachments(_id, _object), do: [] defp player_url(id) do - Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice_player, id) + url(~p[/notice/#{id}/embed_player]) end # Videos have problems without dimensions, but we used to not provide WxH for images. diff --git a/lib/pleroma/web/o_auth/o_auth_controller.ex b/lib/pleroma/web/o_auth/o_auth_controller.ex index 277df1c46..29aa8c10e 100644 --- a/lib/pleroma/web/o_auth/o_auth_controller.ex +++ b/lib/pleroma/web/o_auth/o_auth_controller.ex @@ -39,6 +39,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do action_fallback(Pleroma.Web.OAuth.FallbackController) @oob_token_redirect_uri "urn:ietf:wg:oauth:2.0:oob" + @state_cookie_name "akkoma_oauth_state" # Note: this definition is only called from error-handling methods with `conn.params` as 2nd arg def authorize(%Plug.Conn{} = conn, %{"authorization" => _} = params) do @@ -443,13 +444,10 @@ def prepare_request(%Plug.Conn{} = conn, %{ |> Map.put("scope", scope) |> Jason.encode!() - params = - auth_attrs - |> Map.drop(~w(scope scopes client_id redirect_uri)) - |> Map.put("state", state) - # Handing the request to Ueberauth - redirect(conn, to: Routes.o_auth_path(conn, :request, provider, params)) + conn + |> put_resp_cookie(@state_cookie_name, state) + |> redirect(to: ~p"/oauth/#{provider}") end def request(%Plug.Conn{} = conn, params) do @@ -468,20 +466,26 @@ def request(%Plug.Conn{} = conn, params) do end def callback(%Plug.Conn{assigns: %{ueberauth_failure: failure}} = conn, params) do - params = callback_params(params) + params = callback_params(conn, params) messages = for e <- Map.get(failure, :errors, []), do: e.message message = Enum.join(messages, "; ") - conn - |> put_flash( - :error, - dgettext("errors", "Failed to authenticate: %{message}.", message: message) - ) - |> redirect(external: redirect_uri(conn, params["redirect_uri"])) + error_message = dgettext("errors", "Failed to authenticate: %{message}.", message: message) + + if params["redirect_uri"] do + conn + |> put_flash( + :error, + error_message + ) + |> redirect(external: redirect_uri(conn, params["redirect_uri"])) + else + send_resp(conn, :bad_request, error_message) + end end def callback(%Plug.Conn{} = conn, params) do - params = callback_params(params) + params = callback_params(conn, params) with {:ok, registration} <- Authenticator.get_registration(conn) do auth_attrs = Map.take(params, ~w(client_id redirect_uri scope scopes state)) @@ -511,8 +515,9 @@ def callback(%Plug.Conn{} = conn, params) do end end - defp callback_params(%{"state" => state} = params) do - Map.merge(params, Jason.decode!(state)) + defp callback_params(%Plug.Conn{} = conn, params) do + fetch_cookies(conn) + Map.merge(params, Jason.decode!(Map.get(conn.req_cookies, @state_cookie_name, "{}"))) end def registration_details(%Plug.Conn{} = conn, %{"authorization" => auth_attrs}) do @@ -623,7 +628,7 @@ def login(%User{} = user, %App{} = app, requested_scopes) when is_list(requested end # Special case: Local MastodonFE - defp redirect_uri(%Plug.Conn{} = conn, "."), do: Routes.auth_url(conn, :login) + defp redirect_uri(_, "."), do: url(~p"/web/login") defp redirect_uri(%Plug.Conn{}, redirect_uri), do: redirect_uri diff --git a/lib/pleroma/web/o_status/o_status_controller.ex b/lib/pleroma/web/o_status/o_status_controller.ex index 95a22895e..2b2872c9a 100644 --- a/lib/pleroma/web/o_status/o_status_controller.ex +++ b/lib/pleroma/web/o_status/o_status_controller.ex @@ -14,7 +14,6 @@ defmodule Pleroma.Web.OStatus.OStatusController do alias Pleroma.Web.Fallback.RedirectController alias Pleroma.Web.Metadata.PlayerView alias Pleroma.Web.Plugs.RateLimiter - alias Pleroma.Web.Router plug( RateLimiter, @@ -87,7 +86,7 @@ def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do %{ activity_id: activity.id, object: object, - url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id), + url: url(~p[/notice/#{activity.id}]), user: user } ) diff --git a/lib/pleroma/web/plugs/http_signature_plug.ex b/lib/pleroma/web/plugs/http_signature_plug.ex index 488108b08..eb6a46736 100644 --- a/lib/pleroma/web/plugs/http_signature_plug.ex +++ b/lib/pleroma/web/plugs/http_signature_plug.ex @@ -5,8 +5,9 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do import Plug.Conn import Phoenix.Controller, only: [get_format: 1] + + use Pleroma.Web, :verified_routes alias Pleroma.Activity - alias Pleroma.Web.Router alias Pleroma.Signature alias Pleroma.Instances require Logger @@ -32,10 +33,10 @@ def call(conn, _opts) do end def route_aliases(%{path_info: ["objects", id], query_string: query_string}) do - ap_id = Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :object, id) + ap_id = url(~p[/objects/#{id}]) with %Activity{} = activity <- Activity.get_by_object_ap_id_with_object(ap_id) do - ["/notice/#{activity.id}", "/notice/#{activity.id}?#{query_string}"] + [~p"/notice/#{activity.id}", "/notice/#{activity.id}?#{query_string}"] else _ -> [] end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 3ea3c9132..ca4995281 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -629,6 +629,8 @@ defmodule Pleroma.Web.Router do post("/tags/:id/follow", TagController, :follow) post("/tags/:id/unfollow", TagController, :unfollow) get("/followed_tags", TagController, :show_followed) + + get("/preferences", AccountController, :preferences) end scope "/api/web", Pleroma.Web do diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex index 56ee4e41e..b1ea3178d 100644 --- a/lib/pleroma/web/static_fe/static_fe_controller.ex +++ b/lib/pleroma/web/static_fe/static_fe_controller.ex @@ -11,7 +11,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Metadata - alias Pleroma.Web.Router.Helpers plug(:put_layout, :static_fe) plug(:assign_id) @@ -25,7 +24,13 @@ def show(%{assigns: %{notice_id: notice_id}} = conn, _params) do true <- Visibility.is_public?(activity.object), {_, true} <- {:visible?, Visibility.visible_for_user?(activity, _reading_user = nil)}, %User{} = user <- User.get_by_ap_id(activity.object.data["actor"]) do - meta = Metadata.build_tags(%{url: activity.data["id"], object: activity.object, user: user}) + meta = + Metadata.build_tags(%{ + activity_id: notice_id, + url: activity.data["id"], + object: activity.object, + user: user + }) timeline = activity.object.data["context"] @@ -111,11 +116,11 @@ def show(%{assigns: %{username_or_id: username_or_id, tab: tab}} = conn, params) end def show(%{assigns: %{object_id: _}} = conn, _params) do - url = Helpers.url(conn) <> conn.request_path + url = unverified_url(conn, conn.request_path) case Activity.get_create_by_object_ap_id_with_object(url) do %Activity{} = activity -> - to = Helpers.o_status_path(Pleroma.Web.Endpoint, :notice, activity) + to = ~p[/notice/#{activity}] redirect(conn, to: to) _ -> @@ -124,11 +129,11 @@ def show(%{assigns: %{object_id: _}} = conn, _params) do end def show(%{assigns: %{activity_id: _}} = conn, _params) do - url = Helpers.url(conn) <> conn.request_path + url = unverified_url(conn, conn.request_path) case Activity.get_by_ap_id(url) do %Activity{} = activity -> - to = Helpers.o_status_path(Pleroma.Web.Endpoint, :notice, activity) + to = ~p[/notice/#{activity}] redirect(conn, to: to) _ -> @@ -167,7 +172,7 @@ defp represent(%Activity{object: %Object{data: data}} = activity, selected) do link = case user.local do - true -> Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity) + true -> ~p[/notice/#{activity}] _ -> data["url"] || data["external_url"] || data["id"] end diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex index f0c9ddd22..c1d83c5a0 100644 --- a/lib/pleroma/web/static_fe/static_fe_view.ex +++ b/lib/pleroma/web/static_fe/static_fe_view.ex @@ -11,7 +11,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do alias Pleroma.Web.Gettext alias Pleroma.Web.MediaProxy alias Pleroma.Web.Metadata.Utils - alias Pleroma.Web.Router.Helpers use Phoenix.HTML diff --git a/lib/pleroma/web/telemetry.ex b/lib/pleroma/web/telemetry.ex index b03850600..269f9f238 100644 --- a/lib/pleroma/web/telemetry.ex +++ b/lib/pleroma/web/telemetry.ex @@ -101,7 +101,8 @@ defp distribution_metrics do ] end - defp summary_metrics do + # Summary metrics are currently not (yet) supported by the prometheus exporter + defp summary_metrics(byte_unit) do [ # Phoenix Metrics summary("phoenix.endpoint.stop.duration", @@ -118,10 +119,98 @@ defp summary_metrics do summary("pleroma.repo.query.idle_time", unit: {:native, :millisecond}), # VM Metrics - summary("vm.memory.total", unit: {:byte, :kilobyte}), + summary("vm.memory.total", unit: {:byte, byte_unit}), summary("vm.total_run_queue_lengths.total"), summary("vm.total_run_queue_lengths.cpu"), - summary("vm.total_run_queue_lengths.io"), + summary("vm.total_run_queue_lengths.io") + ] + end + + defp sum_counter_pair(basename, opts) do + [ + sum(basename <> ".psum", opts), + counter(basename <> ".pcount", opts) + ] + end + + # Prometheus exporter doesn't support summaries, so provide fallbacks + defp summary_fallback_metrics(byte_unit \\ :byte) do + # Summary metrics are not supported by the Prometheus exporter + # https://github.com/beam-telemetry/telemetry_metrics_prometheus_core/issues/11 + # and sum metrics currently only work with integers + # https://github.com/beam-telemetry/telemetry_metrics_prometheus_core/issues/35 + # + # For VM metrics this is kindof ok as they appear to always be integers + # and we can use sum + counter to get the average between polls from their change + # But for repo query times we need to use a full distribution + + simple_buckets = [0, 1, 2, 4, 8, 16] + simple_buckets_quick = for t <- simple_buckets, do: t / 100.0 + + # Already included in distribution metrics anyway: + # phoenix.router_dispatch.stop.duration + # pleroma.repo.query.total_time + # pleroma.repo.query.queue_time + dist_metrics = + [ + distribution("phoenix.endpoint.stop.duration.fdist", + event_name: [:phoenix, :endpoint, :stop], + measurement: :duration, + unit: {:native, :millisecond}, + reporter_options: [ + buckets: simple_buckets + ] + ), + distribution("pleroma.repo.query.decode_time.fdist", + event_name: [:pleroma, :repo, :query], + measurement: :decode_time, + unit: {:native, :millisecond}, + reporter_options: [ + buckets: simple_buckets_quick + ] + ), + distribution("pleroma.repo.query.query_time.fdist", + event_name: [:pleroma, :repo, :query], + measurement: :query_time, + unit: {:native, :millisecond}, + reporter_options: [ + buckets: simple_buckets + ] + ), + distribution("pleroma.repo.query.idle_time.fdist", + event_name: [:pleroma, :repo, :query], + measurement: :idle_time, + unit: {:native, :millisecond}, + reporter_options: [ + buckets: simple_buckets + ] + ) + ] + + vm_metrics = + sum_counter_pair("vm.memory.total", + event_name: [:vm, :memory], + measurement: :total, + unit: {:byte, byte_unit} + ) ++ + sum_counter_pair("vm.total_run_queue_lengths.total", + event_name: [:vm, :total_run_queue_lengths], + measurement: :total + ) ++ + sum_counter_pair("vm.total_run_queue_lengths.cpu", + event_name: [:vm, :total_run_queue_lengths], + measurement: :cpu + ) ++ + sum_counter_pair("vm.total_run_queue_lengths.io.fsum", + event_name: [:vm, :total_run_queue_lengths], + measurement: :io + ) + + dist_metrics ++ vm_metrics + end + + defp common_metrics do + [ last_value("pleroma.local_users.total"), last_value("pleroma.domains.total"), last_value("pleroma.local_statuses.total"), @@ -129,8 +218,10 @@ defp summary_metrics do ] end - def prometheus_metrics, do: summary_metrics() ++ distribution_metrics() - def live_dashboard_metrics, do: summary_metrics() + def prometheus_metrics, + do: common_metrics() ++ distribution_metrics() ++ summary_fallback_metrics() + + def live_dashboard_metrics, do: common_metrics() ++ summary_metrics(:megabyte) defp periodic_measurements do [ diff --git a/lib/pleroma/web/templates/akkoma_api/frontend_switcher/switch.html.eex b/lib/pleroma/web/templates/akkoma_api/frontend_switcher/switch.html.eex index a0b0a2361..010a7fbad 100644 --- a/lib/pleroma/web/templates/akkoma_api/frontend_switcher/switch.html.eex +++ b/lib/pleroma/web/templates/akkoma_api/frontend_switcher/switch.html.eex @@ -2,7 +2,7 @@

    After you submit, you will need to refresh manually to get your new frontend!

    -<%= form_for @conn, Routes.frontend_switcher_path(@conn, :do_switch), fn f -> %> +<%= form_for @conn, ~p"/akkoma/frontend", fn f -> %> <%= select(f, :frontend, @choices) %> <%= submit do: "submit" %> diff --git a/lib/pleroma/web/templates/feed/feed/tag.atom.eex b/lib/pleroma/web/templates/feed/feed/tag.atom.eex index 6d497e84c..e85c08b2b 100644 --- a/lib/pleroma/web/templates/feed/feed/tag.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/tag.atom.eex @@ -9,13 +9,13 @@ xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/"> - <%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.rss' %> + <%= '#{url(~p"/tags/#{@tag}")}.rss' %> #<%= @tag %> <%= Gettext.dpgettext("static_pages", "tag feed description", "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse.", tag: @tag) %> <%= feed_logo() %> <%= most_recent_update(@activities) %> - + " type="application/atom+xml"/> <%= for activity <- @activities do %> <%= render @view_module, "_tag_activity.atom", Map.merge(assigns, prepare_activity(activity, actor: true)) %> <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/tag.rss.eex b/lib/pleroma/web/templates/feed/feed/tag.rss.eex index edcc3e436..7ee3ba5a3 100644 --- a/lib/pleroma/web/templates/feed/feed/tag.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/tag.rss.eex @@ -5,7 +5,7 @@ #<%= @tag %> <%= Gettext.dpgettext("static_pages", "tag feed description", "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse.", tag: @tag) %> - <%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.rss' %> + <%= '#{url(~p"/tags/#{@tag}")}.rss' %> <%= feed_logo() %> 2b90d9 <%= for activity <- @activities do %> diff --git a/lib/pleroma/web/templates/feed/feed/user.atom.eex b/lib/pleroma/web/templates/feed/feed/user.atom.eex index 5c1f0ecbc..03585a9d5 100644 --- a/lib/pleroma/web/templates/feed/feed/user.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/user.atom.eex @@ -6,16 +6,16 @@ xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0"> - <%= Routes.user_feed_url(@conn, :feed, @user.nickname) <> ".atom" %> + <%= url(~p"/users/#{@user.nickname}/feed") <> ".atom" %> <%= @user.nickname <> "'s timeline" %> <%= most_recent_update(@activities, @user) %> <%= logo(@user) %> - + " type="application/atom+xml"/> <%= render @view_module, "_author.atom", assigns %> <%= if last_activity(@activities) do %> - + " type="application/atom+xml"/> <% end %> <%= for activity <- @activities do %> diff --git a/lib/pleroma/web/templates/feed/feed/user.rss.eex b/lib/pleroma/web/templates/feed/feed/user.rss.eex index 6b842a085..f2eb7337e 100644 --- a/lib/pleroma/web/templates/feed/feed/user.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/user.rss.eex @@ -1,16 +1,16 @@ - <%= Routes.user_feed_url(@conn, :feed, @user.nickname) <> ".rss" %> + <%= url(~p"/users/#{@user.nickname}/feed") <> ".rss" %> <%= @user.nickname <> "'s timeline" %> <%= most_recent_update(@activities, @user) %> <%= logo(@user) %> - <%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss' %> + <%= '#{url(~p"/users/#{@user.nickname}/feed")}.rss' %> <%= render @view_module, "_author.rss", assigns %> <%= if last_activity(@activities) do %> - <%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss?max_id=#{last_activity(@activities).id}' %> + <%= '#{url(~p"/users/#{@user.nickname}/feed")}.rss?max_id=#{last_activity(@activities).id}' %> <% end %> <%= for activity <- @activities do %> diff --git a/lib/pleroma/web/templates/masto_fe/fedibird.html.heex b/lib/pleroma/web/templates/masto_fe/fedibird.html.heex new file mode 100644 index 000000000..7070bd8d8 --- /dev/null +++ b/lib/pleroma/web/templates/masto_fe/fedibird.html.heex @@ -0,0 +1,58 @@ + + + + + + + + <%= Config.get([:instance, :name]) %> + + + + + + + + + + + + + + + + + + + + + + +
    + + diff --git a/lib/pleroma/web/templates/masto_fe/fedibird.index.html.eex b/lib/pleroma/web/templates/masto_fe/fedibird.index.html.eex deleted file mode 100644 index 6730c0ecc..000000000 --- a/lib/pleroma/web/templates/masto_fe/fedibird.index.html.eex +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - -<%= Config.get([:instance, :name]) %> - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - diff --git a/lib/pleroma/web/templates/masto_fe/glitchsoc.html.heex b/lib/pleroma/web/templates/masto_fe/glitchsoc.html.heex new file mode 100644 index 000000000..469c201a5 --- /dev/null +++ b/lib/pleroma/web/templates/masto_fe/glitchsoc.html.heex @@ -0,0 +1,57 @@ + + + + + + + + <%= Config.get([:instance, :name]) %> + + + + + + + + + + + + + + + + + + + + + + + + +
    + + diff --git a/lib/pleroma/web/templates/masto_fe/glitchsoc.index.html.eex b/lib/pleroma/web/templates/masto_fe/glitchsoc.index.html.eex deleted file mode 100644 index dadf8f413..000000000 --- a/lib/pleroma/web/templates/masto_fe/glitchsoc.index.html.eex +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - -<%= Config.get([:instance, :name]) %> - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - diff --git a/lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex b/lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex index ee40cf277..b9b08c45d 100644 --- a/lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex +++ b/lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex @@ -1,15 +1,15 @@
    - <%= if get_flash(@conn, :info) do %> - + <%= if Flash.get(@flash, :info) do %> + <% end %> - <%= if get_flash(@conn, :error) do %> - + <%= if Flash.get(@flash, :error) do %> + <% end %>
    <%= Gettext.dpgettext("static_pages", "mfa recover page title", "Two-factor recovery") %>
    - <%= form_for @conn, Routes.mfa_verify_path(@conn, :verify), [as: "mfa"], fn f -> %> + <%= form_for @conn, ~p"/oauth/mfa/verify", [as: "mfa"], fn f -> %>
    <%= label f, :code, Gettext.dpgettext("static_pages", "mfa recover recovery code prompt", "Recovery code") %> <%= text_input f, :code, [autocomplete: false, autocorrect: "off", autocapitalize: "off", autofocus: true, spellcheck: false] %> @@ -21,7 +21,7 @@ <%= submit Gettext.dpgettext("static_pages", "mfa recover verify recovery code button", "Verify") %> <% end %> - "> + "> <%= Gettext.dpgettext("static_pages", "mfa recover use 2fa code link", "Enter a two-factor code") %> diff --git a/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex b/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex index 734e62112..59827780b 100644 --- a/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex +++ b/lib/pleroma/web/templates/o_auth/mfa/totp.html.eex @@ -1,15 +1,15 @@
    - <%= if get_flash(@conn, :info) do %> - + <%= if Flash.get(@flash, :info) do %> + <% end %> - <%= if get_flash(@conn, :error) do %> - + <%= if Flash.get(@flash, :error) do %> + <% end %>
    <%= Gettext.dpgettext("static_pages", "mfa auth page title", "Two-factor authentication") %>
    - <%= form_for @conn, Routes.mfa_verify_path(@conn, :verify), [as: "mfa"], fn f -> %> + <%= form_for @conn, ~p"/oauth/mfa/verify", [as: "mfa"], fn f -> %>
    <%= label f, :code, Gettext.dpgettext("static_pages", "mfa auth code prompt", "Authentication code") %> <%= text_input f, :code, [autocomplete: "one-time-code", autocorrect: "off", autocapitalize: "off", autofocus: true, pattern: "[0-9]*", spellcheck: false] %> @@ -21,7 +21,7 @@ <%= submit Gettext.dpgettext("static_pages", "mfa auth verify code button", "Verify") %> <% end %> - "> + "> <%= Gettext.dpgettext("static_pages", "mfa auth page use recovery code link", "Enter a two-factor recovery code") %>
    diff --git a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex index 8b894cd58..97f2b770f 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex @@ -1,6 +1,6 @@

    <%= Gettext.dpgettext("static_pages", "oauth external provider page title", "Sign in with external provider") %>

    -<%= form_for @conn, Routes.o_auth_path(@conn, :prepare_request), [as: "authorization", method: "get"], fn f -> %> +<%= form_for @conn, ~p"/oauth/prepare_request", [as: "authorization", method: "get"], fn f -> %>
    <%= render @view_module, "_scopes.html", Map.merge(assigns, %{form: f}) %>
    diff --git a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex index 1f661efb2..601b16b98 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/register.html.eex @@ -1,14 +1,14 @@ -<%= if get_flash(@conn, :info) do %> - +<%= if Flash.get(@flash, :info) do %> + <% end %> -<%= if get_flash(@conn, :error) do %> - +<%= if Flash.get(@flash, :error) do %> + <% end %>

    <%= Gettext.dpgettext("static_pages", "oauth register page title", "Registration Details") %>

    <%= Gettext.dpgettext("static_pages", "oauth register page fill form prompt", "If you'd like to register a new account, please provide the details below.") %>

    -<%= form_for @conn, Routes.o_auth_path(@conn, :register), [as: "authorization"], fn f -> %> +<%= form_for @conn, ~p"/oauth/register", [as: "authorization"], fn f -> %>
    <%= label f, :nickname, Gettext.dpgettext("static_pages", "oauth register page nickname prompt", "Nickname") %> diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex index 986e6ffce..420a17562 100644 --- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex +++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex @@ -1,11 +1,11 @@ -<%= if get_flash(@conn, :info) do %> - +<%= if Flash.get(@flash, :info) do %> + <% end %> -<%= if get_flash(@conn, :error) do %> - +<%= if Flash.get(@flash, :error) do %> + <% end %> -<%= form_for @conn, Routes.o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %> +<%= form_for @conn, ~p"/oauth/authorize", [as: "authorization"], fn f -> %> <%= if @user do %>
    -
    + "> diff --git a/lib/pleroma/web/templates/twitter_api/password/reset.html.eex b/lib/pleroma/web/templates/twitter_api/password/reset.html.eex index 6a544af51..390a8371f 100644 --- a/lib/pleroma/web/templates/twitter_api/password/reset.html.eex +++ b/lib/pleroma/web/templates/twitter_api/password/reset.html.eex @@ -1,5 +1,5 @@

    Password Reset for <%= @user.nickname %>

    -<%= form_for @conn, Routes.reset_password_path(@conn, :do_reset), [as: "data"], fn f -> %> +<%= form_for @conn, ~p"/api/v1/pleroma/password_reset", [as: "data"], fn f -> %>
    <%= label f, :password, Gettext.dpgettext("static_pages", "password reset form password prompt", "Password") %> <%= password_input f, :password %> diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex index e2d251fac..894b5c6ee 100644 --- a/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex @@ -4,7 +4,7 @@

    <%= Gettext.dpgettext("static_pages", "remote follow header", "Remote follow") %>

    <%= @followee.nickname %>

    - <%= form_for @conn, Routes.remote_follow_path(@conn, :do_follow), [as: "user"], fn f -> %> + <%= form_for @conn, ~p"/ostatus_subscribe", [as: "user"], fn f -> %> <%= hidden_input f, :id, value: @followee.id %> <%= submit Gettext.dpgettext("static_pages", "remote follow authorization button", "Authorize") %> <% end %> diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex index 26340a906..b0084aac4 100644 --- a/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex @@ -4,7 +4,7 @@

    <%= Gettext.dpgettext("static_pages", "remote follow header, need login", "Log in to follow") %>

    <%= @followee.nickname %>

    -<%= form_for @conn, Routes.remote_follow_path(@conn, :do_follow), [as: "authorization"], fn f -> %> +<%= form_for @conn, ~p"/ostatus_subscribe", [as: "authorization"], fn f -> %> <%= text_input f, :name, placeholder: Gettext.dpgettext("static_pages", "placeholder text for username entry", "Username"), required: true, autocomplete: "username" %>
    <%= password_input f, :password, placeholder: Gettext.dpgettext("static_pages", "placeholder text for password entry", "Password"), required: true, autocomplete: "password" %> diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex index 638212c1e..f34eba165 100644 --- a/lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex +++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex @@ -4,7 +4,7 @@

    <%= Gettext.dpgettext("static_pages", "remote follow mfa header", "Two-factor authentication") %>

    <%= @followee.nickname %>

    -<%= form_for @conn, Routes.remote_follow_path(@conn, :do_follow), [as: "mfa"], fn f -> %> +<%= form_for @conn, ~p"/ostatus_subscribe", [as: "mfa"], fn f -> %> <%= text_input f, :code, placeholder: Gettext.dpgettext("static_pages", "placeholder text for auth code entry", "Authentication code"), required: true %>
    <%= hidden_input f, :id, value: @followee.id %> diff --git a/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex index d77174967..3105772e2 100644 --- a/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex +++ b/lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex @@ -2,7 +2,7 @@

    <%= Gettext.dpgettext("static_pages", "status interact error", "Error: %{error}", error: @error) %>

    <% else %>

    <%= raw Gettext.dpgettext("static_pages", "status interact header", "Interacting with %{nickname}'s %{status_link}", nickname: safe_to_string(html_escape(@nickname)), status_link: safe_to_string(link(Gettext.dpgettext("static_pages", "status interact header - status link text", "status"), to: @status_link))) %>

    - <%= form_for @conn, Routes.util_path(@conn, :remote_subscribe), [as: "status"], fn f -> %> + <%= form_for @conn, ~p"/main/ostatus", [as: "status"], fn f -> %> <%= hidden_input f, :status_id, value: @status_id %> <%= text_input f, :profile, placeholder: Gettext.dpgettext("static_pages", "placeholder text for account id", "Your account ID, e.g. lain@quitter.se") %> <%= submit Gettext.dpgettext("static_pages", "status interact authorization button", "Interact") %> diff --git a/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex b/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex index 848660f26..47b73f676 100644 --- a/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex +++ b/lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex @@ -2,7 +2,7 @@

    <%= Gettext.dpgettext("static_pages", "remote follow error", "Error: %{error}", error: @error) %>

    <% else %>

    <%= Gettext.dpgettext("static_pages", "remote follow header", "Remotely follow %{nickname}", nickname: @nickname) %>

    - <%= form_for @conn, Routes.util_path(@conn, :remote_subscribe), [as: "user"], fn f -> %> + <%= form_for @conn, ~p"/main/ostatus", [as: "user"], fn f -> %> <%= hidden_input f, :nickname, value: @nickname %> <%= text_input f, :profile, placeholder: Gettext.dpgettext("static_pages", "placeholder text for account id", "Your account ID, e.g. lain@quitter.se") %> <%= submit Gettext.dpgettext("static_pages", "remote follow authorization button for following with a remote account", "Follow") %> diff --git a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex index 42d7601ed..1927d2021 100644 --- a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex @@ -38,7 +38,7 @@ def follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do defp follow_status(conn, _user, acct) do with {:ok, object} <- Fetcher.fetch_object_from_id(acct), %Activity{id: activity_id} <- Activity.get_create_by_object_ap_id(object.data["id"]) do - redirect(conn, to: Routes.o_status_path(conn, :notice, activity_id)) + redirect(conn, to: ~p"/notice/#{activity_id}") else error -> handle_follow_error(conn, error) diff --git a/lib/pleroma/web/views/embed_view.ex b/lib/pleroma/web/views/embed_view.ex index 913d717be..fe1009e2f 100644 --- a/lib/pleroma/web/views/embed_view.ex +++ b/lib/pleroma/web/views/embed_view.ex @@ -13,7 +13,6 @@ defmodule Pleroma.Web.EmbedView do alias Pleroma.Web.Gettext alias Pleroma.Web.MediaProxy alias Pleroma.Web.Metadata.Utils - alias Pleroma.Web.Router.Helpers import Phoenix.HTML @@ -48,7 +47,7 @@ defp activity_content(%Activity{object: %Object{data: %{"content" => content}}}) defp activity_content(_), do: nil defp activity_url(%User{local: true}, activity) do - Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity) + ~p[/notice/#{activity}] end defp activity_url(%User{local: false}, %Activity{object: %Object{data: data}}) do diff --git a/lib/pleroma/web/views/masto_fe_view.ex b/lib/pleroma/web/views/masto_fe_view.ex index 305368c9d..dfb235976 100644 --- a/lib/pleroma/web/views/masto_fe_view.ex +++ b/lib/pleroma/web/views/masto_fe_view.ex @@ -85,7 +85,7 @@ def render("manifest.json", _params) do 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"]), + start_url: ~p"/web/getting-started", categories: [ "social" ], diff --git a/lib/pleroma/web/xml.ex b/lib/pleroma/web/xml.ex index ba8886548..e68341e20 100644 --- a/lib/pleroma/web/xml.ex +++ b/lib/pleroma/web/xml.ex @@ -26,13 +26,7 @@ def string_from_xpath(xpath, doc) do def parse_document(text) do try do - {doc, _rest} = - text - |> :binary.bin_to_list() - |> :xmerl_scan.string( - quiet: true, - allow_entities: false - ) + doc = SweetXml.parse(text, dtd: :none) {:ok, doc} rescue diff --git a/lib/pleroma/workers/cron/database_prune_worker.ex b/lib/pleroma/workers/cron/database_prune_worker.ex index 58995c69a..ced4b27b7 100644 --- a/lib/pleroma/workers/cron/database_prune_worker.ex +++ b/lib/pleroma/workers/cron/database_prune_worker.ex @@ -21,6 +21,9 @@ def perform(_job) do Logger.info("Pruning old undos") ActivityPruner.prune_undos() + Logger.info("Pruning old updates") + ActivityPruner.prune_updates() + Logger.info("Pruning old removes") ActivityPruner.prune_removes() diff --git a/mix.exs b/mix.exs index 235a3d65d..4e8b3160d 100644 --- a/mix.exs +++ b/mix.exs @@ -4,10 +4,10 @@ defmodule Pleroma.Mixfile do def project do [ app: :pleroma, - version: version("3.10.4"), + version: version("3.11.0"), elixir: "~> 1.14", elixirc_paths: elixirc_paths(Mix.env()), - compilers: [:phoenix] ++ Mix.compilers(), + compilers: Mix.compilers(), elixirc_options: [warnings_as_errors: warnings_as_errors()], xref: [exclude: [:eldap]], start_permanent: Mix.env() == :prod, @@ -114,7 +114,9 @@ defp oauth_deps do # Type `mix help deps` for examples and options. defp deps do [ - {:phoenix, "~> 1.6.15"}, + {:phoenix, "~> 1.7.0"}, + {:phoenix_view, "~> 2.0"}, + {:phoenix_live_dashboard, "~> 0.7.2"}, {:tzdata, "~> 1.1.1"}, {:plug_cowboy, "~> 2.6"}, {:phoenix_pubsub, "~> 2.1"}, @@ -146,7 +148,7 @@ defp deps do {:argon2_elixir, "~> 3.1"}, {:cors_plug, "~> 3.0"}, {:web_push_encryption, "~> 0.3.1"}, - {:swoosh, "~> 1.11"}, + {:swoosh, "~> 1.14.2"}, # for gmail adapter in swoosh {:mail, ">= 0.0.0"}, {:phoenix_swoosh, "~> 1.2"}, @@ -154,9 +156,11 @@ defp deps do {:ex_syslogger, "~> 2.0.0"}, {:floki, "~> 0.34"}, {:timex, "~> 3.7"}, - {:ueberauth, "~> 0.10"}, + {:ueberauth, "== 0.10.5"}, {:linkify, git: "https://akkoma.dev/AkkomaGang/linkify.git"}, - {:http_signatures, "~> 0.1.1"}, + {:http_signatures, + git: "https://akkoma.dev/AkkomaGang/http_signatures.git", + ref: "6640ce7d24c783ac2ef56e27d00d12e8dc85f396"}, {:telemetry, "~> 1.2"}, {:telemetry_poller, "~> 1.0"}, {:telemetry_metrics, "~> 0.6"}, @@ -175,22 +179,23 @@ defp deps do {:remote_ip, "~> 1.1.0"}, {:captcha, git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", - ref: "3bbfa8b5ea13accc1b1c40579a380d8e5cfd6ad2"}, + ref: "90f6ce7672f70f56708792a98d98bd05176c9176"}, {:restarter, path: "./restarter"}, - {:majic, "~> 1.0"}, + {:majic, + git: "https://akkoma.dev/AkkomaGang/majic.git", + ref: "80540b36939ec83f48e76c61e5000e0fd67706f0"}, {:eblurhash, "~> 1.2.2"}, {:open_api_spex, "~> 3.17"}, {:search_parser, git: "https://github.com/FloatingGhost/pleroma-contrib-search-parser.git", ref: "08971a81e68686f9ac465cfb6661d51c5e4e1e7f"}, {:nimble_parsec, "~> 1.3", override: true}, - {:phoenix_live_dashboard, "~> 0.7.2"}, {:ecto_psql_extras, "~> 0.7"}, {:elasticsearch, git: "https://akkoma.dev/AkkomaGang/elasticsearch-elixir.git", ref: "main"}, {:mfm_parser, git: "https://akkoma.dev/AkkomaGang/mfm-parser.git", - ref: "912fba81152d4d572e457fd5427f9875b2bc3dbe"}, + ref: "b21ab7754024af096f2d14247574f55f0063295b"}, ## dev & test {:ex_doc, "~> 0.30", only: :dev, runtime: false}, @@ -201,7 +206,9 @@ defp deps do {:mox, "~> 1.0", only: :test}, {:websockex, "~> 0.4.3", only: :test}, {:dialyxir, "~> 1.3", only: [:dev], runtime: false}, - {:mint, "~> 1.5.1", override: true} + {:elixir_xml_to_map, "~> 3.0", only: :test}, + {:mint, "~> 1.5.1", override: true}, + {:nimble_pool, "~> 1.0", override: true} ] ++ oauth_deps() end diff --git a/mix.lock b/mix.lock index 19b954d81..810356345 100644 --- a/mix.lock +++ b/mix.lock @@ -1,114 +1,117 @@ %{ - "argon2_elixir": {:hex, :argon2_elixir, "3.1.0", "4135e0a1b4ff800d42c85aa663e068efa3cb356297189b5b65caa992db8ec8cf", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "c08feae0ee0292165d1b945003363c7cd8523d002e0483c627dfca930291dd73"}, + "argon2_elixir": {:hex, :argon2_elixir, "3.2.1", "f47740bf9f2a39ffef79ba48eb25dea2ee37bcc7eadf91d49615591d1a6fce1a", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "a813b78217394530b5fcf4c8070feee43df03ffef938d044019169c766315690"}, "base62": {:hex, :base62, "1.2.2", "85c6627eb609317b70f555294045895ffaaeb1758666ab9ef9ca38865b11e629", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "d41336bda8eaa5be197f1e4592400513ee60518e5b9f4dcf38f4b4dae6f377bb"}, "bbcode_pleroma": {:hex, :bbcode_pleroma, "0.2.0", "d36f5bca6e2f62261c45be30fa9b92725c0655ad45c99025cb1c3e28e25803ef", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "19851074419a5fedb4ef49e1f01b30df504bb5dbb6d6adfc135238063bebd1c3"}, "bcrypt_elixir": {:hex, :bcrypt_elixir, "3.0.1", "9be815469e6bfefec40fa74658ecbbe6897acfb57614df1416eeccd4903f602c", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "486bb95efb645d1efc6794c1ddd776a186a9a713abf06f45708a6ce324fb96cf"}, - "benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"}, + "benchee": {:hex, :benchee, "1.2.0", "afd2f0caec06ce3a70d9c91c514c0b58114636db9d83c2dc6bfd416656618353", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "ee729e53217898b8fd30aaad3cce61973dab61574ae6f48229fe7ff42d5e4457"}, "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, "cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"}, "calendar": {:hex, :calendar, "1.0.0", "f52073a708528482ec33d0a171954ca610fe2bd28f1e871f247dc7f1565fa807", [:mix], [{:tzdata, "~> 0.1.201603 or ~> 0.5.20 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "990e9581920c82912a5ee50e62ff5ef96da6b15949a2ee4734f935fdef0f0a6f"}, - "captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "3bbfa8b5ea13accc1b1c40579a380d8e5cfd6ad2", [ref: "3bbfa8b5ea13accc1b1c40579a380d8e5cfd6ad2"]}, - "castore": {:hex, :castore, "1.0.3", "7130ba6d24c8424014194676d608cb989f62ef8039efd50ff4b3f33286d06db8", [:mix], [], "hexpm", "680ab01ef5d15b161ed6a95449fac5c6b8f60055677a8e79acf01b27baa4390b"}, - "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, + "captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "90f6ce7672f70f56708792a98d98bd05176c9176", [ref: "90f6ce7672f70f56708792a98d98bd05176c9176"]}, + "castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"}, + "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, - "comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"}, + "comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"}, "concurrent_limiter": {:git, "https://akkoma.dev/AkkomaGang/concurrent-limiter.git", "a9e0b3d64574bdba761f429bb4fba0cf687b3338", [ref: "a9e0b3d64574bdba761f429bb4fba0cf687b3338"]}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "cors_plug": {:hex, :cors_plug, "3.0.3", "7c3ac52b39624bc616db2e937c282f3f623f25f8d550068b6710e58d04a0e330", [:mix], [{:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3f2d759e8c272ed3835fab2ef11b46bddab8c1ab9528167bd463b6452edf830d"}, "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, - "credo": {:hex, :credo, "1.7.0", "6119bee47272e85995598ee04f2ebbed3e947678dee048d10b5feca139435f75", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6839fcf63d1f0d1c0f450abc8564a57c43d644077ab96f2934563e68b8a769d7"}, + "credo": {:hex, :credo, "1.7.1", "6e26bbcc9e22eefbff7e43188e69924e78818e2fe6282487d0703652bc20fd62", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e9871c6095a4c0381c89b6aa98bc6260a8ba6addccf7f6a53da8849c748a58a2"}, "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"}, - "db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"}, + "db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, - "dialyxir": {:hex, :dialyxir, "1.3.0", "fd1672f0922b7648ff9ce7b1b26fcf0ef56dda964a459892ad15f6b4410b5284", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "00b2a4bcd6aa8db9dcb0b38c1225b7277dca9bc370b6438715667071a304696f"}, - "earmark": {:hex, :earmark, "1.4.39", "acdb2f02c536471029dbcc509fbd6b94b89f40ad7729fb3f68f4b6944843f01d", [:mix], [{:earmark_parser, "~> 1.4.33", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "156c9d8ec3cbeccdbf26216d8247bdeeacc8c76b4d9eee7554be2f1b623ea440"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"}, + "dialyxir": {:hex, :dialyxir, "1.4.2", "764a6e8e7a354f0ba95d58418178d486065ead1f69ad89782817c296d0d746a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "516603d8067b2fd585319e4b13d3674ad4f314a5902ba8130cd97dc902ce6bbd"}, + "earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, "eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"}, "ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"}, "ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"}, - "ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.12", "e3bd8318702b069263d0118e7cdb6c66c5ff0a034f540f4c0158bd769e7dff6a", [:mix], [{:ecto_sql, "~> 3.7", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "4a1d1d10b74ce033a428a99272038c90e444a0a1912a074e38a71ee9f667714c"}, - "ecto_sql": {:hex, :ecto_sql, "3.10.1", "6ea6b3036a0b0ca94c2a02613fd9f742614b5cfe494c41af2e6571bb034dd94c", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f6a25bdbbd695f12c8171eaff0851fa4c8e72eec1e98c7364402dda9ce11c56b"}, + "ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.14", "7a20cfe913b0476542b43870e67386461258734896035e3f284039fd18bd4c4c", [:mix], [{:ecto_sql, "~> 3.7", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "22f5f98592dd597db9416fcef00effae0787669fdcb6faf447e982b553798e98"}, + "ecto_sql": {:hex, :ecto_sql, "3.10.2", "6b98b46534b5c2f8b8b5f03f126e75e2a73c64f3c071149d32987a5378b0fdbd", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "68c018debca57cb9235e3889affdaec7a10616a4e3a80c99fa1d01fdafaa9007"}, "elasticsearch": {:git, "https://akkoma.dev/AkkomaGang/elasticsearch-elixir.git", "6cd946f75f6ab9042521a009d1d32d29a90113ca", [ref: "main"]}, - "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"}, + "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"}, + "elixir_xml_to_map": {:hex, :elixir_xml_to_map, "3.0.0", "67dcff30ecf72aed37ab08525133e4420717a749436e22bfece431e7dddeea7e", [:mix], [{:erlsom, "~> 1.4", [hex: :erlsom, repo: "hexpm", optional: false]}], "hexpm", "11222dd7f029f8db7a6662b41c992dbdb0e1c6e4fdea6a42056f9d27c847efbb"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, + "erlsom": {:hex, :erlsom, "1.5.1", "c8fe2babd33ff0846403f6522328b8ab676f896b793634cfe7ef181c05316c03", [:rebar3], [], "hexpm", "7965485494c5844dd127656ac40f141aadfa174839ec1be1074e7edf5b4239eb"}, "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"}, - "ex_aws": {:hex, :ex_aws, "2.4.4", "d7886eaca7e10f7bd3d9e9d2d5414cb336737b3ab2fddd4fa30358b725293fe0", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a7d63e485ca2b16fb804f3f20097827aa69885eea6e69fa75c98f353c9c91dc7"}, - "ex_aws_s3": {:hex, :ex_aws_s3, "2.4.0", "ce8decb6b523381812798396bc0e3aaa62282e1b40520125d1f4eff4abdff0f4", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "85dda6e27754d94582869d39cba3241d9ea60b6aa4167f9c88e309dc687e56bb"}, + "ex_aws": {:hex, :ex_aws, "2.5.0", "1785e69350b16514c1049330537c7da10039b1a53e1d253bbd703b135174aec3", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "971b86e5495fc0ae1c318e35e23f389e74cf322f2c02d34037c6fc6d405006f1"}, + "ex_aws_s3": {:hex, :ex_aws_s3, "2.5.2", "cee302b8e9ee198cc0d89f1de2a7d6a8921e1a556574476cf5590d2156590fe3", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "cc5bd945a22a99eece4721d734ae2452d3717e81c357a781c8574663254df4a1"}, "ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm", "96fd346610cc992b8f896ed26a98be82ac4efb065a0578f334a32d60a3ba9767"}, - "ex_doc": {:hex, :ex_doc, "0.30.3", "bfca4d340e3b95f2eb26e72e4890da83e2b3a5c5b0e52607333bf5017284b063", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "fbc8702046c1d25edf79de376297e608ac78cdc3a29f075484773ad1718918b6"}, + "ex_doc": {:hex, :ex_doc, "0.31.0", "06eb1dfd787445d9cab9a45088405593dd3bb7fe99e097eaa71f37ba80c7a676", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "5350cafa6b7f77bdd107aa2199fe277acf29d739aba5aee7e865fc680c62a110"}, "ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"}, "ex_syslogger": {:hex, :ex_syslogger, "2.0.0", "de6de5c5472a9c4fdafb28fa6610e381ae79ebc17da6490b81d785d68bd124c9", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "a52b2fe71764e9e6ecd149ab66635812f68e39279cbeee27c52c0e35e8b8019e"}, "excoveralls": {:hex, :excoveralls, "0.16.1", "0bd42ed05c7d2f4d180331a20113ec537be509da31fed5c8f7047ce59ee5a7c5", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "dae763468e2008cf7075a64cb1249c97cb4bc71e236c5c2b5e5cdf1cfa2bf138"}, "expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"}, "fast_html": {:hex, :fast_html, "2.2.0", "6c5ef1be087a4ed613b0379c13f815c4d11742b36b67bb52cee7859847c84520", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "064c4f23b4a6168f9187dac8984b056f2c531bb0787f559fd6a8b34b38aefbae"}, "fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"}, + "file_ex": {:git, "https://akkoma.dev/AkkomaGang/file_ex.git", "cc7067c7d446c2526e9ecf91d40896b088851569", [ref: "cc7067c7d446c2526e9ecf91d40896b088851569"]}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "finch": {:hex, :finch, "0.16.0", "40733f02c89f94a112518071c0a91fe86069560f5dbdb39f9150042f44dcfb1a", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f660174c4d519e5fec629016054d60edd822cdfe2b7270836739ac2f97735ec5"}, "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"}, - "floki": {:hex, :floki, "0.34.3", "5e2dcaec5d7c228ce5b1d3501502e308b2d79eb655e4191751a1fe491c37feac", [:mix], [], "hexpm", "9577440eea5b97924b4bf3c7ea55f7b8b6dce589f9b28b096cc294a8dc342341"}, + "floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"}, "gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"}, "gettext": {:hex, :gettext, "0.22.3", "c8273e78db4a0bb6fba7e9f0fd881112f349a3117f7f7c598fa18c66c888e524", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "935f23447713954a6866f1bb28c3a878c4c011e802bcd68a726f5e558e4b64bd"}, - "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, + "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.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", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, - "http_signatures": {:hex, :http_signatures, "0.1.1", "ca7ebc1b61542b163644c8c3b1f0e0f41037d35f2395940d3c6c7deceab41fd8", [:mix], [], "hexpm", "cc3b8a007322cc7b624c0c15eec49ee58ac977254ff529a3c482f681465942a3"}, + "http_signatures": {:git, "https://akkoma.dev/AkkomaGang/http_signatures.git", "6640ce7d24c783ac2ef56e27d00d12e8dc85f396", [ref: "6640ce7d24c783ac2ef56e27d00d12e8dc85f396"]}, "httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, "joken": {:hex, :joken, "2.6.0", "b9dd9b6d52e3e6fcb6c65e151ad38bf4bc286382b5b6f97079c47ade6b1bcc6a", [:mix], [{:jose, "~> 1.11.5", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "5a95b05a71cd0b54abd35378aeb1d487a23a52c324fa7efdffc512b655b5aaa7"}, "jose": {:hex, :jose, "1.11.6", "613fda82552128aa6fb804682e3a616f4bc15565a048dabd05b1ebd5827ed965", [:mix, :rebar3], [], "hexpm", "6275cb75504f9c1e60eeacb771adfeee4905a9e182103aa59b53fed651ff9738"}, - "jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"}, + "jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"}, "linkify": {:git, "https://akkoma.dev/AkkomaGang/linkify.git", "2567e2c1073fa371fd26fd66dfa5bc77b6919c16", []}, - "mail": {:hex, :mail, "0.3.0", "f353ef5f41d9f2e483ba7c5df92cdfe27b990b2d8c8c41d84c7b2b40ec33989f", [:mix], [], "hexpm", "523d700b2231d887dc4ee41d3bb13f48358f6f118e55a67cef6d630d7907116c"}, - "majic": {:hex, :majic, "1.0.0", "37e50648db5f5c2ff0c9fb46454d034d11596c03683807b9fb3850676ffdaab3", [:make, :mix], [{:elixir_make, "~> 0.6.1", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7905858f76650d49695f14ea55cd9aaaee0c6654fa391671d4cf305c275a0a9e"}, - "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, + "mail": {:hex, :mail, "0.3.1", "cb0a14e4ed8904e4e5a08214e686ccf6f9099346885db17d8c309381f865cc5c", [:mix], [], "hexpm", "1db701e89865c1d5fa296b2b57b1cd587587cca8d8a1a22892b35ef5a8e352a6"}, + "majic": {:git, "https://akkoma.dev/AkkomaGang/majic.git", "80540b36939ec83f48e76c61e5000e0fd67706f0", [ref: "80540b36939ec83f48e76c61e5000e0fd67706f0"]}, + "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.3", "d684f4bac8690e70b06eb52dad65d26de2eefa44cd19d64a8095e1417df7c8fd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "b78dc853d2e670ff6390b605d807263bf606da3c82be37f9d7f68635bd886fc9"}, "meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mfm_parser": {:git, "https://akkoma.dev/AkkomaGang/mfm-parser.git", "912fba81152d4d572e457fd5427f9875b2bc3dbe", [ref: "912fba81152d4d572e457fd5427f9875b2bc3dbe"]}, - "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, + "mfm_parser": {:git, "https://akkoma.dev/AkkomaGang/mfm-parser.git", "b21ab7754024af096f2d14247574f55f0063295b", [ref: "b21ab7754024af096f2d14247574f55f0063295b"]}, + "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, - "mint": {:hex, :mint, "1.5.1", "8db5239e56738552d85af398798c80648db0e90f343c8469f6c6d8898944fb6f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4a63e1e76a7c3956abd2c72f370a0d0aecddc3976dea5c27eccbecfa5e7d5b1e"}, + "mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"}, "mock": {:hex, :mock, "0.3.8", "7046a306b71db2488ef54395eeb74df0a7f335a7caca4a3d3875d1fc81c884dd", [:mix], [{:meck, "~> 0.9.2", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "7fa82364c97617d79bb7d15571193fc0c4fe5afd0c932cef09426b3ee6fe2022"}, "mogrify": {:hex, :mogrify, "0.9.3", "238c782f00271dace01369ad35ae2e9dd020feee3443b9299ea5ea6bed559841", [:mix], [], "hexpm", "0189b1e1de27455f2b9ae8cf88239cefd23d38de9276eb5add7159aea51731e6"}, - "mox": {:hex, :mox, "1.0.2", "dc2057289ac478b35760ba74165b4b3f402f68803dd5aecd3bfd19c183815d64", [:mix], [], "hexpm", "f9864921b3aaf763c8741b5b8e6f908f44566f1e427b2630e89e9a73b981fef2"}, - "nimble_options": {:hex, :nimble_options, "1.0.2", "92098a74df0072ff37d0c12ace58574d26880e522c22801437151a159392270e", [:mix], [], "hexpm", "fd12a8db2021036ce12a309f26f564ec367373265b53e25403f0ee697380f1b8"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, - "nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"}, - "oban": {:hex, :oban, "2.15.2", "8f934a49db39163633965139c8846d8e24c2beb4180f34a005c2c7c3f69a6aa2", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0f4a579ea48fc7489e0d84facf8b01566e142bdc6542d7dabce32c10e664f1e9"}, - "open_api_spex": {:hex, :open_api_spex, "3.17.3", "ada8e352eb786050dd639db2439d3316e92f3798eb2abd051f55bb9af825b37e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "165db21a85ca83cffc8e7c8890f35b354eddda8255de7404a2848ed652b9f0fe"}, - "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, - "phoenix": {:hex, :phoenix, "1.6.16", "e5bdd18c7a06da5852a25c7befb72246de4ddc289182285f8685a40b7b5f5451", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e15989ff34f670a96b95ef6d1d25bad0d9c50df5df40b671d8f4a669e050ac39"}, - "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.2", "b21bd01fdeffcfe2fab49e4942aa938b6d3e89e93a480d4aee58085560a0bc0d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "70242edd4601d50b69273b057ecf7b684644c19ee750989fd555625ae4ce8f5d"}, - "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"}, + "mox": {:hex, :mox, "1.1.0", "0f5e399649ce9ab7602f72e718305c0f9cdc351190f72844599545e4996af73c", [:mix], [], "hexpm", "d44474c50be02d5b72131070281a5d3895c0e7a95c780e90bc0cfe712f633a13"}, + "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, + "oban": {:hex, :oban, "2.15.4", "d49ab4ffb7153010e32f80fe9e56f592706238149ec579eb50f8a4e41d218856", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5fce611fdfffb13e9148df883116e5201adf1e731eb302cc88cde0588510079c"}, + "open_api_spex": {:hex, :open_api_spex, "3.18.0", "f9952b6bc8a1bf14168f3754981b7c8d72d015112bfedf2588471dd602e1e715", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "37849887ab67efab052376401fac28c0974b273ffaecd98f4532455ca0886464"}, + "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, + "phoenix": {:hex, :phoenix, "1.7.10", "02189140a61b2ce85bb633a9b6fd02dff705a5f1596869547aeb2b2b95edd729", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "cf784932e010fd736d656d7fead6a584a4498efefe5b8227e9f383bf15bb79d0"}, + "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.3", "86e9878f833829c3f66da03d75254c155d91d72a201eb56ae83482328dc7ca93", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d36c401206f3011fefd63d04e8ef626ec8791975d9d107f9a0817d426f61ac07"}, + "phoenix_html": {:hex, :phoenix_html, "3.3.3", "380b8fb45912b5638d2f1d925a3771b4516b9a78587249cabe394e0a5d579dc9", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "923ebe6fec6e2e3b3e569dfbdc6560de932cd54b000ada0208b5f45024bdd76c"}, "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"}, "phoenix_live_view": {:hex, :phoenix_live_view, "0.18.18", "1f38fbd7c363723f19aad1a04b5490ff3a178e37daaf6999594d5f34796c47fc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a5810d0472f3189ede6d2a95bda7f31c6113156b91784a3426cb0ab6a6d85214"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, "phoenix_swoosh": {:hex, :phoenix_swoosh, "1.2.0", "a544d83fde4a767efb78f45404a74c9e37b2a9c5ea3339692e65a6966731f935", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "e88d117251e89a16b92222415a6d87b99a96747ddf674fc5c7631de734811dba"}, "phoenix_template": {:hex, :phoenix_template, "1.0.3", "32de561eefcefa951aead30a1f94f1b5f0379bc9e340bb5c667f65f1edfa4326", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "16f4b6588a4152f3cc057b9d0c0ba7e82ee23afa65543da535313ad8d25d8e2c"}, - "phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"}, - "plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"}, + "phoenix_view": {:hex, :phoenix_view, "2.0.3", "4d32c4817fce933693741deeb99ef1392619f942633dde834a5163124813aad3", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "cd34049af41be2c627df99cd4eaa71fc52a328c0c3d8e7d4aa28f880c30e7f64"}, + "plug": {:hex, :plug, "1.15.2", "94cf1fa375526f30ff8770837cb804798e0045fd97185f0bb9e5fcd858c792a3", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02731fa0c2dcb03d8d21a1d941bdbbe99c2946c0db098eee31008e04c6283615"}, "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, + "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"}, "poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"}, "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"}, - "postgrex": {:hex, :postgrex, "0.17.2", "a3ec9e3239d9b33f1e5841565c4eb200055c52cc0757a22b63ca2d529bbe764c", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "80a918a9e9531d39f7bd70621422f3ebc93c01618c645f2d91306f50041ed90c"}, + "postgrex": {:hex, :postgrex, "0.17.4", "5777781f80f53b7c431a001c8dad83ee167bcebcf3a793e3906efff680ab62b3", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "6458f7d5b70652bc81c3ea759f91736c16a31be000f306d3c64bcdfe9a18b3cc"}, "pot": {:hex, :pot, "1.0.2", "13abb849139fdc04ab8154986abbcb63bdee5de6ed2ba7e1713527e33df923dd", [:rebar3], [], "hexpm", "78fe127f5a4f5f919d6ea5a2a671827bd53eb9d37e5b4128c0ad3df99856c2e0"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, - "recon": {:hex, :recon, "2.5.3", "739107b9050ea683c30e96de050bc59248fd27ec147696f79a8797ff9fa17153", [:mix, :rebar3], [], "hexpm", "6c6683f46fd4a1dfd98404b9f78dcabc7fcd8826613a89dcb984727a8c3099d7"}, + "recon": {:hex, :recon, "2.5.4", "05dd52a119ee4059fa9daa1ab7ce81bc7a8161a2f12e9d42e9d551ffd2ba901c", [:mix, :rebar3], [], "hexpm", "e9ab01ac7fc8572e41eb59385efeb3fb0ff5bf02103816535bacaedf327d0263"}, "remote_ip": {:hex, :remote_ip, "1.1.0", "cb308841595d15df3f9073b7c39243a1dd6ca56e5020295cb012c76fbec50f2d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "616ffdf66aaad6a72fc546dabf42eed87e2a99e97b09cbd92b10cc180d02ed74"}, "search_parser": {:git, "https://github.com/FloatingGhost/pleroma-contrib-search-parser.git", "08971a81e68686f9ac465cfb6661d51c5e4e1e7f", [ref: "08971a81e68686f9ac465cfb6661d51c5e4e1e7f"]}, "sleeplocks": {:hex, :sleeplocks, "1.1.2", "d45aa1c5513da48c888715e3381211c859af34bee9b8290490e10c90bb6ff0ca", [:rebar3], [], "hexpm", "9fe5d048c5b781d6305c1a3a0f40bb3dfc06f49bf40571f3d2d0c57eaa7f59a5"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, - "sweet_xml": {:hex, :sweet_xml, "0.7.3", "debb256781c75ff6a8c5cbf7981146312b66f044a2898f453709a53e5031b45b", [:mix], [], "hexpm", "e110c867a1b3fe74bfc7dd9893aa851f0eed5518d0d7cad76d7baafd30e4f5ba"}, - "swoosh": {:hex, :swoosh, "1.11.4", "9b353f998cba3c5e101a0669559c2fb2757b5d9eb7db058bf08687d82e93e416", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d3390914022a456ae1604bfcb3431bd12509b2afe8c70296bae6c9dca4903d0f"}, + "sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"}, + "swoosh": {:hex, :swoosh, "1.14.2", "cf686f92ad3b21e6651b20c50eeb1781f581dc7097ef6251b4d322a9f1d19339", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "01d8fae72930a0b5c1bb9725df0408602ed8c5c3d59dc6e7a39c57b723cd1065"}, "syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"}, "table_rex": {:hex, :table_rex, "3.1.1", "0c67164d1714b5e806d5067c1e96ff098ba7ae79413cc075973e17c38a587caa", [:mix], [], "hexpm", "678a23aba4d670419c23c17790f9dcd635a4a89022040df7d5d772cb21012490"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, @@ -117,14 +120,16 @@ "telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.1.0", "4e15f6d7dbedb3a4e3aed2262b7e1407f166fcb9c30ca3f96635dfbbef99965c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0dd10e7fe8070095df063798f82709b0a1224c31b8baf6278b423898d591a069"}, "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"}, "temple": {:git, "https://akkoma.dev/AkkomaGang/temple.git", "066a699ade472d8fa42a9d730b29a61af9bc8b59", [ref: "066a699ade472d8fa42a9d730b29a61af9bc8b59"]}, - "tesla": {:hex, :tesla, "1.7.0", "a62dda2f80d4f8a925eb7b8c5b78c461e0eb996672719fe1a63b26321a5f8b4e", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "2e64f01ebfdb026209b47bc651a0e65203fcff4ae79c11efb73c4852b00dc313"}, + "tesla": {:hex, :tesla, "1.8.0", "d511a4f5c5e42538d97eef7c40ec4f3e44effdc5068206f42ed859e09e51d1fd", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "10501f360cd926a309501287470372af1a6e1cbed0f43949203a4c13300bc79f"}, "timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"}, "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"}, "tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"}, "ueberauth": {:hex, :ueberauth, "0.10.5", "806adb703df87e55b5615cf365e809f84c20c68aa8c08ff8a416a5a6644c4b02", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3efd1f31d490a125c7ed453b926f7c31d78b97b8a854c755f5c40064bf3ac9e1"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, - "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"}, - "vex": {:hex, :vex, "0.9.0", "613ea5eb3055662e7178b83e25b2df0975f68c3d8bb67c1645f0573e1a78d606", [:mix], [], "hexpm", "c69fff44d5c8aa3f1faee71bba1dcab05dd36364c5a629df8bb11751240c857f"}, + "unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"}, + "vex": {:hex, :vex, "0.9.1", "cb65348ebd1c4002861b65bef36e524c29d9a879c90119b2d0e674e323124277", [:mix], [], "hexpm", "a0f9f3959d127ad6a6a617c3f607ecfb1bc6f3c59f9c3614a901a46d1765bafe"}, "web_push_encryption": {:hex, :web_push_encryption, "0.3.1", "76d0e7375142dfee67391e7690e89f92578889cbcf2879377900b5620ee4708d", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.11.1", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "4f82b2e57622fb9337559058e8797cb0df7e7c9790793bdc4e40bc895f70e2a2"}, + "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"}, "websockex": {:hex, :websockex, "0.4.3", "92b7905769c79c6480c02daacaca2ddd49de936d912976a4d3c923723b647bf0", [:mix], [], "hexpm", "95f2e7072b85a3a4cc385602d42115b73ce0b74a9121d0d6dbbf557645ac53e4"}, } diff --git a/priv/gettext/pl/LC_MESSAGES/config_descriptions.po b/priv/gettext/pl/LC_MESSAGES/config_descriptions.po index d212a7d87..0692a61cd 100644 --- a/priv/gettext/pl/LC_MESSAGES/config_descriptions.po +++ b/priv/gettext/pl/LC_MESSAGES/config_descriptions.po @@ -8,50 +8,50 @@ ### to merge POT files into PO files. msgid "" msgstr "" -"PO-Revision-Date: 2023-08-04 14:26+0000\n" -"Last-Translator: Anonymous \n" +"PO-Revision-Date: 2023-10-22 11:53+0000\n" +"Last-Translator: subtype \n" "Language-Team: Polish \n" "Language: pl\n" "Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2;\n" "X-Generator: Weblate 4.18.2\n" -"Content-Transfer-Encoding: 8bit\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :logger" msgid "Logger-related settings" -msgstr "Logger-related settings" +msgstr "Ustawienia związane z Loggerem" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :mime" msgid "Mime Types settings" -msgstr "Mime Types settings" +msgstr "Ustawienia typów Mime" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma" msgid "Allows setting a token that can be used to authenticate requests with admin privileges without a normal user account token. Append the `admin_token` parameter to requests to utilize it. (Please reconsider using HTTP Basic Auth or OAuth-based authentication if possible)" msgstr "" -"Allows setting a token that can be used to authenticate requests with admin " -"privileges without a normal user account token. Append the `admin_token` " -"parameter to requests to utilize it. (Please reconsider using HTTP Basic " -"Auth or OAuth-based authentication if possible)" +"Pozwala na ustawienie tokenu, który może zostać użyty do uwierzytelniania " +"zapytań z uprawnieniami administratora bez zwykłego tokenu użytkownika. " +"Dodaj parametr `admin_token` by go użyć. (Proszę przemyśl użycie " +"uwierzytelnienia HTTP Basic Auth lub OAuth jeśli to możliwe)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma" msgid "Authenticator" -msgstr "Authenticator" +msgstr "Uwierzytelniacz" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :cors_plug" msgid "CORS plug config" -msgstr "CORS plug config" +msgstr "Konfiguracja wtyczki CORS" #: lib/pleroma/docs/translator.ex:5 #, elixir-autogen, elixir-format, fuzzy @@ -60,1158 +60,1161 @@ msgid "Logger" msgstr "Logger" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :mime" msgid "Mime Types" -msgstr "Mime Types" +msgstr "Typy Mime" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma" msgid "Pleroma Admin Token" -msgstr "Pleroma Admin Token" +msgstr "Token Administratora Pleromy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma" msgid "Pleroma Authenticator" -msgstr "Pleroma Authenticator" +msgstr "Uwierzytelniacz Pleromy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :logger-:console" msgid "Console logger settings" -msgstr "Console logger settings" +msgstr "Ustawienia logowania do konsoli" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :logger-:ex_syslogger" msgid "ExSyslogger-related settings" -msgstr "ExSyslogger-related settings" +msgstr "Ustawienia zwiazane z ExSysloggerem" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:activitypub" msgid "ActivityPub-related settings" -msgstr "ActivityPub-related settings" +msgstr "Ustawienia związane z ActivityPub" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:assets" msgid "This section configures assets to be used with various frontends. Currently the only option relates to mascots on the mastodon frontend" msgstr "" -"This section configures assets to be used with various frontends. Currently " -"the only option relates to mascots on the mastodon frontend" +"Ta sekcja konfiguruje zasoby używane przez różne frontendy. Jak na razie, " +"jedyne opcje są związane z maskotkami na frontendzie Mastodon." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:auth" msgid "Authentication / authorization settings" -msgstr "Authentication / authorization settings" +msgstr "Ustawienia uwierzytelniania / autoryzacji." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:email_notifications" msgid "Email notifications settings" -msgstr "Email notifications settings" +msgstr "Ustawienia powiadomień przez e-mail" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:features" msgid "Customizable features" -msgstr "Customizable features" +msgstr "Konfigurowalne funkcjonalności" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:feed" msgid "Configure feed rendering" -msgstr "Configure feed rendering" +msgstr "Konfiguruj wyświetlanie osi czasu" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:frontends" msgid "Installed frontends management" -msgstr "Installed frontends management" +msgstr "Zarządzanie zainstalowanymi frontendami" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:http" msgid "HTTP settings" -msgstr "HTTP settings" +msgstr "Ustawienia HTTP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:http_security" msgid "HTTP security settings" -msgstr "HTTP security settings" +msgstr "Ustawienia bezpieczeństwa HTTP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:instance" msgid "Instance-related settings" -msgstr "Instance-related settings" +msgstr "Ustawienia związane z intancją" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:instances_favicons" msgid "Control favicons for instances" -msgstr "Control favicons for instances" +msgstr "Kontrola favikonek dla instancji" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:ldap" msgid "Use LDAP for user authentication. When a user logs in to the Pleroma instance, the name and password will be verified by trying to authenticate (bind) to a LDAP server. If a user exists in the LDAP directory but there is no account with the same name yet on the Pleroma instance then a new Pleroma account will be created with the same name as the LDAP user name." msgstr "" -"Use LDAP for user authentication. When a user logs in to the Pleroma " -"instance, the name and password will be verified by trying to authenticate " -"(bind) to a LDAP server. If a user exists in the LDAP directory but there is " -"no account with the same name yet on the Pleroma instance then a new Pleroma " -"account will be created with the same name as the LDAP user name." +"Użyj LDAP do uwierzytelnienia użytkowników. Kiedy użytkownik zaloguje się do " +"instancji Akkomy, nazwa i hasło zostaną zweryfikowane przez próbę " +"uwierzytelnienia w serwerze LDAP. Jeśli użytkownik istnieje w katalogu LDAP " +"ale nie ma jeszcze konta z tą nazwą na instancji Akkomy, wtedy nowe konto " +"Akkomy zostanie stworzone z tą samą nazwą jak nazwa użytkownika LDAP." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:majic_pool" msgid "Majic/libmagic configuration" -msgstr "Majic/libmagic configuration" +msgstr "Konfiguracja majic/libmagic" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:manifest" msgid "This section describe PWA manifest instance-specific values. Currently this option relate only for MastoFE." msgstr "" -"This section describe PWA manifest instance-specific values. Currently this " -"option relate only for MastoFE." +"Ta sekcja opisuje właściwe dla instancji wartości manifestu PWA. Jak na " +"razie, ta opcja jest związana tylko z MastoFE." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:media_preview_proxy" msgid "Media preview proxy" -msgstr "Media preview proxy" +msgstr "Proxy podglądu mediów" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:media_proxy" msgid "Media proxy" -msgstr "Media proxy" +msgstr "Proxy mediów" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:modules" msgid "Custom Runtime Modules" -msgstr "Custom Runtime Modules" +msgstr "Własne moduły czasu działania" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf" msgid "General MRF settings" -msgstr "General MRF settings" +msgstr "Ogólne ustawienia MRF" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_activity_expiration" msgid "Adds automatic expiration to all local activities" -msgstr "Adds automatic expiration to all local activities" +msgstr "Dodaj automatyczne wygaśnięcie do wszystkich lokalnych aktywności" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_follow_bot" msgid "Automatically follows newly discovered accounts." -msgstr "Automatically follows newly discovered accounts." +msgstr "Automatycznie śledzi nowoodnalezione konta" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_hashtag" msgid "Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags (without the leading #)\n\nNote: This MRF Policy is always enabled, if you want to disable it you have to set empty lists.\n" msgstr "" -"Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags (" -"without the leading #)\n" +"Odrzuć, usuń z całej znanej sieci, lub ustaw jako wrażliwe wiadomości z " +"określonymi hasztagami (bez #)\n" "\n" -"Note: This MRF Policy is always enabled, if you want to disable it you have " -"to set empty lists.\n" +"Uwaga: ta zasada MRF jest zawsze włączona. Jeśli chcesz ją wyłączyć, zostaw " +"listę pustą.\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_hellthread" msgid "Block messages with excessive user mentions" -msgstr "Block messages with excessive user mentions" +msgstr "Blokuj wiadomości ze zbyt dużą liczbą wspomnień" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_keyword" msgid "Reject or Word-Replace messages matching a keyword or [Regex](https://hexdocs.pm/elixir/Regex.html)." msgstr "" -"Reject or Word-Replace messages matching a keyword or [Regex](https://hexdocs" -".pm/elixir/Regex.html)." +"Odrzuć lub zmień treść wiadomości zawierających słowo kluczowe lub " +"pasujących do [regexa](https://hexdocs.pm/elixir/Regex.html)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_mention" msgid "Block messages which mention a specific user" -msgstr "Block messages which mention a specific user" +msgstr "Blokuj wiadomości wspominające o określonych użytkownikach" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_normalize_markup" msgid "MRF NormalizeMarkup settings. Scrub configured hypertext markup." -msgstr "MRF NormalizeMarkup settings. Scrub configured hypertext markup." +msgstr "" +"Ustawienia MRF NormalizeMarkup. Wyczyść skonfigurowany markup hipertekstu." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_object_age" msgid "Rejects or delists posts based on their timestamp deviance from your server's clock." -msgstr "" -"Rejects or delists posts based on their timestamp deviance from your " -"server's clock." +msgstr "Odrzuć lub usuń z osi czasu wpisy biorąc pod uwagę ich datę utworzenia." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_rejectnonpublic" msgid "RejectNonPublic drops posts with non-public visibility settings." -msgstr "RejectNonPublic drops posts with non-public visibility settings." +msgstr "RejectNonPublic usuwa wpisy które nie są oznaczone jako publiczne." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_simple" msgid "Simple ingress policies" -msgstr "Simple ingress policies" +msgstr "Proste zasady modyfikacji wiadomości przychodzących" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_steal_emoji" msgid "Steals emojis from selected instances when it sees them." -msgstr "Steals emojis from selected instances when it sees them." +msgstr "Kradnij emoji z określonych instancji gdy tylko je zobaczysz." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_subchain" msgid "This policy processes messages through an alternate pipeline when a given message matches certain criteria. All criteria are configured as a map of regular expressions to lists of policy modules." msgstr "" -"This policy processes messages through an alternate pipeline when a given " -"message matches certain criteria. All criteria are configured as a map of " -"regular expressions to lists of policy modules." +"Ta taktyka przetwarza wiadomości przez alternatywny potok jeśli wiadomość " +"pasuje do określonych kryteriów. Wszystkie kryteria są skonfigurowane jako " +"mapa wyrażeń regularnych na listę modułów zasad." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:mrf_vocabulary" msgid "Filter messages which belong to certain activity vocabularies" -msgstr "Filter messages which belong to certain activity vocabularies" +msgstr "Filtruj wiadomości należących do określonego słownictwa aktywności" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:oauth2" msgid "Configure OAuth 2 provider capabilities" -msgstr "Configure OAuth 2 provider capabilities" +msgstr "Konfiguruj możliwości dostawcy OAuth 2" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:populate_hashtags_table" msgid "`populate_hashtags_table` background migration settings" -msgstr "`populate_hashtags_table` background migration settings" +msgstr "Ustawienia migracji w tle:`populate_hashtags_table`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:rate_limit" msgid "Rate limit settings. This is an advanced feature enabled only for :authentication by default." msgstr "" -"Rate limit settings. This is an advanced feature enabled only for :" -"authentication by default." +"Ustawienia limitów prędkości. To jest zaawansowana funkcjonalność włączona " +"domyślnie tylko dla :authentication." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:rich_media" msgid "If enabled the instance will parse metadata from attached links to generate link previews" msgstr "" -"If enabled the instance will parse metadata from attached links to generate " -"link previews" +"Jeżeli włączone, ta instancja będzie przetwarzać metadane z dołączonych " +"linków by tworzyć podglądy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:static_fe" msgid "Render profiles and posts using server-generated HTML that is viewable without using JavaScript" msgstr "" -"Render profiles and posts using server-generated HTML that is viewable " -"without using JavaScript" +"Wyświetlaj profile i posty używając tworzonego na serwerze HTML który można " +"przeglądać bez JavaScript" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:streamer" msgid "Settings for notifications streamer" -msgstr "Settings for notifications streamer" +msgstr "Ustawienia wysyłania powiadomień" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:uri_schemes" msgid "URI schemes related settings" -msgstr "URI schemes related settings" +msgstr "Ustawienia związane ze schematami URI" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:web_cache_ttl" msgid "The expiration time for the web responses cache. Values should be in milliseconds or `nil` to disable expiration." msgstr "" -"The expiration time for the web responses cache. Values should be in " -"milliseconds or `nil` to disable expiration." +"Czas wygaśnięcia cache odpowiedzi sieciowych. Wartość powinna być podana w " +"milisekundach, lub `nil` by wyłączyć." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:welcome" msgid "Welcome messages settings" -msgstr "Welcome messages settings" +msgstr "Ustawienia wiadomości powitalnych" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:workers" msgid "Includes custom worker options not interpretable directly by `Oban`" -msgstr "Includes custom worker options not interpretable directly by `Oban`" +msgstr "" +"Zawiera dodatkowe opcje workerów nieinterpretowalne bezpośrednio przez `Oban`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-ConcurrentLimiter" msgid "Limits configuration for background tasks." -msgstr "Limits configuration for background tasks." +msgstr "Konfiguracja limitów dla zadań w tle." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Oban" msgid "[Oban](https://github.com/sorentwo/oban) asynchronous job processor configuration." msgstr "" -"[Oban](https://github.com/sorentwo/oban) asynchronous job processor " -"configuration." +"Konfiguracja procesora zadań asynchronicznych [Oban](https://github.com/" +"sorentwo/oban)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Captcha" msgid "Captcha-related settings" -msgstr "Captcha-related settings" +msgstr "Ustawienia związane z Captcha" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Captcha.Kocaptcha" msgid "Kocaptcha is a very simple captcha service with a single API endpoint, the source code is here: https://github.com/koto-bank/kocaptcha. The default endpoint (https://captcha.kotobank.ch) is hosted by the developer." msgstr "" -"Kocaptcha is a very simple captcha service with a single API endpoint, the " -"source code is here: https://github.com/koto-bank/kocaptcha. The default " -"endpoint (https://captcha.kotobank.ch) is hosted by the developer." +"Kocaptcha to bardzo prosta usługa captcha z pojedynczym endpointem API, kod " +"źródłowy jest tu: https://github.com/koto-bank/kocaptcha. Domyślny endpoint " +"(https://captcha.kotobank.ch) jest hostowany przez developera." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Emails.Mailer" msgid "Mailer-related settings" -msgstr "Mailer-related settings" +msgstr "Ustawienia związane z Mailerem" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Emails.NewUsersDigestEmail" msgid "New users admin email digest" -msgstr "New users admin email digest" +msgstr "Administracyjne podsumowanie e-maili dla nowych użytkowników" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Emails.UserEmail" msgid "Email template settings" -msgstr "Email template settings" +msgstr "Ustawienia szablonów e-maili" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Formatter" msgid "Configuration for Pleroma's link formatter which parses mentions, hashtags, and URLs." msgstr "" -"Configuration for Pleroma's link formatter which parses mentions, hashtags, " -"and URLs." +"Konfiguracja formattera linków Akkomy, który przetwarza wspomnienia, " +"hasztagi, i URL." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.ScheduledActivity" msgid "Scheduled activities settings" -msgstr "Scheduled activities settings" +msgstr "Ustawienia zaplanowanych aktywności" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Upload" msgid "Upload general settings" -msgstr "Upload general settings" +msgstr "Ustawienia wysyłania plików" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename" msgid "Filter replaces the filename of the upload" -msgstr "Filter replaces the filename of the upload" +msgstr "Filtr zmienia nazwę wysyłanego pliku" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Upload.Filter.Mogrify" msgid "Uploads mogrify filter settings" -msgstr "Uploads mogrify filter settings" +msgstr "Ustawienia mogrifera wysyłanych plików" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Uploaders.Local" msgid "Local uploader-related settings" -msgstr "Local uploader-related settings" +msgstr "Ustawnia związane z lokalnym wysyłaniem" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Uploaders.S3" msgid "S3 uploader-related settings" -msgstr "S3 uploader-related settings" +msgstr "Ustawienia związane z wysyłaniem na S3" #: lib/pleroma/docs/translator.ex:5 #, elixir-autogen, elixir-format, fuzzy msgctxt "config description at :pleroma-Pleroma.User.Backup" msgid "Account Backup" -msgstr "Account Backup" +msgstr "Kopia zapasowa konta" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http" msgid "HTTP invalidate settings" -msgstr "HTTP invalidate settings" +msgstr "Ustawienia inwalidacji HTTP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script" msgid "Invalidation script settings" -msgstr "Invalidation script settings" +msgstr "Ustawienia skryptu inwalidacyjnego" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Web.Metadata" msgid "Metadata-related settings" -msgstr "Metadata-related settings" +msgstr "Ustawienia związane z metadanymi" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Web.Plugs.RemoteIp" msgid "`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration.\n**If your instance is not behind at least one reverse proxy, you should not enable this plug.**\n" msgstr "" -"`Pleroma.Web.Plugs.RemoteIp` is a shim to call [`RemoteIp`](https://git." -"pleroma.social/pleroma/remote_ip) but with runtime configuration.\n" -"**If your instance is not behind at least one reverse proxy, you should not " -"enable this plug.**\n" +"`Pleroma.Web.Plugs.RemoteIp` to podkładka by wywołać [`RemoteIp`](https://git" +".pleroma.social/pleroma/remote_ip) ale z konfiguracją w czasie działania.\n" +"**Jeśli twoja intancja nie jest przynajmniej za jednym odwrotnym proxy, nie " +"powinnoś włączać tej wtyczki.**\n" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Web.Preload" msgid "Preload-related settings" -msgstr "Preload-related settings" +msgstr "Ustawienia preloadu" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-Pleroma.Workers.PurgeExpiredActivity" msgid "Expired activities settings" -msgstr "Expired activities settings" +msgstr "Ustawienia wygasłych aktywności" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :web_push_encryption-:vapid_details" msgid "Web Push Notifications configuration. You can use the mix task mix web_push.gen.keypair to generate it." msgstr "" -"Web Push Notifications configuration. You can use the mix task mix " -"web_push.gen.keypair to generate it." +"Ustawienia powiadomień Push. Możesz użyć zadania mix web_push.gen.keypair by " +"je wygenerować." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :ex_aws-:s3" msgid "S3" msgstr "S3" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :logger-:console" msgid "Console Logger" -msgstr "Console Logger" +msgstr "Logger konsolowy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :logger-:ex_syslogger" msgid "ExSyslogger" msgstr "ExSyslogger" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:activitypub" msgid "ActivityPub" msgstr "ActivityPub" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:assets" msgid "Assets" -msgstr "Assets" +msgstr "Zasoby" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:auth" msgid "Auth" -msgstr "Auth" +msgstr "Autoryzacja" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:email_notifications" msgid "Email notifications" -msgstr "Email notifications" +msgstr "Powiadomienia e-mail" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:emoji" msgid "Emoji" msgstr "Emoji" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:features" msgid "Features" -msgstr "Features" +msgstr "Funkcjonalności" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:feed" msgid "Feed" -msgstr "Feed" +msgstr "Oś czasu" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:frontend_configurations" msgid "Frontend configurations" -msgstr "Frontend configurations" +msgstr "Konfiguracje frontenów" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:frontends" msgid "Frontends" -msgstr "Frontends" +msgstr "Frontendy" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:http" msgid "HTTP" msgstr "HTTP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:http_security" msgid "HTTP security" -msgstr "HTTP security" +msgstr "Bezpieczeństwo HTTP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:instance" msgid "Instance" -msgstr "Instance" +msgstr "Instancja" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:instances_favicons" msgid "Instances favicons" -msgstr "Instances favicons" +msgstr "Favikonki instancji" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:ldap" msgid "LDAP" msgstr "LDAP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:majic_pool" msgid "Majic pool" -msgstr "Majic pool" +msgstr "Pula Majic" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:manifest" msgid "Manifest" msgstr "Manifest" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:markup" msgid "Markup Settings" -msgstr "Markup Settings" +msgstr "Ustawienia Markup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:media_preview_proxy" msgid "Media preview proxy" -msgstr "Media preview proxy" +msgstr "Proxy podglądu mediów" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:media_proxy" msgid "Media proxy" -msgstr "Media proxy" +msgstr "Proxy mediów" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:modules" msgid "Modules" -msgstr "Modules" +msgstr "Moduły" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf" msgid "MRF" msgstr "MRF" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_activity_expiration" msgid "MRF Activity Expiration Policy" -msgstr "MRF Activity Expiration Policy" +msgstr "MRF Wygaśnięcie Aktyności" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_follow_bot" msgid "MRF FollowBot Policy" -msgstr "MRF FollowBot Policy" +msgstr "MRF Bot Śledzący" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_hashtag" msgid "MRF Hashtag" msgstr "MRF Hashtag" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_hellthread" msgid "MRF Hellthread" msgstr "MRF Hellthread" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_keyword" msgid "MRF Keyword" -msgstr "MRF Keyword" +msgstr "MRF Słowa Kluczowe" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_mention" msgid "MRF Mention" -msgstr "MRF Mention" +msgstr "MRF Wspomnienia" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_normalize_markup" msgid "MRF Normalize Markup" -msgstr "MRF Normalize Markup" +msgstr "MRF Normalizuj Markup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_object_age" msgid "MRF Object Age" -msgstr "MRF Object Age" +msgstr "MRF Wiek Objektów" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_rejectnonpublic" msgid "MRF Reject Non Public" -msgstr "MRF Reject Non Public" +msgstr "MRF Odrzuć Niepubliczne" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_simple" msgid "MRF Simple" -msgstr "MRF Simple" +msgstr "MRF Prosty" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_steal_emoji" msgid "MRF Emojis" -msgstr "MRF Emojis" +msgstr "MRF Emoji" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_subchain" msgid "MRF Subchain" msgstr "MRF Subchain" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:mrf_vocabulary" msgid "MRF Vocabulary" -msgstr "MRF Vocabulary" +msgstr "MRF Słownictwo" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:oauth2" msgid "OAuth2" msgstr "OAuth2" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:populate_hashtags_table" msgid "Populate hashtags table" -msgstr "Populate hashtags table" +msgstr "Wypełnij tabelę hasztagów" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:rate_limit" msgid "Rate limit" -msgstr "Rate limit" +msgstr "Limit prędkości" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:restrict_unauthenticated" msgid "Restrict Unauthenticated" -msgstr "Restrict Unauthenticated" +msgstr "Ogranicz nieuwieżytelnione" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:rich_media" msgid "Rich media" -msgstr "Rich media" +msgstr "Bogate media" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:static_fe" msgid "Static FE" -msgstr "Static FE" +msgstr "Statyczny FE" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:streamer" msgid "Streamer" msgstr "Streamer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:uri_schemes" msgid "URI Schemes" -msgstr "URI Schemes" +msgstr "Schematy URI" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:user" msgid "User" -msgstr "User" +msgstr "Użytkownik" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:web_cache_ttl" msgid "Web cache TTL" -msgstr "Web cache TTL" +msgstr "TTL cache sieciowego" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:welcome" msgid "Welcome" -msgstr "Welcome" +msgstr "Witaj" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-:workers" msgid "Workers" -msgstr "Workers" +msgstr "Workery" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-ConcurrentLimiter" msgid "ConcurrentLimiter" msgstr "ConcurrentLimiter" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Oban" msgid "Oban" msgstr "Oban" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Captcha" msgid "Pleroma.Captcha" msgstr "Pleroma.Captcha" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Captcha.Kocaptcha" msgid "Pleroma.Captcha.Kocaptcha" msgstr "Pleroma.Captcha.Kocaptcha" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Emails.Mailer" msgid "Pleroma.Emails.Mailer" msgstr "Pleroma.Emails.Mailer" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Emails.NewUsersDigestEmail" msgid "Pleroma.Emails.NewUsersDigestEmail" msgstr "Pleroma.Emails.NewUsersDigestEmail" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Emails.UserEmail" msgid "Pleroma.Emails.UserEmail" msgstr "Pleroma.Emails.UserEmail" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Formatter" msgid "Linkify" msgstr "Linkify" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.ScheduledActivity" msgid "Pleroma.ScheduledActivity" msgstr "Pleroma.ScheduledActivity" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Upload" msgid "Pleroma.Upload" msgstr "Pleroma.Upload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Upload.Filter.AnonymizeFilename" msgid "Pleroma.Upload.Filter.AnonymizeFilename" msgstr "Pleroma.Upload.Filter.AnonymizeFilename" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Upload.Filter.Mogrify" msgid "Pleroma.Upload.Filter.Mogrify" msgstr "Pleroma.Upload.Filter.Mogrify" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Uploaders.Local" msgid "Pleroma.Uploaders.Local" msgstr "Pleroma.Uploaders.Local" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Uploaders.S3" msgid "Pleroma.Uploaders.S3" msgstr "Pleroma.Uploaders.S3" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.User" msgid "Pleroma.User" msgstr "Pleroma.User" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.User.Backup" msgid "Pleroma.User.Backup" msgstr "Pleroma.User.Backup" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Web.ApiSpec.CastAndValidate" msgid "Pleroma.Web.ApiSpec.CastAndValidate" msgstr "Pleroma.Web.ApiSpec.CastAndValidate" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Http" msgid "Pleroma.Web.MediaProxy.Invalidation.Http" msgstr "Pleroma.Web.MediaProxy.Invalidation.Http" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Web.MediaProxy.Invalidation.Script" msgid "Pleroma.Web.MediaProxy.Invalidation.Script" msgstr "Pleroma.Web.MediaProxy.Invalidation.Script" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Web.Metadata" msgid "Pleroma.Web.Metadata" msgstr "Pleroma.Web.Metadata" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Web.Plugs.RemoteIp" msgid "Pleroma.Web.Plugs.RemoteIp" msgstr "Pleroma.Web.Plugs.RemoteIp" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Web.Preload" msgid "Pleroma.Web.Preload" msgstr "Pleroma.Web.Preload" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :pleroma-Pleroma.Workers.PurgeExpiredActivity" msgid "Pleroma.Workers.PurgeExpiredActivity" msgstr "Pleroma.Workers.PurgeExpiredActivity" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config label at :web_push_encryption-:vapid_details" msgid "Vapid Details" -msgstr "Vapid Details" +msgstr "Detale Vapid" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :ex_aws-:s3 > :access_key_id" msgid "S3 access key ID" -msgstr "S3 access key ID" +msgstr "ID klucza dostępu S3" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :ex_aws-:s3 > :host" msgid "S3 host" -msgstr "S3 host" +msgstr "Host S3" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :ex_aws-:s3 > :region" msgid "S3 region (for AWS)" -msgstr "S3 region (for AWS)" +msgstr "Region S3 (dla AWS)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :ex_aws-:s3 > :secret_access_key" msgid "Secret access key" -msgstr "Secret access key" +msgstr "Sekretny klucz dostępu" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :logger > :backends" msgid "Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :ex_syslogger } - to syslog, Quack.Logger - to Slack." msgstr "" -"Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :" -"ex_syslogger } - to syslog, Quack.Logger - to Slack." +"Gdzie będą wysyłane logi, :console - wysyła na standardowe wyjście, { " +"ExSyslogger, :ex_syslogger } - do sysloga, Quack.Logger - na Slack." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :logger-:console > :format" msgid "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" -msgstr "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" +msgstr "Domyślne: \"$date $time [$level] $levelpad$node $metadata $message\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :logger-:console > :level" msgid "Log level" -msgstr "Log level" +msgstr "Poziom logowania" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :logger-:ex_syslogger > :format" msgid "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" -msgstr "Default: \"$date $time [$level] $levelpad$node $metadata $message\"" +msgstr "Domyślne: \"$date $time [$level] $levelpad$node $metadata $message\"" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :logger-:ex_syslogger > :ident" msgid "A string that's prepended to every message, and is typically set to the app name" msgstr "" -"A string that's prepended to every message, and is typically set to the app " -"name" +"Tekst dopisywany do początku każdej wiadomości, i zazwyczaj ustawiany na " +"nazwę apki" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :logger-:ex_syslogger > :level" msgid "Log level" -msgstr "Log level" +msgstr "Poziom logowania" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma > :admin_token" msgid "Admin token" -msgstr "Admin token" +msgstr "Token admina" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:activitypub > :blockers_visible" msgid "Whether a user can see someone who has blocked them" -msgstr "Whether a user can see someone who has blocked them" +msgstr "Czy użytkownik może widzieć, kto go blokuje" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:activitypub > :follow_handshake_timeout" msgid "Following handshake timeout" -msgstr "Following handshake timeout" +msgstr "Limit czasu na hanshake prośby o śledzenie" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:activitypub > :note_replies_output_limit" msgid "The number of Note replies' URIs to be included with outgoing federation (`5` to match Mastodon hardcoded value, `0` to disable the output)" msgstr "" -"The number of Note replies' URIs to be included with outgoing federation (`5`" -" to match Mastodon hardcoded value, `0` to disable the output)" +"Limit URI do odpowiedzi na notatkę zawartych w wychodzącej federacji (`5` by " +"dopasować się do wartości ustawionej na sztywno w Mastodonie, `0` by " +"wyłączyć)" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:activitypub > :outgoing_blocks" msgid "Whether to federate blocks to other instances" -msgstr "Whether to federate blocks to other instances" +msgstr "Czy informować inne instancje o blokadach" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:activitypub > :sign_object_fetches" msgid "Sign object fetches with HTTP signatures" -msgstr "Sign object fetches with HTTP signatures" +msgstr "Podpisuj zapytania o objekty podpisami HTTP" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:activitypub > :unfollow_blocked" msgid "Whether blocks result in people getting unfollowed" -msgstr "Whether blocks result in people getting unfollowed" +msgstr "Czy blokady usuwają śledzenie" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:assets > :default_mascot" msgid "This will be used as the default mascot on MastoFE. Default: `:pleroma_fox_tan`" -msgstr "" -"This will be used as the default mascot on MastoFE. Default: " -"`:pleroma_fox_tan`" +msgstr "Domyślna maskotka na MastoFE. Domyślna: `:pleroma_fox_tan`" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:assets > :default_user_avatar" msgid "URL of the default user avatar" -msgstr "URL of the default user avatar" +msgstr "URL domyślnego avatara nowych użytkowników" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:assets > :mascots" msgid "Keyword of mascots, each element must contain both an URL and a mime_type key" msgstr "" -"Keyword of mascots, each element must contain both an URL and a mime_type key" +"Słowa kluczowe maskotek, każdy element musi zawierać URL i klucz mime_type" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:auth > :auth_template" msgid "Authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`." msgstr "" -"Authentication form template. By default it's `show.html` which corresponds " -"to `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`." +"Szablon formy uwierzytelnienia. Domyślnie jest to `show.html` które " +"odpowiada `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:auth > :enforce_oauth_admin_scope_usage" msgid "OAuth admin scope requirement toggle. If enabled, admin actions explicitly demand admin OAuth scope(s) presence in OAuth token (client app must support admin scopes). If disabled and token doesn't have admin scope(s), `is_admin` user flag grants access to admin-specific actions." msgstr "" -"OAuth admin scope requirement toggle. If enabled, admin actions explicitly " -"demand admin OAuth scope(s) presence in OAuth token (client app must support " -"admin scopes). If disabled and token doesn't have admin scope(s), `is_admin` " -"user flag grants access to admin-specific actions." +"Zakres wymagań zakresu admina OAuth. Jeśli włączone, akcje admina wymagają " +"obecności zakresu admina OAuth w tokenie OAuth (aplikacja kliencka musi " +"wspierać zakresy admina). Jeśli wyłączone i token nie ma zakresów admina, " +"flaga użytkownika`is_admin` daje dostęp do zadań administracyjnych." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:auth > :oauth_consumer_strategies" msgid "The list of enabled OAuth consumer strategies. By default it's set by OAUTH_CONSUMER_STRATEGIES environment variable. Each entry in this space-delimited string should be of format \"strategy\" or \"strategy:dependency\" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is named differently than ueberauth_)." msgstr "" -"The list of enabled OAuth consumer strategies. By default it's set by " -"OAUTH_CONSUMER_STRATEGIES environment variable. Each entry in this space-" -"delimited string should be of format \"strategy\" or \"strategy:dependency\" " -"(e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is " -"named differently than ueberauth_)." +"Lista włączonych strategii konsumenckich OAuth. Domyślnie jest to ustawione " +"przez zmienną środowiskową OAUTH_CONSUMER_STRATEGIES. Każdy fragment tego " +"ciągu znaków oddzielonego spacjamy powinien być formatu \"strategy\" or " +"\"strategy:dependency\" (np. twitter lub keycloak:" +"ueberauth_keycloak_strategy jeśli zależność jest nazwana inaczej niż " +"ueberatuh_)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:auth > :oauth_consumer_template" msgid "OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`." msgstr "" -"OAuth consumer mode authentication form template. By default it's `consumer." -"html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/consumer." -"html.eex`." +"Szablon formularza uwierzytelniania w trybie konsumenckim. Domyślnie jest " +"to`consumer.html` które odpowiada`lib/pleroma/web/templates/o_auth/o_auth/" +"consumer.html.eex`." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:email_notifications > :digest" msgid "emails of \"what you've missed\" for users who have been inactive for a while" msgstr "" -"emails of \"what you've missed\" for users who have been inactive for a while" +"e-mail z \"co przegapiłoś\" dla użytkowników którzy nie logowali się przez " +"jakiś czas" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:email_notifications > :digest > :active" msgid "Globally enable or disable digest emails" -msgstr "Globally enable or disable digest emails" +msgstr "Globalnie włącz lub wyłącz e-maile z podsumowaniem" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:email_notifications > :digest > :inactivity_threshold" msgid "Minimum user inactivity threshold" -msgstr "Minimum user inactivity threshold" +msgstr "Próg minimalnej nieaktywności użytkowników" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:email_notifications > :digest > :interval" msgid "Minimum interval between digest emails to one user" -msgstr "Minimum interval between digest emails to one user" +msgstr "" +"Minimalny okres między e-mailami z podsumowaniami dla jednego użytkownika" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:email_notifications > :digest > :schedule" msgid "When to send digest email, in crontab format. \"0 0 0\" is the default, meaning \"once a week at midnight on Sunday morning\"." msgstr "" -"When to send digest email, in crontab format. \"0 0 0\" is the default, " -"meaning \"once a week at midnight on Sunday morning\"." +"Kiedy wysyłać e-mail z podsumowaniem, w formacie crontaba. Domyślne jest \"0 " +"0 0\", co znaczy \"raz na tydzień, o północy, w niedzielę wieczór\"." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:emoji > :default_manifest" msgid "Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download. Currently only one manifest can be added (no arrays)." msgstr "" -"Location of the JSON-manifest. This manifest contains information about the " -"emoji-packs you can download. Currently only one manifest can be added (no " -"arrays)." +"Położenie manifestu JSON. Ten manifest zawiera informacje o paczkach emoji " +"które możesz ściągnąć. Obecnie można dodać tylko jeden manifest (bez tablic)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:emoji > :groups" msgid "Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the group name and the value is the location or array of locations. * can be used as a wildcard." msgstr "" -"Emojis are ordered in groups (tags). This is an array of key-value pairs " -"where the key is the group name and the value is the location or array of " -"locations. * can be used as a wildcard." +"Emoji są podzielone na grupy (tagi). Jest to tablica par klucz-wartość, " +"gdzie klucz jest nazwą grupy, a wartość jest położeniem lub tablicą położeń. " +"* może być użyte by dopasować dowolny ciąg znaków." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:emoji > :pack_extensions" msgid "A list of file extensions for emojis, when no emoji.txt for a pack is present" -msgstr "" -"A list of file extensions for emojis, when no emoji.txt for a pack is present" +msgstr "Lista rozszerzeń plików emoji, jeśli nie ma emoji.txt dla paczki" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:emoji > :shortcode_globs" msgid "Location of custom emoji files. * can be used as a wildcard." -msgstr "Location of custom emoji files. * can be used as a wildcard." +msgstr "" +"Położenie własnych plików emoji. * może być użyte dla dopasowania dowolnego " +"ciągu znaków." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:features > :improved_hashtag_timeline" msgid "Setting to force toggle / force disable improved hashtags timeline. `:enabled` forces hashtags to be fetched from `hashtags` table for hashtags timeline. `:disabled` forces object-embedded hashtags to be used (slower). Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` [unless overridden] when HashtagsTableMigrator completes)." msgstr "" -"Setting to force toggle / force disable improved hashtags timeline. " -"`:enabled` forces hashtags to be fetched from `hashtags` table for hashtags " -"timeline. `:disabled` forces object-embedded hashtags to be used (slower). " -"Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` [" -"unless overridden] when HashtagsTableMigrator completes)." +"Ustawienie by przełączyć / wymusić wyłączenie poprawionej osi czasów " +"hasztagów. `:enabled` wymusza by hasztagi były pobierane z tabeli `hashtags` " +"dla osi czasu hasztagów. `:disabled` wymusza użycie hasztagów zagnieżdżonych " +"w objektach (wolniejsze). Zostaw jako `:auto` dla zachowania automatycznego (" +"jest automatycznie ustawione na `:enabled` [o ile nie nadpisane] kiedy " +"zakończy pracę HashtagsTableMigrator)." #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:feed > :post_title" msgid "Configure title rendering" -msgstr "Configure title rendering" +msgstr "Konfiguruj wyświetlanie kafli" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:feed > :post_title > :max_length" msgid "Maximum number of characters before truncating title" -msgstr "Maximum number of characters before truncating title" +msgstr "Maksymalna liczba znaków przed skróceniem tytułu" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:feed > :post_title > :omission" msgid "Replacement which will be used after truncating string" -msgstr "Replacement which will be used after truncating string" +msgstr "Czego użyć po skróceniu ciągu znaków" #: lib/pleroma/docs/translator.ex:5 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgctxt "config description at :pleroma-:frontend_configurations > :pleroma_fe" msgid "Settings for Pleroma FE" -msgstr "Settings for Pleroma FE" +msgstr "Ustawienia Pleroma FE" #: lib/pleroma/docs/translator.ex:5 #, elixir-autogen, elixir-format, fuzzy diff --git a/priv/gettext/pl/LC_MESSAGES/posix_errors.po b/priv/gettext/pl/LC_MESSAGES/posix_errors.po index 3fe3a2db9..442b77324 100644 --- a/priv/gettext/pl/LC_MESSAGES/posix_errors.po +++ b/priv/gettext/pl/LC_MESSAGES/posix_errors.po @@ -8,146 +8,154 @@ ### to merge POT files into PO files. msgid "" msgstr "" +"PO-Revision-Date: 2023-10-09 18:53+0000\n" +"Last-Translator: subtype \n" +"Language-Team: Polish \n" "Language: pl\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10||n%100>=20) ? 1 : 2);\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.18.2\n" +"Content-Transfer-Encoding: 8bit\n" msgid "eperm" -msgstr "" +msgstr "Operacja niedozwolona" msgid "eacces" -msgstr "" +msgstr "Brak dostępu" msgid "eagain" -msgstr "" +msgstr "Zasoby chwilowo niedostępne" msgid "ebadf" -msgstr "" +msgstr "Błędny deskryptor pliku" msgid "ebadmsg" -msgstr "" +msgstr "Błędny komunikat" msgid "ebusy" -msgstr "" +msgstr "Urządzenie lub zasoby zajęte" msgid "edeadlk" -msgstr "" +msgstr "Uniknięto zakleszczenia zasobów" msgid "edeadlock" -msgstr "" +msgstr "Uniknięto zakleszczenia zasobów" msgid "edquot" -msgstr "" +msgstr "Przekroczony limit dyskowy" msgid "eexist" -msgstr "" +msgstr "Plik istnieje" msgid "efault" -msgstr "" +msgstr "Błędny adres" msgid "efbig" -msgstr "" +msgstr "Plik zbyt duży" msgid "eftype" -msgstr "" +msgstr "Niewłaściwy typ pliku" msgid "eintr" -msgstr "" +msgstr "Przerwane wywołanie systemowe" msgid "einval" -msgstr "" +msgstr "Zły argument" msgid "eio" -msgstr "" +msgstr "Błąd wejścia/wyjścia" msgid "eisdir" -msgstr "" +msgstr "Jest katalogiem" msgid "eloop" -msgstr "" +msgstr "Za duże zagnieżdżenie dowiązań symbolicznych" msgid "emfile" -msgstr "" +msgstr "Za dużo otwartych plików" msgid "emlink" -msgstr "" +msgstr "Za dużo dowiązań" msgid "emultihop" -msgstr "" +msgstr "Multihop attempted" msgid "enametoolong" -msgstr "" +msgstr "Za długa nazwa pliku" msgid "enfile" -msgstr "" +msgstr "Za dużo otwartych plików w systemie" msgid "enobufs" -msgstr "" +msgstr "Brak miejsca w buforze" msgid "enodev" -msgstr "" +msgstr "Nie ma takiego urządzenia" msgid "enolck" -msgstr "" +msgstr "Brak dostępnych blokad" msgid "enolink" -msgstr "" +msgstr "Połączenie zostało przerwane" msgid "enoent" -msgstr "" +msgstr "Nie ma takiego pliku ani katalogu" msgid "enomem" -msgstr "" +msgstr "Nie można przydzielić pamięci" msgid "enospc" -msgstr "" +msgstr "Brak miejsca na urządzeniu" msgid "enosr" -msgstr "" +msgstr "Brak dodatkowych strumieni" msgid "enostr" -msgstr "" +msgstr "Nie jest strumieniem" msgid "enosys" -msgstr "" +msgstr "Niezaimplementowana funkcja" msgid "enotblk" -msgstr "" +msgstr "Wymagane urządzenie blokowe" msgid "enotdir" -msgstr "" +msgstr "Nie jest katalogiem" msgid "enotsup" -msgstr "" +msgstr "Operacja nieobsługiwana" msgid "enxio" -msgstr "" +msgstr "Nie ma takiego urządzenia ani adresu" msgid "eopnotsupp" -msgstr "" +msgstr "Operacja na gnieździe nieobsługiwana" msgid "eoverflow" -msgstr "" +msgstr "Wartość za duża dla zdefiniowanego typu danych" msgid "epipe" -msgstr "" +msgstr "Przerwany potok" msgid "erange" -msgstr "" +msgstr "Za duży wynik" msgid "erofs" -msgstr "" +msgstr "System plików wyłącznie do odczytu" msgid "espipe" -msgstr "" +msgstr "Błędne przesunięcie" msgid "esrch" -msgstr "" +msgstr "Nie ma takiego procesu" msgid "estale" -msgstr "" +msgstr "Nieaktualny uchwyt pliku" msgid "etxtbsy" -msgstr "" +msgstr "Plik tekstowy zajęty" msgid "exdev" -msgstr "" +msgstr "Niepoprawne dowiązanie" diff --git a/priv/gettext/vi/LC_MESSAGES/errors.po b/priv/gettext/vi/LC_MESSAGES/errors.po index 445a5ae07..8aee75e9f 100644 --- a/priv/gettext/vi/LC_MESSAGES/errors.po +++ b/priv/gettext/vi/LC_MESSAGES/errors.po @@ -3,16 +3,16 @@ 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 \n" -"Language-Team: Vietnamese \n" +"PO-Revision-Date: 2023-09-08 05:53+0000\n" +"Last-Translator: Nguyễn Gia Phong \n" +"Language-Team: Vietnamese \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" +"X-Generator: Weblate 4.18.2\n" ## This file is a PO Template file. ## @@ -577,37 +577,37 @@ msgstr "Người này không phải quản trị viên." #, elixir-format msgid "Last export was less than a day ago" msgid_plural "Last export was less than %{days} days ago" -msgstr[0] "" +msgstr[0] "Vừa sao lưu lần cuối %{days} ngày trước" #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:399 #, elixir-autogen, elixir-format msgid "Character limit (%{limit} characters) exceeded, contains %{length} characters" -msgstr "" +msgstr "Quá dài: %{length} kí tự (tối đa %{limit})" #: lib/pleroma/web/plugs/ensure_staff_privileged_plug.ex:33 #: lib/pleroma/web/plugs/user_is_staff_plug.ex:20 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgid "User is not a staff member." -msgstr "Người này không phải quản trị viên." +msgstr "Người dùng không phải quản trị viên." #: lib/pleroma/web/o_auth/o_auth_controller.ex:391 #, elixir-autogen, elixir-format msgid "Your account is awaiting approval." -msgstr "" +msgstr "Tài khoản của bạn đang chờ được duyệt." #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:256 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:259 #: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:262 #, elixir-autogen, elixir-format msgid "File is too large" -msgstr "" +msgstr "Tệp quá lớn" #: lib/pleroma/web/mastodon_api/controllers/tag_controller.ex:37 #: lib/pleroma/web/mastodon_api/controllers/tag_controller.ex:48 #: lib/pleroma/web/mastodon_api/controllers/tag_controller.ex:59 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgid "Hashtag not found" -msgstr "Không tìm thấy danh sách" +msgstr "Không tìm thấy hashtag" #: lib/pleroma/web/common_api/activity_draft.ex:144 #, elixir-autogen, elixir-format @@ -627,7 +627,7 @@ msgstr "" #: lib/pleroma/web/common_api/activity_draft.ex:126 #, elixir-autogen, elixir-format msgid "You can't quote a status that doesn't exist" -msgstr "" +msgstr "Bạn không thể trích dẫn bàn viết không tồn tại" #: lib/pleroma/web/embed_controller.ex:35 #, elixir-autogen, elixir-format @@ -637,9 +637,9 @@ msgstr "" #: lib/pleroma/web/embed_controller.ex:38 #, elixir-autogen, elixir-format msgid "Not authorized to view this post" -msgstr "" +msgstr "Không có quyền xem bài viết này" #: lib/pleroma/web/embed_controller.ex:32 -#, elixir-autogen, elixir-format, fuzzy +#, elixir-autogen, elixir-format msgid "Post not found" -msgstr "Không tìm thấy danh sách" +msgstr "Không tìm thấy bài viết" diff --git a/priv/repo/migrations/20240210000000_drop_chat_tables.exs b/priv/repo/migrations/20240210000000_drop_chat_tables.exs new file mode 100644 index 000000000..f83524e4d --- /dev/null +++ b/priv/repo/migrations/20240210000000_drop_chat_tables.exs @@ -0,0 +1,50 @@ +defmodule Pleroma.Repo.Migrations.DropChatTables do + use Ecto.Migration + + def up do + # Automatically drops associated indices and constraints + drop table(:chat_message_references) + drop table(:chats) + end + + def down do + # Ecto's default primary key is bigserial, thus configure manually + create table(:chats, primary_key: false) do + add(:id, :uuid, primary_key: true, autogenerated: true) + + add( + :user_id, + references(:users, type: :uuid, on_delete: :delete_all) + # yes, this was nullable + ) + + add( + :recipient, + references(:users, column: :ap_id, type: :string, on_delete: :delete_all) + # yes, this was nullable + ) + + timestamps() + end + + create(index(:chats, [:user_id, :recipient], unique: true)) + + create table(:chat_message_references, primary_key: false) do + add(:id, :uuid, primary_key: true, autogenerated: true) + add(:chat_id, references(:chats, type: :uuid, on_delete: :delete_all), null: false) + add(:object_id, references(:objects, on_delete: :delete_all), null: false) + add(:unread, :boolean, default: true, null: false) + timestamps() + end + + create(index(:chat_message_references, [:chat_id, "id desc"])) + create(unique_index(:chat_message_references, [:object_id, :chat_id])) + + create( + index(:chat_message_references, [:chat_id], + where: "unread = true", + name: "unread_messages_count_index" + ) + ) + end +end diff --git a/priv/repo/migrations/20240213120000_add_permit_followback.exs b/priv/repo/migrations/20240213120000_add_permit_followback.exs new file mode 100644 index 000000000..72475a58e --- /dev/null +++ b/priv/repo/migrations/20240213120000_add_permit_followback.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.AddPermitFollowback do + use Ecto.Migration + + def change do + alter table(:users) do + add(:permit_followback, :boolean, null: false, default: false) + end + end +end diff --git a/priv/repo/optional_migrations/20230422154018_drop_unused_indexes.exs b/priv/repo/optional_migrations/20230422154018_drop_unused_indexes.exs new file mode 100644 index 000000000..d8acb1034 --- /dev/null +++ b/priv/repo/optional_migrations/20230422154018_drop_unused_indexes.exs @@ -0,0 +1,74 @@ +defmodule Pleroma.Repo.Migrations.DropUnusedIndexes do + use Ecto.Migration + + @disable_ddl_transaction true + + @disable_migration_lock true + + def up do + drop_if_exists( + index(:activities, ["(data->>'actor')", "inserted_at desc"], name: :activities_actor_index) + ) + + drop_if_exists(index(:activities, ["(data->'to')"], name: :activities_to_index)) + + drop_if_exists(index(:activities, ["(data->'cc')"], name: :activities_cc_index)) + + drop_if_exists(index(:activities, ["(split_part(actor, '/', 3))"], name: :activities_hosts)) + + drop_if_exists( + index(:activities, ["(data->'object'->>'inReplyTo')"], name: :activities_in_reply_to) + ) + + drop_if_exists( + index(:activities, ["((data #> '{\"object\",\"likes\"}'))"], name: :activities_likes) + ) + end + + def down do + create_if_not_exists( + index(:activities, ["(data->>'actor')", "inserted_at desc"], + name: :activities_actor_index, + concurrently: true + ) + ) + + create_if_not_exists( + index(:activities, ["(data->'to')"], + name: :activities_to_index, + using: :gin, + concurrently: true + ) + ) + + create_if_not_exists( + index(:activities, ["(data->'cc')"], + name: :activities_cc_index, + using: :gin, + concurrently: true + ) + ) + + create_if_not_exists( + index(:activities, ["(split_part(actor, '/', 3))"], + name: :activities_hosts, + concurrently: true + ) + ) + + create_if_not_exists( + index(:activities, ["(data->'object'->>'inReplyTo')"], + name: :activities_in_reply_to, + concurrently: true + ) + ) + + create_if_not_exists( + index(:activities, ["((data #> '{\"object\",\"likes\"}'))"], + name: :activities_likes, + using: :gin, + concurrently: true + ) + ) + end +end diff --git a/priv/repo/optional_migrations/pleroma_develop_rollbacks/20230306112859_instances_add_metadata.exs b/priv/repo/optional_migrations/pleroma_develop_rollbacks/20230306112859_instances_add_metadata.exs new file mode 100644 index 000000000..ab8ac83a0 --- /dev/null +++ b/priv/repo/optional_migrations/pleroma_develop_rollbacks/20230306112859_instances_add_metadata.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.InstancesAddMetadata do + use Ecto.Migration + + def down do + alter table(:instances) do + remove_if_exists(:metadata, :map) + end + end + + def up do + alter table(:instances) do + add_if_not_exists(:metadata, :map) + end + end +end diff --git a/priv/repo/optional_migrations/pleroma_develop_rollbacks/20230504173400_remove_user_ap_enabled.exs b/priv/repo/optional_migrations/pleroma_develop_rollbacks/20230504173400_remove_user_ap_enabled.exs new file mode 100644 index 000000000..f399d9fd7 --- /dev/null +++ b/priv/repo/optional_migrations/pleroma_develop_rollbacks/20230504173400_remove_user_ap_enabled.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.RemoveUserApEnabled do + use Ecto.Migration + + def up do + alter table(:users) do + remove_if_exists(:ap_enabled, :boolean) + end + end + + def down do + alter table(:users) do + add_if_not_exists(:ap_enabled, :boolean, default: true, null: false) + end + end +end diff --git a/priv/scrubbers/default.ex b/priv/scrubbers/default.ex index 37ffaef3a..74de910fd 100644 --- a/priv/scrubbers/default.ex +++ b/priv/scrubbers/default.ex @@ -26,7 +26,9 @@ defmodule Pleroma.HTML.Scrubber.Default do "nofollow", "noopener", "noreferrer", - "ugc" + "ugc", + "tag ugc", + "ugc tag" ]) Meta.allow_tag_with_these_attributes(:a, ["name", "title"]) @@ -126,6 +128,4 @@ defmodule Pleroma.HTML.Scrubber.Default do Meta.allow_tag_with_these_attributes(:small, []) Meta.strip_everything_not_covered() - - defp scrub_css(value), do: value end diff --git a/priv/scrubbers/links_only.ex b/priv/scrubbers/links_only.ex index b30a00589..5ec35c027 100644 --- a/priv/scrubbers/links_only.ex +++ b/priv/scrubbers/links_only.ex @@ -19,7 +19,9 @@ defmodule Pleroma.HTML.Scrubber.LinksOnly do "noopener", "noreferrer", "me", - "ugc" + "ugc", + "tag ugc", + "ugc tag" ]) Meta.allow_tag_with_these_attributes(:a, ["name", "title"]) diff --git a/priv/scrubbers/twitter_text.ex b/priv/scrubbers/twitter_text.ex index c4e796cad..9cb455a27 100644 --- a/priv/scrubbers/twitter_text.ex +++ b/priv/scrubbers/twitter_text.ex @@ -26,7 +26,9 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do "tag", "nofollow", "noopener", - "noreferrer" + "noreferrer", + "tag ugc", + "ugc tag" ]) Meta.allow_tag_with_these_attributes(:a, ["name", "title"]) diff --git a/rel/files/bin/pleroma_ctl b/rel/files/bin/pleroma_ctl index f05e3cd57..42fa06a53 100755 --- a/rel/files/bin/pleroma_ctl +++ b/rel/files/bin/pleroma_ctl @@ -2,21 +2,28 @@ # XXX: This should be removed when elixir's releases get custom command support detect_flavour() { - arch="amd64" - if getconf GNU_LIBC_VERSION >/dev/null; then - libc_postfix="" - elif [ "$(ldd 2>&1 | head -c 9)" = "musl libc" ]; then - libc_postfix="-musl" - elif [ "$(find /lib/libc.musl* | wc -l)" ]; then - libc_postfix="-musl" - else - echo "Unsupported libc" >&2 - exit 1 + machine_type=$(uname -m) + if [ ${machine_type} = 'aarch64' ] ; then + arch='arm64' + elif [ ${machine_type} = 'x86_64' ] ; then + arch='amd64' + if getconf GNU_LIBC_VERSION >/dev/null; then + libc_postfix="" + elif [ "$(ldd 2>&1 | head -c 9)" = "musl libc" ]; then + libc_postfix="-musl" + elif [ "$(find /lib/libc.musl* | wc -l)" ]; then + libc_postfix="-musl" + else + echo "Unsupported libc" >&2 + exit 1 + fi + else + echo "Could not detect your architecture please pass them via --flavour" + exit 1 fi - echo "$arch$libc_postfix" + echo "$arch$libc_postfix" } - detect_branch() { version="$(cut -d' ' -f2 <"$RELEASE_ROOT"/releases/start_erl.data)" # Expected format: major.minor.patch_version(-number_of_commits_ahead_of_tag-gcommit_hash).branch diff --git a/rel/vm.args.eex b/rel/vm.args.eex index 71e803264..6c252186e 100644 --- a/rel/vm.args.eex +++ b/rel/vm.args.eex @@ -9,3 +9,9 @@ ## Tweak GC to run more often ##-env ERL_FULLSWEEP_AFTER 10 + +## Disable busy waits; vastly reduces CPU usage while idle +## See https://docs.akkoma.dev/stable/configuration/optimisation/optimizing_beam/#virtual-machine-andor-few-cpu-cores ++sbwt none ++sbwtdcpu none ++sbwtdio none diff --git a/test/fixtures/xml_normal.xml b/test/fixtures/xml_normal.xml new file mode 100644 index 000000000..8dfa0af54 --- /dev/null +++ b/test/fixtures/xml_normal.xml @@ -0,0 +1,44 @@ + + + + + Match One + + + 1 + Team One + + + 2 + Team Two + + + + + Match Two + + + 2 + Team Two + + + 3 + Team Three + + + + + Match Three + + + 1 + Team One + + + 3 + Team Three + + + + + diff --git a/test/mix/tasks/pleroma/config_test.exs b/test/mix/tasks/pleroma/config_test.exs index 46c109cc1..3b09f656b 100644 --- a/test/mix/tasks/pleroma/config_test.exs +++ b/test/mix/tasks/pleroma/config_test.exs @@ -182,8 +182,81 @@ test "load a settings with large values and pass to file", %{temp_file: temp_fil assert File.exists?(temp_file) {:ok, file} = File.read(temp_file) - assert file == - "import Config\n\nconfig :pleroma, :instance,\n name: \"Pleroma\",\n email: \"example@example.com\",\n notify_email: \"noreply@example.com\",\n description: \"A Pleroma instance, an alternative fediverse server\",\n limit: 5000,\n remote_limit: 100_000,\n upload_limit: 16_000_000,\n avatar_upload_limit: 2_000_000,\n background_upload_limit: 4_000_000,\n banner_upload_limit: 4_000_000,\n poll_limits: %{\n max_expiration: 31_536_000,\n max_option_chars: 200,\n max_options: 20,\n min_expiration: 0\n },\n registrations_open: true,\n federating: true,\n federation_incoming_replies_max_depth: 100,\n federation_reachability_timeout_days: 7,\n federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n allow_relay: true,\n public: true,\n quarantined_instances: [],\n managed_config: true,\n static_dir: \"instance/static/\",\n allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n autofollowed_nicknames: [],\n max_pinned_statuses: 1,\n attachment_links: false,\n max_report_comment_size: 1000,\n safe_dm_mentions: false,\n healthcheck: false,\n remote_post_retention_days: 90,\n skip_thread_containment: true,\n limit_to_local_content: :unauthenticated,\n user_bio_length: 5000,\n user_name_length: 100,\n max_account_fields: 10,\n max_remote_account_fields: 20,\n account_field_name_length: 512,\n account_field_value_length: 2048,\n external_user_synchronization: true,\n extended_nickname_format: true,\n multi_factor_authentication: [\n totp: [digits: 6, period: 30],\n backup_codes: [number: 2, length: 6]\n ]\n" + {:ok, file_quote} = Code.string_to_quoted(file) + + {:__block__, [], + [ + _, + {:config, _, config_quote} + ]} = file_quote + + assert [ + :pleroma, + :instance, + [ + name: "Pleroma", + email: "example@example.com", + notify_email: "noreply@example.com", + description: "A Pleroma instance, an alternative fediverse server", + limit: 5000, + remote_limit: 100_000, + upload_limit: 16_000_000, + avatar_upload_limit: 2_000_000, + background_upload_limit: 4_000_000, + banner_upload_limit: 4_000_000, + poll_limits: {_, _, poll_limits}, + registrations_open: true, + federating: true, + federation_incoming_replies_max_depth: 100, + federation_reachability_timeout_days: 7, + federation_publisher_modules: [ + {_, _, [:Pleroma, :Web, :ActivityPub, :Publisher]} + ], + allow_relay: true, + public: true, + quarantined_instances: [], + managed_config: true, + static_dir: "instance/static/", + allowed_post_formats: ["text/plain", "text/html", "text/markdown", "text/bbcode"], + autofollowed_nicknames: [], + max_pinned_statuses: 1, + attachment_links: false, + max_report_comment_size: 1000, + safe_dm_mentions: false, + healthcheck: false, + remote_post_retention_days: 90, + skip_thread_containment: true, + limit_to_local_content: :unauthenticated, + user_bio_length: 5000, + user_name_length: 100, + max_account_fields: 10, + max_remote_account_fields: 20, + account_field_name_length: 512, + account_field_value_length: 2048, + external_user_synchronization: true, + extended_nickname_format: true, + multi_factor_authentication: [ + {:totp, + [ + digits: 6, + period: 30 + ]}, + {:backup_codes, + [ + number: 2, + length: 6 + ]} + ] + ] + ] = config_quote + + assert Keyword.equal?( + poll_limits, + max_options: 20, + max_option_chars: 200, + min_expiration: 0, + max_expiration: 31_536_000 + ) end end diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs index 40c5fd402..97fa830ff 100644 --- a/test/mix/tasks/pleroma/database_test.exs +++ b/test/mix/tasks/pleroma/database_test.exs @@ -371,8 +371,6 @@ test "We don't have unexpected tables which may contain objects that are referen ["apps"], ["backups"], ["bookmarks"], - ["chat_message_references"], - ["chats"], ["config"], ["conversation_participation_recipient_ships"], ["conversation_participations"], diff --git a/test/pleroma/activity/pruner_test.exs b/test/pleroma/activity/pruner_test.exs index e8d4b30aa..26db60c1c 100644 --- a/test/pleroma/activity/pruner_test.exs +++ b/test/pleroma/activity/pruner_test.exs @@ -6,22 +6,52 @@ defmodule Pleroma.Activity.PrunerTest do import Pleroma.Factory - describe "prune_deletes" do - test "it prunes old delete objects" do + describe "prune_transient_activities" do + test "it prunes old transient activities" do user = insert(:user) + old_time = DateTime.utc_now() |> DateTime.add(-31 * 24, :hour) new_delete = insert(:delete_activity, type: "Delete", user: user) old_delete = insert(:delete_activity, - type: "Delete", user: user, - inserted_at: DateTime.utc_now() |> DateTime.add(-31 * 24, :hour) + inserted_at: old_time ) + new_update = insert(:update_activity, type: "Update", user: user) + + old_update = + insert(:update_activity, + type: "Update", + user: user, + inserted_at: old_time + ) + + new_undo = insert(:undo_activity) + + old_undo = insert(:undo_activity, inserted_at: old_time) + + new_remove = insert(:remove_activity) + + old_remove = insert(:remove_activity, inserted_at: old_time) + Pruner.prune_deletes() + Pruner.prune_updates() + Pruner.prune_undos() + Pruner.prune_removes() + assert Activity.get_by_id(new_delete.id) refute Activity.get_by_id(old_delete.id) + + assert Activity.get_by_id(new_update.id) + refute Activity.get_by_id(old_update.id) + + assert Activity.get_by_id(new_undo.id) + refute Activity.get_by_id(old_undo.id) + + assert Activity.get_by_id(new_remove.id) + refute Activity.get_by_id(old_remove.id) end end diff --git a/test/pleroma/emails/admin_email_test.exs b/test/pleroma/emails/admin_email_test.exs index e65752c23..6b0acf817 100644 --- a/test/pleroma/emails/admin_email_test.exs +++ b/test/pleroma/emails/admin_email_test.exs @@ -7,7 +7,6 @@ defmodule Pleroma.Emails.AdminEmailTest do import Pleroma.Factory alias Pleroma.Emails.AdminEmail - alias Pleroma.Web.Router.Helpers test "build report email" do config = Pleroma.Config.get(:instance) @@ -18,7 +17,7 @@ test "build report email" do res = AdminEmail.report(to_user, reporter, account, [%{name: "Test", id: "12"}], "Test comment") - status_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, "12") + status_url = url(~p[/notice/12]) reporter_url = reporter.ap_id account_url = account.ap_id diff --git a/test/pleroma/emails/user_email_test.exs b/test/pleroma/emails/user_email_test.exs index 564552004..ee76dc45c 100644 --- a/test/pleroma/emails/user_email_test.exs +++ b/test/pleroma/emails/user_email_test.exs @@ -6,8 +6,6 @@ defmodule Pleroma.Emails.UserEmailTest do use Pleroma.DataCase, async: true alias Pleroma.Emails.UserEmail - alias Pleroma.Web.Endpoint - alias Pleroma.Web.Router import Pleroma.Factory @@ -18,7 +16,7 @@ test "build password reset email" do assert email.from == {config[:name], config[:notify_email]} assert email.to == [{user.name, user.email}] assert email.subject == "Password reset" - assert email.html_body =~ Router.Helpers.reset_password_url(Endpoint, :reset, "test_token") + assert email.html_body =~ url(~p"/api/v1/pleroma/password_reset/test_token") end test "build user invitation email" do @@ -30,8 +28,7 @@ test "build user invitation email" do assert email.subject == "Invitation to Akkoma" assert email.to == [{"Jonh", "test@test.com"}] - assert email.html_body =~ - Router.Helpers.redirect_url(Endpoint, :registration_page, token.token) + assert email.html_body =~ url(~p[/registration/#{token.token}]) end test "build account confirmation email" do @@ -42,8 +39,7 @@ test "build account confirmation email" do assert email.to == [{user.name, user.email}] assert email.subject == "#{config[:name]} account confirmation" - assert email.html_body =~ - Router.Helpers.confirm_email_url(Endpoint, :confirm_email, user.id, "conf-token") + assert email.html_body =~ url(~p[/api/account/confirm_email/#{user.id}/conf-token]) end test "build approval pending email" do diff --git a/test/pleroma/healthcheck_test.exs b/test/pleroma/healthcheck_test.exs index 469e5b397..9352840b5 100644 --- a/test/pleroma/healthcheck_test.exs +++ b/test/pleroma/healthcheck_test.exs @@ -6,17 +6,19 @@ defmodule Pleroma.HealthcheckTest do use Pleroma.DataCase, async: true alias Pleroma.Healthcheck + import Pleroma.Test.Matchers.List + test "system_info/0" do result = Healthcheck.system_info() |> Map.from_struct() - assert Map.keys(result) == [ - :active, - :healthy, - :idle, - :job_queue_stats, - :memory_used, - :pool_size - ] + assert_unordered_list_equal(Map.keys(result), [ + :active, + :healthy, + :idle, + :job_queue_stats, + :memory_used, + :pool_size + ]) end describe "check_health/1" do diff --git a/test/pleroma/integration/federation_test.exs b/test/pleroma/integration/federation_test.exs index da433e2c0..e4e37aa9f 100644 --- a/test/pleroma/integration/federation_test.exs +++ b/test/pleroma/integration/federation_test.exs @@ -31,10 +31,9 @@ test "within/2 captures local bindings and executes block on remote node" do test "runs webserver on customized port" do {nickname, url, url_404} = within @federated1 do - import Pleroma.Web.Router.Helpers user = Pleroma.Factory.insert(:user) - user_url = account_url(Pleroma.Web.Endpoint, :show, user) - url_404 = account_url(Pleroma.Web.Endpoint, :show, "not-exists") + user_url = ~p[/api/v1/accounts/#{user}] + url_404 = ~p"/api/v1/accounts/not-exists" {user.nickname, user_url, url_404} end diff --git a/test/pleroma/mfa/totp_test.exs b/test/pleroma/mfa/totp_test.exs index 828993866..b0572ad80 100644 --- a/test/pleroma/mfa/totp_test.exs +++ b/test/pleroma/mfa/totp_test.exs @@ -6,16 +6,19 @@ defmodule Pleroma.MFA.TOTPTest do use Pleroma.DataCase, async: true alias Pleroma.MFA.TOTP + import Pleroma.Test.Matchers.URI test "create provisioning_uri to generate qrcode" do uri = - TOTP.provisioning_uri("test-secrcet", "test@example.com", + TOTP.provisioning_uri("test-secret", "test@example.com", issuer: "Plerome-42", digits: 8, period: 60 ) - assert uri == - "otpauth://totp/test@example.com?digits=8&issuer=Plerome-42&period=60&secret=test-secrcet" + assert_uri_equals( + uri, + "otpauth://totp/test@example.com?digits=8&issuer=Plerome-42&period=60&secret=test-secret" + ) end end diff --git a/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs b/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs index a7d4d493c..073e70705 100644 --- a/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs +++ b/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs @@ -29,13 +29,13 @@ test "change/0 converts auto_linker opts for Pleroma.Formatter", %{migration: mi %{value: new_opts} = ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Formatter}) - assert new_opts == [ + assert Keyword.equal?(new_opts, class: false, extra: true, new_window: false, rel: "testing", strip_prefix: false - ] + ) clear_config(Pleroma.Formatter, new_opts) assert new_opts == Pleroma.Config.get(Pleroma.Formatter) @@ -67,6 +67,6 @@ test "transform_opts/1 returns a list of compatible opts", %{migration: migratio strip_prefix: false ] - assert migration.transform_opts(old_opts) == expected_opts + assert Keyword.equal?(migration.transform_opts(old_opts), expected_opts) end end diff --git a/test/pleroma/repo/migrations/fix_malformed_formatter_config_test.exs b/test/pleroma/repo/migrations/fix_malformed_formatter_config_test.exs index 65c9961b0..9f589882d 100644 --- a/test/pleroma/repo/migrations/fix_malformed_formatter_config_test.exs +++ b/test/pleroma/repo/migrations/fix_malformed_formatter_config_test.exs @@ -26,16 +26,16 @@ test "change/0 converts a map into a list", %{migration: migration} do %{value: new_opts} = ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Formatter}) - assert new_opts == [ + assert Keyword.equal?(new_opts, class: false, extra: true, new_window: false, rel: "F", strip_prefix: false - ] + ) clear_config(Pleroma.Formatter, new_opts) - assert new_opts == Pleroma.Config.get(Pleroma.Formatter) + assert Keyword.equal?(new_opts, Pleroma.Config.get(Pleroma.Formatter)) {text, _mentions, []} = Pleroma.Formatter.linkify( @@ -61,7 +61,7 @@ test "change/0 skips if Pleroma.Formatter config is already a list", %{migration %{value: new_opts} = ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Formatter}) - assert new_opts == opts + assert Keyword.equal?(new_opts, opts) end test "change/0 skips if Pleroma.Formatter is empty", %{migration: migration} do diff --git a/test/pleroma/signature_test.exs b/test/pleroma/signature_test.exs index 1f52484a5..e2d02fe4c 100644 --- a/test/pleroma/signature_test.exs +++ b/test/pleroma/signature_test.exs @@ -71,6 +71,35 @@ test "it returns error when not found user" do end end + defp split_signature(sig) do + sig + |> String.split(",") + |> Enum.map(fn part -> + [key, value] = String.split(part, "=", parts: 2) + [key, String.trim(value, ~s|"|)] + end) + |> Enum.sort_by(fn [k, _] -> k end) + end + + # Break up a signature and check by parts + defp assert_signature_equal(sig_a, sig_b) when is_binary(sig_a) and is_binary(sig_b) do + parts_a = split_signature(sig_a) + parts_b = split_signature(sig_b) + + parts_a + |> Enum.with_index() + |> Enum.each(fn {part_a, index} -> + part_b = Enum.at(parts_b, index) + assert_part_equal(part_a, part_b) + end) + end + + defp assert_part_equal(part_a, part_b) do + if part_a != part_b do + flunk("Signature check failed - expected #{part_a} to equal #{part_b}") + end + end + describe "sign/2" do test "it returns signature headers" do user = @@ -79,14 +108,18 @@ test "it returns signature headers" do keys: @private_key }) - assert Signature.sign( - user, - %{ - host: "test.test", - "content-length": 100 - } - ) == - "keyId=\"https://mastodon.social/users/lambadalambda#main-key\",algorithm=\"rsa-sha256\",headers=\"content-length host\",signature=\"sibUOoqsFfTDerquAkyprxzDjmJm6erYc42W5w1IyyxusWngSinq5ILTjaBxFvfarvc7ci1xAi+5gkBwtshRMWm7S+Uqix24Yg5EYafXRun9P25XVnYBEIH4XQ+wlnnzNIXQkU3PU9e6D8aajDZVp3hPJNeYt1gIPOA81bROI8/glzb1SAwQVGRbqUHHHKcwR8keiR/W2h7BwG3pVRy4JgnIZRSW7fQogKedDg02gzRXwUDFDk0pr2p3q6bUWHUXNV8cZIzlMK+v9NlyFbVYBTHctAR26GIAN6Hz0eV0mAQAePHDY1mXppbA8Gpp6hqaMuYfwifcXmcc+QFm4e+n3A==\"" + headers = %{ + host: "test.test", + "content-length": 100 + } + + assert_signature_equal( + Signature.sign( + user, + headers + ), + "keyId=\"https://mastodon.social/users/lambadalambda#main-key\",algorithm=\"rsa-sha256\",headers=\"content-length host\",signature=\"sibUOoqsFfTDerquAkyprxzDjmJm6erYc42W5w1IyyxusWngSinq5ILTjaBxFvfarvc7ci1xAi+5gkBwtshRMWm7S+Uqix24Yg5EYafXRun9P25XVnYBEIH4XQ+wlnnzNIXQkU3PU9e6D8aajDZVp3hPJNeYt1gIPOA81bROI8/glzb1SAwQVGRbqUHHHKcwR8keiR/W2h7BwG3pVRy4JgnIZRSW7fQogKedDg02gzRXwUDFDk0pr2p3q6bUWHUXNV8cZIzlMK+v9NlyFbVYBTHctAR26GIAN6Hz0eV0mAQAePHDY1mXppbA8Gpp6hqaMuYfwifcXmcc+QFm4e+n3A==\"" + ) end test "it returns error" do diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index c33528a67..5a0d77cab 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -1004,23 +1004,13 @@ test "it doesn't fail on invalid alsoKnownAs entries" do test "returns an ap_id for a user" do user = insert(:user) - assert User.ap_id(user) == - Pleroma.Web.Router.Helpers.user_feed_url( - Pleroma.Web.Endpoint, - :feed_redirect, - user.nickname - ) + assert User.ap_id(user) == url(@endpoint, ~p[/users/#{user.nickname}]) end test "returns an ap_followers link for a user" do user = insert(:user) - assert User.ap_followers(user) == - Pleroma.Web.Router.Helpers.user_feed_url( - Pleroma.Web.Endpoint, - :feed_redirect, - user.nickname - ) <> "/followers" + assert User.ap_followers(user) == url(@endpoint, ~p[/users/#{user.nickname}/followers]) end describe "remote user changeset" do @@ -1363,25 +1353,27 @@ test "does not block domain with same end if wildcard added" do refute User.blocks?(user, collateral_user) end - test "blocks domain with wildcard for subdomain" do - user = insert(:user) - - user_from_subdomain = - insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"}) - - user_with_two_subdomains = - insert(:user, %{ - ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully" - }) - - user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"}) - - {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com") - - assert User.blocks?(user, user_from_subdomain) - assert User.blocks?(user, user_with_two_subdomains) - assert User.blocks?(user, user_domain) - end + # This behaviour is not honoured by the timeline query + # re-add at a later date when UX is established + # test "blocks domain with wildcard for subdomain" do + # user = insert(:user) + # + # user_from_subdomain = + # insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"}) + # + # user_with_two_subdomains = + # insert(:user, %{ + # ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully" + # }) + # + # user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"}) + # + # {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com") + # + # assert User.blocks?(user, user_from_subdomain) + # assert User.blocks?(user, user_with_two_subdomains) + # assert User.blocks?(user, user_domain) + # end test "unblocks domains" do user = insert(:user) diff --git a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs index 4ef0c9302..dcb5f143c 100644 --- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs @@ -39,7 +39,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do test "with the relay active, it returns the relay user", %{conn: conn} do res = conn - |> get(activity_pub_path(conn, :relay)) + |> get(~p"/relay") |> json_response(200) assert res["id"] =~ "/relay" @@ -49,7 +49,7 @@ test "with the relay disabled, it returns 404", %{conn: conn} do clear_config([:instance, :allow_relay], false) conn - |> get(activity_pub_path(conn, :relay)) + |> get(~p"/relay") |> json_response(404) end @@ -59,7 +59,7 @@ test "on non-federating instance, it returns 404", %{conn: conn} do conn |> assign(:user, user) - |> get(activity_pub_path(conn, :relay)) + |> get(~p"/relay") |> json_response(404) end end @@ -68,7 +68,7 @@ test "on non-federating instance, it returns 404", %{conn: conn} do test "it returns the internal fetch user", %{conn: conn} do res = conn - |> get(activity_pub_path(conn, :internal_fetch)) + |> get(~p"/internal/fetch") |> json_response(200) assert res["id"] =~ "/fetch" @@ -80,7 +80,7 @@ test "on non-federating instance, it returns 404", %{conn: conn} do conn |> assign(:user, user) - |> get(activity_pub_path(conn, :internal_fetch)) + |> get(~p"/internal/fetch") |> json_response(404) end end diff --git a/test/pleroma/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs index d4d1c2aac..5d5388cf5 100644 --- a/test/pleroma/web/activity_pub/activity_pub_test.exs +++ b/test/pleroma/web/activity_pub/activity_pub_test.exs @@ -2629,6 +2629,14 @@ test "allow fetching of accounts with an empty string name field" do assert user.name == " " end + test "pin_data_from_featured_collection will ignore unsupported values" do + assert %{} == + ActivityPub.pin_data_from_featured_collection(%{ + "type" => "CollectionThatIsNotRealAndCannotHurtMe", + "first" => "https://social.example/users/alice/collections/featured?page=true" + }) + end + describe "persist/1" do test "should not persist remote delete activities" do poster = insert(:user, local: false) diff --git a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs index 875cf8f43..1ae42036d 100644 --- a/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs @@ -19,6 +19,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do accept: [], avatar_removal: [], banner_removal: [], + background_removal: [], reject_deletes: [] ) @@ -283,7 +284,7 @@ test "obfuscates domains listed in :transparency_obfuscate_domains" do assert {:ok, %{ - mrf_simple: %{reject: ["rem***.*****nce", "a.b"]}, + mrf_simple: %{reject: ["rem***.*****nce", "*.b"]}, mrf_simple_info: %{reject: %{"rem***.*****nce" => %{}}} }} = SimplePolicy.describe() end @@ -618,6 +619,42 @@ test "match with wildcard domain" do end end + describe "when :background_removal" do + test "is empty" do + clear_config([:mrf_simple, :background_removal], []) + + remote_user = build_remote_user() + + assert SimplePolicy.filter(remote_user) == {:ok, remote_user} + end + + test "is not empty but it doesn't have a matching host" do + clear_config([:mrf_simple, :background_removal], [{"non.matching.remote", ""}]) + + remote_user = build_remote_user() + + assert SimplePolicy.filter(remote_user) == {:ok, remote_user} + end + + test "has a matching host" do + clear_config([:mrf_simple, :background_removal], [{"remote.instance", ""}]) + + remote_user = build_remote_user() + {:ok, filtered} = SimplePolicy.filter(remote_user) + + refute filtered["backgroundUrl"] + end + + test "match with wildcard domain" do + clear_config([:mrf_simple, :background_removal], [{"*.remote.instance", ""}]) + + remote_user = build_remote_user() + {:ok, filtered} = SimplePolicy.filter(remote_user) + + refute filtered["backgroundUrl"] + end + end + describe "when :reject_deletes is empty" do setup do: clear_config([:mrf_simple, :reject_deletes], []) @@ -701,6 +738,10 @@ defp build_remote_user do "url" => "http://example.com/image.jpg", "type" => "Image" }, + "backgroundUrl" => %{ + "url" => "http://example.com/background.jpg", + "type" => "Image" + }, "type" => "Person" } end diff --git a/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs b/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs index b0a7e8993..59baa3a43 100644 --- a/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs @@ -60,6 +60,32 @@ test "Steals emoji on unknown shortcode from allowed remote host", %{ |> File.exists?() end + test "rejects invalid shortcodes", %{path: path} do + message = %{ + "type" => "Create", + "object" => %{ + "emoji" => [{"fired/fox", "https://example.org/emoji/firedfox"}], + "actor" => "https://example.org/users/admin" + } + } + + fullpath = Path.join(path, "fired/fox.png") + + Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/firedfox"} -> + %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")} + end) + + clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468) + + refute "firedfox" in installed() + refute File.exists?(path) + + assert {:ok, _message} = StealEmojiPolicy.filter(message) + + refute "fired/fox" in installed() + refute File.exists?(fullpath) + end + test "reject regex shortcode", %{message: message} do refute "firedfox" in installed() diff --git a/test/pleroma/web/activity_pub/side_effects_test.exs b/test/pleroma/web/activity_pub/side_effects_test.exs index 80714b1db..28a591d3c 100644 --- a/test/pleroma/web/activity_pub/side_effects_test.exs +++ b/test/pleroma/web/activity_pub/side_effects_test.exs @@ -155,7 +155,13 @@ test "it blocks but does not unfollow if the relevant setting is set", %{ user = insert(:user, local: false) {:ok, update_data, []} = - Builder.update(user, %{"id" => user.ap_id, "type" => "Person", "name" => "new name!"}) + Builder.update(user, %{ + "id" => user.ap_id, + "type" => "Person", + "name" => "new name!", + "icon" => %{"type" => "Image", "url" => "https://example.org/icon.png"}, + "backgroundUrl" => %{"type" => "Image", "url" => "https://example.org/bg.jxl"} + }) {:ok, update, _meta} = ActivityPub.persist(update_data, local: true) @@ -165,7 +171,10 @@ test "it blocks but does not unfollow if the relevant setting is set", %{ test "it updates the user", %{user: user, update: update} do {:ok, _, _} = SideEffects.handle(update) user = User.get_by_id(user.id) + assert user.name == "new name!" + assert [%{"href" => "https://example.org/icon.png"}] = user.avatar["url"] + assert [%{"href" => "https://example.org/bg.jxl"}] = user.background["url"] end test "it uses a given changeset to update", %{user: user, update: update} do diff --git a/test/pleroma/web/activity_pub/views/user_view_test.exs b/test/pleroma/web/activity_pub/views/user_view_test.exs index 5501e64d6..abe91cdea 100644 --- a/test/pleroma/web/activity_pub/views/user_view_test.exs +++ b/test/pleroma/web/activity_pub/views/user_view_test.exs @@ -58,16 +58,19 @@ test "Does not add an avatar image if the user hasn't set one" do result = UserView.render("user.json", %{user: user}) refute result["icon"] refute result["image"] + refute result["backgroundUrl"] user = insert(:user, avatar: %{"url" => [%{"href" => "https://someurl"}]}, - banner: %{"url" => [%{"href" => "https://somebanner"}]} + banner: %{"url" => [%{"href" => "https://somebanner"}]}, + background: %{"url" => [%{"href" => "https://somebackground"}]} ) result = UserView.render("user.json", %{user: user}) assert result["icon"]["url"] == "https://someurl" assert result["image"]["url"] == "https://somebanner" + assert result["backgroundUrl"]["url"] == "https://somebackground" end test "renders an invisible user with the invisible property set to true" do @@ -76,6 +79,15 @@ test "renders an invisible user with the invisible property set to true" do assert %{"invisible" => true} = UserView.render("service.json", %{user: user}) end + test "service has a few essential fields" do + user = insert(:user) + result = UserView.render("service.json", %{user: user}) + assert result["id"] + assert result["type"] == "Application" + assert result["inbox"] + assert result["outbox"] + end + test "renders AKAs" do akas = ["https://i.tusooa.xyz/users/test-pleroma"] user = insert(:user, also_known_as: akas) diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index e0a2cb9de..68d77ae5a 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -783,7 +783,8 @@ test "it confirms emails of two users", %{conn: conn, admin: admin} do describe "PATCH /resend_confirmation_email" do test "it resend emails for two users", %{conn: conn, admin: admin} do - [first_user, second_user] = insert_pair(:user, is_confirmed: false) + [first_user, second_user] = + insert_pair(:user, is_confirmed: false, confirmation_token: "something") ret_conn = patch(conn, "/api/v1/pleroma/admin/users/resend_confirmation_email", %{ diff --git a/test/pleroma/web/admin_api/controllers/report_controller_test.exs b/test/pleroma/web/admin_api/controllers/report_controller_test.exs index 2ec9ca969..ace71785b 100644 --- a/test/pleroma/web/admin_api/controllers/report_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/report_controller_test.exs @@ -212,7 +212,7 @@ test "updates state of multiple reports", %{ test "returns empty response when no reports created", %{conn: conn} do response = conn - |> get(report_path(conn, :index)) + |> get(~p"/api/v1/pleroma/admin/reports") |> json_response_and_validate_schema(:ok) assert Enum.empty?(response["reports"]) @@ -232,7 +232,7 @@ test "returns reports", %{conn: conn} do response = conn - |> get(report_path(conn, :index)) + |> get(~p"/api/v1/pleroma/admin/reports") |> json_response_and_validate_schema(:ok) [report] = response["reports"] @@ -264,7 +264,7 @@ test "returns reports with specified state", %{conn: conn} do response = conn - |> get(report_path(conn, :index, %{state: "open"})) + |> get(~p[/api/v1/pleroma/admin/reports?#{[state: "open"]}]) |> json_response_and_validate_schema(:ok) assert [open_report] = response["reports"] @@ -276,7 +276,7 @@ test "returns reports with specified state", %{conn: conn} do response = conn - |> get(report_path(conn, :index, %{state: "closed"})) + |> get(~p[/api/v1/pleroma/admin/reports?#{[state: "closed"]}]) |> json_response_and_validate_schema(:ok) assert [closed_report] = response["reports"] @@ -288,7 +288,7 @@ test "returns reports with specified state", %{conn: conn} do assert %{"total" => 0, "reports" => []} == conn - |> get(report_path(conn, :index, %{state: "resolved"})) + |> get(~p[/api/v1/pleroma/admin/reports?#{[state: "resolved"]}]) |> json_response_and_validate_schema(:ok) end diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs index ba6465630..6dcef1a39 100644 --- a/test/pleroma/web/admin_api/controllers/user_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs @@ -685,7 +685,7 @@ test "load users with actor_type is Person", %{admin: admin, conn: conn} do response = conn - |> get(user_path(conn, :index), %{actor_types: ["Person"]}) + |> get(~p"/api/v1/pleroma/admin/users", %{actor_types: ["Person"]}) |> json_response_and_validate_schema(200) users = [ @@ -706,7 +706,7 @@ test "load users with actor_type is Person and Service", %{admin: admin, conn: c response = conn - |> get(user_path(conn, :index), %{actor_types: ["Person", "Service"]}) + |> get(~p"/api/v1/pleroma/admin/users", %{actor_types: ["Person", "Service"]}) |> json_response_and_validate_schema(200) users = [ @@ -727,7 +727,7 @@ test "load users with actor_type is Service", %{conn: conn} do response = conn - |> get(user_path(conn, :index), %{actor_types: ["Service"]}) + |> get(~p"/api/v1/pleroma/admin/users", %{actor_types: ["Service"]}) |> json_response_and_validate_schema(200) users = [user_response(user_service, %{"actor_type" => "Service"})] diff --git a/test/pleroma/web/akkoma_api/frontend_settings_controller_test.exs b/test/pleroma/web/akkoma_api/frontend_settings_controller_test.exs index 07e45d9b9..7b1329593 100644 --- a/test/pleroma/web/akkoma_api/frontend_settings_controller_test.exs +++ b/test/pleroma/web/akkoma_api/frontend_settings_controller_test.exs @@ -119,4 +119,18 @@ test "deletes a config" do ) == nil end end + + describe "PUT /api/v1/akkoma/preferred_frontend" do + test "sets a cookie with selected frontend" do + %{conn: conn} = oauth_access(["read"]) + + response = + conn + |> put_req_header("content-type", "application/json") + |> put("/api/v1/akkoma/preferred_frontend", %{"frontend_name" => "pleroma-fe/stable"}) + + json_response_and_validate_schema(response, 200) + assert %{"preferred_frontend" => %{value: "pleroma-fe/stable"}} = response.resp_cookies + end + end end diff --git a/test/pleroma/web/common_api_test.exs b/test/pleroma/web/common_api_test.exs index f2675ad01..379cf85b8 100644 --- a/test/pleroma/web/common_api_test.exs +++ b/test/pleroma/web/common_api_test.exs @@ -1061,6 +1061,36 @@ test "directly follows a non-locked local user" do assert User.following?(follower, followed) end + + test "directly follows back a locked, but followback-allowing local user" do + uopen = insert(:user, is_locked: false) + uselective = insert(:user, is_locked: true, permit_followback: true) + + assert {:ok, uselective, uopen, %{data: %{"state" => "accept"}}} = + CommonAPI.follow(uselective, uopen) + + assert User.get_follow_state(uselective, uopen) == :follow_accept + + assert {:ok, uopen, uselective, %{data: %{"state" => "accept"}}} = + CommonAPI.follow(uopen, uselective) + + assert User.get_follow_state(uopen, uselective) == :follow_accept + end + + test "creates a pending request for locked, non-followback local user" do + uopen = insert(:user, is_locked: false) + ulocked = insert(:user, is_locked: true, permit_followback: false) + + assert {:ok, ulocked, uopen, %{data: %{"state" => "accept"}}} = + CommonAPI.follow(ulocked, uopen) + + assert User.get_follow_state(ulocked, uopen) == :follow_accept + + assert {:ok, uopen, ulocked, %{data: %{"state" => "pending"}}} = + CommonAPI.follow(uopen, ulocked) + + assert User.get_follow_state(uopen, ulocked) == :follow_pending + end end describe "unfollow/2" do diff --git a/test/pleroma/web/feed/tag_controller_test.exs b/test/pleroma/web/feed/tag_controller_test.exs index fe7940f41..f67d5485d 100644 --- a/test/pleroma/web/feed/tag_controller_test.exs +++ b/test/pleroma/web/feed/tag_controller_test.exs @@ -50,7 +50,7 @@ test "gets a feed (ATOM)", %{conn: conn} do response = conn |> put_req_header("accept", "application/atom+xml") - |> get(tag_feed_path(conn, :feed, "pleromaart.atom")) + |> get(~p"/tags/pleromaart.atom") |> response(200) xml = parse(response) @@ -117,7 +117,7 @@ test "gets a feed (RSS)", %{conn: conn} do response = conn |> put_req_header("accept", "application/rss+xml") - |> get(tag_feed_path(conn, :feed, "pleromaart.rss")) + |> get(~p"/tags/pleromaart.rss") |> response(200) xml = parse(response) @@ -157,7 +157,7 @@ test "gets a feed (RSS)", %{conn: conn} do response = conn |> put_req_header("accept", "application/rss+xml") - |> get(tag_feed_path(conn, :feed, "pleromaart.rss")) + |> get(~p"/tags/pleromaart.rss") |> response(200) xml = parse(response) @@ -188,7 +188,7 @@ test "gets a feed (RSS)", %{conn: conn} do test "returns 404 for tags feed", %{conn: conn} do conn |> put_req_header("accept", "application/rss+xml") - |> get(tag_feed_path(conn, :feed, "pleromaart.rss")) + |> get(~p"/tags/pleromaart.rss") |> response(404) end end diff --git a/test/pleroma/web/feed/user_controller_test.exs b/test/pleroma/web/feed/user_controller_test.exs index 245ffcf0a..d5d9faf06 100644 --- a/test/pleroma/web/feed/user_controller_test.exs +++ b/test/pleroma/web/feed/user_controller_test.exs @@ -66,7 +66,7 @@ test "gets an atom feed", %{conn: conn, user: user, object: object, max_id: max_ resp = conn |> put_req_header("accept", "application/atom+xml") - |> get(user_feed_path(conn, :feed, user.nickname)) + |> get(~p[/users/#{user.nickname}/feed]) |> response(200) activity_titles = @@ -128,7 +128,7 @@ test "returns 404 for a missing feed", %{conn: conn} do conn = conn |> put_req_header("accept", "application/atom+xml") - |> get(user_feed_path(conn, :feed, "nonexisting")) + |> get(~p"/users/nonexisting/feed") assert response(conn, 404) end @@ -144,7 +144,7 @@ test "returns feed with public and unlisted activities", %{conn: conn} do resp = conn |> put_req_header("accept", "application/atom+xml") - |> get(user_feed_path(conn, :feed, user.nickname)) + |> get(~p[/users/#{user.nickname}/feed]) |> response(200) activity_titles = @@ -163,7 +163,7 @@ test "returns 404 when the user is remote", %{conn: conn} do assert conn |> put_req_header("accept", "application/atom+xml") - |> get(user_feed_path(conn, :feed, user.nickname)) + |> get(~p[/users/#{user.nickname}/feed]) |> response(404) end @@ -240,7 +240,7 @@ test "with non-html / non-json format, it returns error when user is not found", response = conn |> put_req_header("accept", "application/xml") - |> get(user_feed_path(conn, :feed, "jimm")) + |> get(~p"/users/jimm/feed") |> response(404) assert response == ~S({"error":"Not found"}) @@ -258,7 +258,7 @@ test "returns 404 for user feed", %{conn: conn} do assert conn |> put_req_header("accept", "application/atom+xml") - |> get(user_feed_path(conn, :feed, user.nickname)) + |> get(~p[/users/#{user.nickname}/feed]) |> response(404) end end diff --git a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs index 6ca9cfc50..ede14030b 100644 --- a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs @@ -2060,4 +2060,32 @@ test "removing user from followers errors", %{user: user, conn: conn} do assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404) end end + + describe "preferences" do + test "get account preferences" do + user = insert(:user, default_scope: "public") + %{conn: conn} = oauth_access(["read:accounts"], user: user) + + conn = get(conn, "/api/v1/preferences") + response = json_response_and_validate_schema(conn, 200) + + assert %{ + "posting:default:language" => nil, + "posting:default:sensitive" => false, + "posting:default:visibility" => "public", + "reading:expand:media" => "default", + "reading:expand:spoilers" => false + } = response + end + + test "test changing account preferences" do + user = insert(:user, default_scope: "unlisted") + %{conn: conn} = oauth_access(["read:accounts"], user: user) + + conn = get(conn, "/api/v1/preferences") + response = json_response_and_validate_schema(conn, 200) + + assert response["posting:default:visibility"] == "unlisted" + end + end end diff --git a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs index bd3735925..25a18e145 100644 --- a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs @@ -1883,7 +1883,7 @@ test "favorites paginate correctly" do # Using the header for pagination works correctly [next, _] = get_resp_header(result, "link") |> hd() |> String.split(", ") - [_, max_id] = Regex.run(~r/max_id=([^&]+)/, next) + [_, max_id] = Regex.run(~r/max_id=([^&>]+)/, next) assert max_id == third_favorite.id diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs index a347c7987..92a5726bf 100644 --- a/test/pleroma/web/mastodon_api/update_credentials_test.exs +++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs @@ -91,7 +91,7 @@ test "updates the user's bio", %{conn: conn} do assert user_data = json_response_and_validate_schema(conn, 200) assert user_data["note"] == - ~s(I drink #cofe with @#{user2.nickname}

    suya..) + ~s(I drink #cofe with @#{user2.nickname}

    suya..) assert user_data["source"]["note"] == raw_bio @@ -529,7 +529,7 @@ test "update fields with a link to content with rel=me, with frontend path", %{ user: user, conn: conn } do - fe_url = "#{Pleroma.Web.Endpoint.url()}/#{user.nickname}" + fe_url = url(~p[/#{user.nickname}]) Tesla.Mock.mock(fn %{url: "http://example.com/rel_me/fe_path"} -> diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index 5b8aea8ac..d017b87c8 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -40,7 +40,8 @@ test "Represent a user account" do emoji: %{"karjalanpiirakka" => "/file.png"}, raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"", also_known_as: ["https://shitposter.zone/users/shp"], - status_ttl_days: 5 + status_ttl_days: 5, + last_status_at: ~N[2023-12-31T15:06:17] }) insert(:instance, %{host: "example.com", nodeinfo: %{version: "2.1"}}) @@ -65,7 +66,8 @@ test "Represent a user account" do }, favicon: nil }, - status_ttl_days: 5 + status_ttl_days: 5, + permit_followback: false }, avatar: "http://localhost:4001/images/avi.png", avatar_static: "http://localhost:4001/images/avi.png", @@ -91,7 +93,7 @@ test "Represent a user account" do fields: [] }, fqn: "shp@shitposter.club", - last_status_at: nil, + last_status_at: ~D[2023-12-31], pleroma: %{ ap_id: user.ap_id, also_known_as: ["https://shitposter.zone/users/shp"], @@ -248,7 +250,8 @@ test "Represent a Service(bot) account" do favicon: "http://localhost:4001/favicon.png", nodeinfo: %{version: "2.0"} }, - status_ttl_days: nil + status_ttl_days: nil, + permit_followback: false }, pleroma: %{ ap_id: user.ap_id, diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs index 682c633f4..22f65a0d1 100644 --- a/test/pleroma/web/mastodon_api/views/status_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs @@ -258,7 +258,7 @@ test "a note activity" do expected = %{ id: to_string(note.id), uri: object_data["id"], - url: Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, note), + url: url(~p[/notice/#{note}]), account: AccountView.render("show.json", %{user: user, skip_visibility_check: true}), in_reply_to_id: nil, in_reply_to_account_id: nil, diff --git a/test/pleroma/web/metadata/providers/twitter_card_test.exs b/test/pleroma/web/metadata/providers/twitter_card_test.exs index 731447094..cd3f5eced 100644 --- a/test/pleroma/web/metadata/providers/twitter_card_test.exs +++ b/test/pleroma/web/metadata/providers/twitter_card_test.exs @@ -12,7 +12,6 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do alias Pleroma.Web.MediaProxy alias Pleroma.Web.Metadata.Providers.TwitterCard alias Pleroma.Web.Metadata.Utils - alias Pleroma.Web.Router setup do: clear_config([Pleroma.Web.Metadata, :unfurl_nsfw]) @@ -189,7 +188,7 @@ test "it renders supported types of attachments and skips unknown types" do {:meta, [ name: "twitter:player", - content: Router.Helpers.o_status_url(Endpoint, :notice_player, activity.id) + content: url(Endpoint, ~p[/notice/#{activity.id}/embed_player]) ], []}, {:meta, [name: "twitter:player:width", content: "800"], []}, {:meta, [name: "twitter:player:height", content: "600"], []}, diff --git a/test/pleroma/web/mongoose_im_controller_test.exs b/test/pleroma/web/mongoose_im_controller_test.exs index bda7c613f..cf7db6d93 100644 --- a/test/pleroma/web/mongoose_im_controller_test.exs +++ b/test/pleroma/web/mongoose_im_controller_test.exs @@ -13,28 +13,28 @@ test "/user_exists", %{conn: conn} do res = conn - |> get(mongoose_im_path(conn, :user_exists), user: "lain") + |> get(~p"/user_exists", user: "lain") |> json_response(200) assert res == true res = conn - |> get(mongoose_im_path(conn, :user_exists), user: "alice") + |> get(~p"/user_exists", user: "alice") |> json_response(404) assert res == false res = conn - |> get(mongoose_im_path(conn, :user_exists), user: "bob") + |> get(~p"/user_exists", user: "bob") |> json_response(404) assert res == false res = conn - |> get(mongoose_im_path(conn, :user_exists), user: "konata") + |> get(~p"/user_exists", user: "konata") |> json_response(404) assert res == false @@ -52,28 +52,28 @@ test "/check_password", %{conn: conn} do res = conn - |> get(mongoose_im_path(conn, :check_password), user: user.nickname, pass: "cool") + |> get(~p"/check_password", user: user.nickname, pass: "cool") |> json_response(200) assert res == true res = conn - |> get(mongoose_im_path(conn, :check_password), user: user.nickname, pass: "uncool") + |> get(~p"/check_password", user: user.nickname, pass: "uncool") |> json_response(403) assert res == false res = conn - |> get(mongoose_im_path(conn, :check_password), user: "konata", pass: "cool") + |> get(~p"/check_password", user: "konata", pass: "cool") |> json_response(404) assert res == false res = conn - |> get(mongoose_im_path(conn, :check_password), user: "nobody", pass: "cool") + |> get(~p"/check_password", user: "nobody", pass: "cool") |> json_response(404) assert res == false diff --git a/test/pleroma/web/o_auth/o_auth_controller_test.exs b/test/pleroma/web/o_auth/o_auth_controller_test.exs index 3748940fd..d0703f44c 100644 --- a/test/pleroma/web/o_auth/o_auth_controller_test.exs +++ b/test/pleroma/web/o_auth/o_auth_controller_test.exs @@ -57,7 +57,7 @@ test "GET /oauth/authorize renders auth forms, including OAuth consumer form", % assert response = html_response(conn, 200) assert response =~ "Sign in with Twitter" - assert response =~ o_auth_path(conn, :prepare_request) + assert response =~ ~p"/prepare_request" end test "GET /oauth/prepare_request encodes parameters as `state` and redirects", %{ @@ -81,9 +81,7 @@ test "GET /oauth/prepare_request encodes parameters as `state` and redirects", % assert html_response(conn, 302) - redirect_query = URI.parse(redirected_to(conn)).query - assert %{"state" => state_param} = URI.decode_query(redirect_query) - assert {:ok, state_components} = Jason.decode(state_param) + assert {:ok, state_components} = Jason.decode(conn.resp_cookies["akkoma_oauth_state"].value) expected_client_id = app.client_id expected_redirect_uri = app.redirect_uris @@ -97,7 +95,7 @@ test "GET /oauth/prepare_request encodes parameters as `state` and redirects", % end test "with user-bound registration, GET /oauth//callback redirects to `redirect_uri` with `code`", - %{app: app, conn: conn} do + %{app: app, conn: _} do registration = insert(:registration) redirect_uri = OAuthController.default_redirect_uri(app) @@ -109,15 +107,17 @@ test "with user-bound registration, GET /oauth//callback redirects to } conn = - conn + build_conn() + |> put_req_cookie("akkoma_oauth_state", Jason.encode!(state_params)) + |> Plug.Session.call(Plug.Session.init(@session_opts)) + |> fetch_session() |> assign(:ueberauth_auth, %{provider: registration.provider, uid: registration.uid}) |> get( "/oauth/twitter/callback", %{ "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", - "provider" => "twitter", - "state" => Jason.encode!(state_params) + "provider" => "twitter" } ) @@ -162,15 +162,42 @@ test "with user-unbound registration, GET /oauth//callback renders reg test "on authentication error, GET /oauth//callback redirects to `redirect_uri`", %{ app: app, - conn: conn + conn: _ } do state_params = %{ "scope" => Enum.join(app.scopes, " "), "client_id" => app.client_id, - "redirect_uri" => OAuthController.default_redirect_uri(app), - "state" => "" + "redirect_uri" => OAuthController.default_redirect_uri(app) } + conn = + build_conn() + |> put_req_cookie("akkoma_oauth_state", Jason.encode!(state_params)) + |> Plug.Session.call(Plug.Session.init(@session_opts)) + |> fetch_session() + |> assign(:ueberauth_failure, %{errors: [%{message: "(error description)"}]}) + |> get( + "/oauth/twitter/callback", + %{ + "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", + "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", + "provider" => "twitter", + "state" => "" + } + ) + + assert html_response(conn, 302) + assert redirected_to(conn) == app.redirect_uris + + assert Phoenix.Flash.get(conn.assigns.flash, :error) == + "Failed to authenticate: (error description)." + end + + test "on authentication error with no prior state, GET /oauth//callback returns 400", + %{ + app: _, + conn: conn + } do conn = conn |> assign(:ueberauth_failure, %{errors: [%{message: "(error description)"}]}) @@ -180,13 +207,11 @@ test "on authentication error, GET /oauth//callback redirects to `redi "oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM", "oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs", "provider" => "twitter", - "state" => Jason.encode!(state_params) + "state" => "" } ) - assert html_response(conn, 302) - assert redirected_to(conn) == app.redirect_uris - assert get_flash(conn, :error) == "Failed to authenticate: (error description)." + assert response(conn, 400) end test "GET /oauth/registration_details renders registration details form", %{ @@ -307,7 +332,9 @@ test "with invalid params, POST /oauth/register?op=register renders registration |> post("/oauth/register", bad_params) assert html_response(conn, 403) =~ ~r/name="op" type="submit" value="register"/ - assert get_flash(conn, :error) == "Error: #{bad_param} has already been taken." + + assert Phoenix.Flash.get(conn.assigns.flash, :error) == + "Error: #{bad_param} has already been taken." end end @@ -398,7 +425,7 @@ test "with invalid params, POST /oauth/register?op=connect renders registration_ |> post("/oauth/register", params) assert html_response(conn, 401) =~ ~r/name="op" type="submit" value="connect"/ - assert get_flash(conn, :error) == "Invalid Username/Password" + assert Phoenix.Flash.get(conn.assigns.flash, :error) == "Invalid Username/Password" end end diff --git a/test/pleroma/web/static_fe/static_fe_controller_test.exs b/test/pleroma/web/static_fe/static_fe_controller_test.exs index 935e44171..79d4d6261 100644 --- a/test/pleroma/web/static_fe/static_fe_controller_test.exs +++ b/test/pleroma/web/static_fe/static_fe_controller_test.exs @@ -19,9 +19,26 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do setup %{conn: conn} do conn = put_req_header(conn, "accept", "text/html") - user = insert(:user) - %{conn: conn, user: user} + user_avatar_url = "https://example.org/akko.png" + + user = + insert(:user, + local: true, + name: "Akko", + nickname: "atsuko", + bio: "A believing heart is my magic!", + raw_bio: "A believing heart is my magic!", + avatar: %{ + "url" => [ + %{ + "href" => user_avatar_url + } + ] + } + ) + + %{conn: conn, user: user, user_avatar_url: user_avatar_url} end describe "user profile html" do @@ -291,4 +308,142 @@ test "returns 404 for local public activity with `restrict_unauthenticated/activ |> html_response(404) end end + + defp meta_content(metadata_tag) do + :proplists.get_value("content", metadata_tag) + end + + defp meta_find_og(document, name) do + Floki.find(document, "head>meta[property=\"og:" <> name <> "\"]") + end + + defp meta_find_twitter(document, name) do + Floki.find(document, "head>meta[name=\"twitter:" <> name <> "\"]") + end + + # Detailed metadata tests are already done for each builder individually, so just + # one check per type of content should suffice to ensure we're calling the providers correctly + describe "metadata tags for" do + setup do + clear_config([Pleroma.Web.Metadata, :providers], [ + Pleroma.Web.Metadata.Providers.OpenGraph, + Pleroma.Web.Metadata.Providers.TwitterCard + ]) + end + + test "user profile", %{conn: conn, user: user, user_avatar_url: user_avatar_url} do + conn = get(conn, "/users/#{user.nickname}") + html = html_response(conn, 200) + + {:ok, document} = Floki.parse_document(html) + + [{"meta", og_type, _}] = meta_find_og(document, "type") + [{"meta", og_title, _}] = meta_find_og(document, "title") + [{"meta", og_url, _}] = meta_find_og(document, "url") + [{"meta", og_desc, _}] = meta_find_og(document, "description") + [{"meta", og_img, _}] = meta_find_og(document, "image") + [{"meta", og_imgw, _}] = meta_find_og(document, "image:width") + [{"meta", og_imgh, _}] = meta_find_og(document, "image:height") + + [{"meta", tw_card, _}] = meta_find_twitter(document, "card") + [{"meta", tw_title, _}] = meta_find_twitter(document, "title") + [{"meta", tw_desc, _}] = meta_find_twitter(document, "description") + [{"meta", tw_img, _}] = meta_find_twitter(document, "image") + + assert meta_content(og_type) == "article" + assert meta_content(og_title) == Pleroma.Web.Metadata.Utils.user_name_string(user) + assert meta_content(og_url) == user.ap_id + assert meta_content(og_desc) == user.bio + assert meta_content(og_img) == user_avatar_url + assert meta_content(og_imgw) == "150" + assert meta_content(og_imgh) == "150" + + assert meta_content(tw_card) == "summary" + assert meta_content(tw_title) == meta_content(og_title) + assert meta_content(tw_desc) == meta_content(og_desc) + assert meta_content(tw_img) == meta_content(og_img) + end + + test "text-only post", %{conn: conn, user: user, user_avatar_url: user_avatar_url} do + post_text = "How are lessons about magic t h i s boring?!" + {:ok, activity} = CommonAPI.post(user, %{status: post_text}) + + conn = get(conn, "/notice/#{activity.id}") + html = html_response(conn, 200) + + {:ok, document} = Floki.parse_document(html) + + [{"meta", og_type, _}] = meta_find_og(document, "type") + [{"meta", og_title, _}] = meta_find_og(document, "title") + [{"meta", og_url, _}] = meta_find_og(document, "url") + [{"meta", og_desc, _}] = meta_find_og(document, "description") + [{"meta", og_img, _}] = meta_find_og(document, "image") + [{"meta", og_imgw, _}] = meta_find_og(document, "image:width") + [{"meta", og_imgh, _}] = meta_find_og(document, "image:height") + + [{"meta", tw_card, _}] = meta_find_twitter(document, "card") + [{"meta", tw_title, _}] = meta_find_twitter(document, "title") + [{"meta", tw_desc, _}] = meta_find_twitter(document, "description") + [{"meta", tw_img, _}] = meta_find_twitter(document, "image") + + assert meta_content(og_type) == "article" + assert meta_content(og_title) == Pleroma.Web.Metadata.Utils.user_name_string(user) + assert meta_content(og_url) == activity.data["id"] + assert meta_content(og_desc) == post_text + assert meta_content(og_img) == user_avatar_url + assert meta_content(og_imgw) == "150" + assert meta_content(og_imgh) == "150" + + assert meta_content(tw_card) == "summary" + assert meta_content(tw_title) == meta_content(og_title) + assert meta_content(tw_desc) == meta_content(og_desc) + assert meta_content(tw_img) == meta_content(og_img) + end + + test "post with attachments", %{conn: conn, user: user} do + file = %Plug.Upload{ + content_type: "image/jpeg", + path: Path.absname("test/fixtures/image.jpg"), + filename: "an_image.jpg" + } + + alt_text = "The rarest of all Shiny Chariot cards" + {:ok, upload_data} = ActivityPub.upload(file, actor: user.ap_id, description: alt_text) + + %{id: media_id, data: %{"url" => [%{"href" => media_url}]}} = upload_data + + post_text = "Look!" + {:ok, activity} = CommonAPI.post(user, %{status: post_text, media_ids: [media_id]}) + + conn = get(conn, "/notice/#{activity.id}") + html = html_response(conn, 200) + + {:ok, document} = Floki.parse_document(html) + + [{"meta", og_type, _}] = meta_find_og(document, "type") + [{"meta", og_title, _}] = meta_find_og(document, "title") + [{"meta", og_url, _}] = meta_find_og(document, "url") + [{"meta", og_desc, _}] = meta_find_og(document, "description") + [{"meta", og_img, _}] = meta_find_og(document, "image") + [{"meta", og_alt, _}] = meta_find_og(document, "image:alt") + + [{"meta", tw_card, _}] = meta_find_twitter(document, "card") + [{"meta", tw_title, _}] = meta_find_twitter(document, "title") + [{"meta", tw_desc, _}] = meta_find_twitter(document, "description") + [{"meta", tw_player, _}] = meta_find_twitter(document, "player") + + assert meta_content(og_type) == "article" + assert meta_content(og_title) == Pleroma.Web.Metadata.Utils.user_name_string(user) + assert meta_content(og_url) == activity.data["id"] + assert meta_content(og_desc) == post_text + assert meta_content(og_img) == media_url + assert meta_content(og_alt) == alt_text + + # Audio and video attachments use "player" and have some more metadata + assert meta_content(tw_card) == "summary_large_image" + assert meta_content(tw_title) == meta_content(og_title) + assert meta_content(tw_desc) == meta_content(og_desc) + assert meta_content(tw_player) == meta_content(og_img) + end + end end diff --git a/test/pleroma/web/twitter_api/remote_follow_controller_test.exs b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs index dc300296c..d2bc7840f 100644 --- a/test/pleroma/web/twitter_api/remote_follow_controller_test.exs +++ b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs @@ -48,9 +48,7 @@ test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} assert conn |> get( - remote_follow_path(conn, :follow, %{ - acct: "https://mastodon.social/users/emelie/statuses/101849165031453009" - }) + ~p[/ostatus_subscribe?#{[acct: "https://mastodon.social/users/emelie/statuses/101849165031453009"]}] ) |> redirected_to() =~ "/notice/" end @@ -77,7 +75,7 @@ test "show follow account page if the `acct` is a account link", %{conn: conn} d response = conn - |> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"})) + |> get(~p[/ostatus_subscribe?#{[acct: "https://mastodon.social/users/emelie"]}]) |> html_response(200) assert response =~ "Log in to follow" @@ -108,7 +106,7 @@ test "show follow page if the `acct` is a account link", %{conn: conn} do response = conn |> assign(:user, user) - |> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"})) + |> get(~p[/ostatus_subscribe?#{[acct: "https://mastodon.social/users/emelie"]}]) |> html_response(200) assert response =~ "Remote follow" @@ -129,9 +127,7 @@ test "show follow page with error when user can not be fetched by `acct` link", conn |> assign(:user, user) |> get( - remote_follow_path(conn, :follow, %{ - acct: "https://mastodon.social/users/not_found" - }) + ~p[/ostatus_subscribe?#{[acct: "https://mastodon.social/users/not_found"]}] ) |> html_response(200) @@ -151,7 +147,7 @@ test "required `follow | write:follows` scope", %{conn: conn} do conn |> assign(:user, user) |> assign(:token, read_token) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) + |> post(~p"/ostatus_subscribe", %{"user" => %{"id" => user2.id}}) |> response(200) assert response =~ "Error following account" @@ -166,7 +162,7 @@ test "follows user", %{conn: conn} do conn |> assign(:user, user) |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"])) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) + |> post(~p"/ostatus_subscribe", %{"user" => %{"id" => user2.id}}) assert redirected_to(conn) == "/users/#{user2.id}" end @@ -178,7 +174,7 @@ test "returns error when user is deactivated", %{conn: conn} do response = conn |> assign(:user, user) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) + |> post(~p"/ostatus_subscribe", %{"user" => %{"id" => user2.id}}) |> response(200) assert response =~ "Error following account" @@ -194,7 +190,7 @@ test "returns error when user is blocked", %{conn: conn} do response = conn |> assign(:user, user) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) + |> post(~p"/ostatus_subscribe", %{"user" => %{"id" => user2.id}}) |> response(200) assert response =~ "Error following account" @@ -206,7 +202,7 @@ test "returns error when followee not found", %{conn: conn} do response = conn |> assign(:user, user) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => "jimm"}}) + |> post(~p"/ostatus_subscribe", %{"user" => %{"id" => "jimm"}}) |> response(200) assert response =~ "Error following account" @@ -221,7 +217,7 @@ test "returns success result when user already in followers", %{conn: conn} do conn |> assign(:user, refresh_record(user)) |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"])) - |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) + |> post(~p"/ostatus_subscribe", %{"user" => %{"id" => user2.id}}) assert redirected_to(conn) == "/users/#{user2.id}" end @@ -243,7 +239,7 @@ test "render the MFA login form", %{conn: conn} do response = conn - |> post(remote_follow_path(conn, :do_follow), %{ + |> post(~p"/ostatus_subscribe", %{ "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} }) |> response(200) @@ -271,7 +267,7 @@ test "returns error when password is incorrect", %{conn: conn} do response = conn - |> post(remote_follow_path(conn, :do_follow), %{ + |> post(~p"/ostatus_subscribe", %{ "authorization" => %{"name" => user.nickname, "password" => "test1", "id" => user2.id} }) |> response(200) @@ -299,7 +295,7 @@ test "follows", %{conn: conn} do conn = conn |> post( - remote_follow_path(conn, :do_follow), + ~p"/ostatus_subscribe", %{ "mfa" => %{"code" => otp_token, "token" => token, "id" => user2.id} } @@ -328,7 +324,7 @@ test "returns error when auth code is incorrect", %{conn: conn} do response = conn |> post( - remote_follow_path(conn, :do_follow), + ~p"/ostatus_subscribe", %{ "mfa" => %{"code" => otp_token, "token" => token, "id" => user2.id} } @@ -347,7 +343,7 @@ test "follows", %{conn: conn} do conn = conn - |> post(remote_follow_path(conn, :do_follow), %{ + |> post(~p"/ostatus_subscribe", %{ "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} }) @@ -360,7 +356,7 @@ test "returns error when followee not found", %{conn: conn} do response = conn - |> post(remote_follow_path(conn, :do_follow), %{ + |> post(~p"/ostatus_subscribe", %{ "authorization" => %{"name" => user.nickname, "password" => "test", "id" => "jimm"} }) |> response(200) @@ -373,7 +369,7 @@ test "returns error when login invalid", %{conn: conn} do response = conn - |> post(remote_follow_path(conn, :do_follow), %{ + |> post(~p"/ostatus_subscribe", %{ "authorization" => %{"name" => "jimm", "password" => "test", "id" => user.id} }) |> response(200) @@ -387,7 +383,7 @@ test "returns error when password invalid", %{conn: conn} do response = conn - |> post(remote_follow_path(conn, :do_follow), %{ + |> post(~p"/ostatus_subscribe", %{ "authorization" => %{"name" => user.nickname, "password" => "42", "id" => user2.id} }) |> response(200) @@ -403,7 +399,7 @@ test "returns error when user is blocked", %{conn: conn} do response = conn - |> post(remote_follow_path(conn, :do_follow), %{ + |> post(~p"/ostatus_subscribe", %{ "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} }) |> response(200) diff --git a/test/pleroma/web/uploader_controller_test.exs b/test/pleroma/web/uploader_controller_test.exs index 032895e71..e11a7367f 100644 --- a/test/pleroma/web/uploader_controller_test.exs +++ b/test/pleroma/web/uploader_controller_test.exs @@ -10,7 +10,7 @@ defmodule Pleroma.Web.UploaderControllerTest do test "it returns 400 response when process callback isn't alive", %{conn: conn} do res = conn - |> post(uploader_path(conn, :callback, "test-path")) + |> post(~p"/api/v1/pleroma/uploader_callback/test-path") assert res.status == 400 assert res.resp_body == "{\"error\":\"bad request\"}" @@ -34,7 +34,7 @@ test "it returns success result", %{conn: conn} do res = conn - |> post(uploader_path(conn, :callback, "test-path")) + |> post(~p"/api/v1/pleroma/uploader_callback/test-path") |> json_response(200) assert res == %{"upload_path" => "test-path"} diff --git a/test/pleroma/web/web_finger/web_finger_controller_test.exs b/test/pleroma/web/web_finger/web_finger_controller_test.exs index 6b5b7c46c..fe8301fa4 100644 --- a/test/pleroma/web/web_finger/web_finger_controller_test.exs +++ b/test/pleroma/web/web_finger/web_finger_controller_test.exs @@ -8,6 +8,7 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do import ExUnit.CaptureLog import Pleroma.Factory import Tesla.Mock + import Pleroma.Test.Matchers.XML setup do mock(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -23,8 +24,10 @@ test "GET host-meta" do assert response.status == 200 - assert response.resp_body == - ~s() + assert_xml_equals( + response.resp_body, + ~s() + ) end test "Webfinger JRD" do diff --git a/test/pleroma/web/xml_test.exs b/test/pleroma/web/xml_test.exs index 49306430b..0dc8d299e 100644 --- a/test/pleroma/web/xml_test.exs +++ b/test/pleroma/web/xml_test.exs @@ -3,6 +3,11 @@ defmodule Pleroma.Web.XMLTest do alias Pleroma.Web.XML + test "parses normal XML" do + data = File.read!("test/fixtures/xml_normal.xml") + assert {:ok, _} = XML.parse_document(data) + end + test "refuses to parse any entities from XML" do data = File.read!("test/fixtures/xml_billion_laughs.xml") assert(:error == XML.parse_document(data)) diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index eab469833..21f031bba 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -27,12 +27,12 @@ defmodule Pleroma.Web.ConnCase do import Plug.Conn import Phoenix.ConnTest use Pleroma.Tests.Helpers - import Pleroma.Web.Router.Helpers alias Pleroma.Config # The default endpoint for testing @endpoint Pleroma.Web.Endpoint + use Pleroma.Web, :verified_routes # Sets up OAuth access with specified scopes defp oauth_access(scopes, opts \\ []) do diff --git a/test/support/data_case.ex b/test/support/data_case.ex index 0ee2aa4a2..5eacc148d 100644 --- a/test/support/data_case.ex +++ b/test/support/data_case.ex @@ -23,12 +23,14 @@ defmodule Pleroma.DataCase do using do quote do alias Pleroma.Repo + @endpoint Pleroma.Web.Endpoint import Ecto import Ecto.Changeset import Ecto.Query import Pleroma.DataCase use Pleroma.Tests.Helpers + use Pleroma.Web, :verified_routes # Sets up OAuth access with specified scopes defp oauth_access(scopes, opts \\ []) do diff --git a/test/support/factory.ex b/test/support/factory.ex index 42c940c52..e21b8fc1e 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Factory do alias Pleroma.Object alias Pleroma.User + alias Pleroma.Web.ActivityPub.UserView @rsa_keys [ "test/fixtures/rsa_keys/key_1.pem", @@ -307,7 +308,7 @@ def add_activity_factory(attrs \\ %{}) do featured_collection_activity(attrs, "Add") end - def remove_activity_factor(attrs \\ %{}) do + def remove_activity_factory(attrs \\ %{}) do featured_collection_activity(attrs, "Remove") end @@ -328,7 +329,7 @@ defp featured_collection_activity(attrs, type) do "target" => user.featured_address, "object" => note.data["object"], "actor" => note.data["actor"], - "type" => "Add", + "type" => type, "to" => [Pleroma.Constants.as_public()], "cc" => [user.follower_address] } @@ -554,6 +555,54 @@ def delete_activity_factory(attrs \\ %{}) do |> Map.merge(attrs) end + def undo_activity_factory(attrs \\ %{}) do + like_activity = attrs[:like_activity] || insert(:like_activity) + attrs = Map.drop(attrs, [:like_activity]) + + data = + %{ + "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(), + "type" => "Undo", + "actor" => like_activity.data["actor"], + "to" => like_activity.data["to"], + "object" => like_activity.data["id"], + "published" => DateTime.utc_now() |> DateTime.to_iso8601(), + "context" => like_activity.data["context"] + } + + %Pleroma.Activity{ + data: data, + actor: data["actor"], + recipients: data["to"] + } + |> Map.merge(attrs) + end + + def update_activity_factory(attrs \\ %{}) do + user = attrs[:user] || insert(:user, nickname: "testuser") + attrs = Map.drop(attrs, [:user]) + + user_data = + UserView.render("user.json", %{user: user}) + |> Map.merge(%{"name" => "new display name"}) + + data = %{ + "type" => "Update", + "to" => [ + user_data["followers"], + "https://www.w3.org/ns/activitystreams#Public" + ], + "actor" => user_data["id"], + "object" => user_data + } + + %Pleroma.Activity{ + actor: user_data["id"], + data: data + } + |> Map.merge(attrs) + end + def oauth_app_factory do %Pleroma.Web.OAuth.App{ client_name: sequence(:client_name, &"Some client #{&1}"), diff --git a/test/support/matchers/list.ex b/test/support/matchers/list.ex new file mode 100644 index 000000000..fa3303e34 --- /dev/null +++ b/test/support/matchers/list.ex @@ -0,0 +1,16 @@ +defmodule Pleroma.Test.Matchers.List do + import ExUnit.Assertions + + def assert_unordered_list_equal(list_a, list_b) when is_list(list_a) and is_list(list_b) do + list_a = Enum.sort(list_a) + list_b = Enum.sort(list_b) + + if list_a != list_b do + flunk("Expected list + #{inspect(list_a)} + to have the same elements as + #{inspect(list_b)} + ") + end + end +end diff --git a/test/support/matchers/uri.ex b/test/support/matchers/uri.ex new file mode 100644 index 000000000..8bd518a40 --- /dev/null +++ b/test/support/matchers/uri.ex @@ -0,0 +1,37 @@ +defmodule Pleroma.Test.Matchers.URI do + import ExUnit.Assertions + + def assert_uri_equals(%URI{} = uri_a, %URI{} = uri_b) do + [:scheme, :authority, :userinfo, :host, :port, :path, :fragment] + |> Enum.each(fn attribute -> + if Map.get(uri_a, attribute) == Map.get(uri_b, attribute) do + :ok + else + flunk("Expected #{uri_a} to match #{uri_b} - #{attribute} does not match") + end + end) + + # And the query string + query_a = URI.decode_query(uri_a.query) + query_b = URI.decode_query(uri_b.query) + + if query_a == query_b do + :ok + else + flunk( + "Expected #{uri_a} to match #{uri_b} - query parameters #{inspect(query_a)} do not match #{inspect(query_b)}" + ) + end + end + + def assert_uri_equals(uri_a, uri_b) when is_binary(uri_a) do + uri_a + |> URI.parse() + |> assert_uri_equals(uri_b) + end + + def assert_uri_equals(%URI{} = uri_a, uri_b) when is_binary(uri_b) do + uri_b = URI.parse(uri_b) + assert_uri_equals(uri_a, uri_b) + end +end diff --git a/test/support/matchers/xml.ex b/test/support/matchers/xml.ex new file mode 100644 index 000000000..9f260ce82 --- /dev/null +++ b/test/support/matchers/xml.ex @@ -0,0 +1,18 @@ +defmodule Pleroma.Test.Matchers.XML do + import ExUnit.Assertions + + def assert_xml_equals(xml_a, xml_b) do + map_a = XmlToMap.naive_map(xml_a) + map_b = XmlToMap.naive_map(xml_b) + + if map_a != map_b do + flunk(~s|Expected XML + #{xml_a} + + to equal + + #{xml_b} + |) + end + end +end