From fba838d61ad280e2a03dd937aa71637e7c0f166b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Nov 2023 13:45:19 +0100 Subject: [PATCH 001/255] Update dependency @material-symbols/svg-600 to ^0.14.0 (#27803) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 112 ++++++--------------------------------------------- 2 files changed, 14 insertions(+), 100 deletions(-) diff --git a/package.json b/package.json index e8f7f02e0..96bfb1571 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "@formatjs/intl-pluralrules": "^5.2.2", "@gamestdio/websocket": "^0.3.2", "@github/webauthn-json": "^2.1.1", - "@material-symbols/svg-600": "^0.13.1", + "@material-symbols/svg-600": "^0.14.0", "@rails/ujs": "^7.1.1", "@reduxjs/toolkit": "^1.9.5", "@svgr/webpack": "^5.5.0", diff --git a/yarn.lock b/yarn.lock index 1b2bfe059..4c70859d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -52,14 +52,7 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9": - version: 7.23.2 - resolution: "@babel/compat-data@npm:7.23.2" - checksum: 0397a08c3e491696cc1b12cf0879bf95fc550bfc6ef524d5a9452981aa0e192a958b2246debfb230fa22718fac473cc5a36616f89b1ad6e7e52055732cd374a1 - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.23.3": +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9, @babel/compat-data@npm:^7.23.3": version: 7.23.3 resolution: "@babel/compat-data@npm:7.23.3" checksum: c6af331753c34ee8a5678bc94404320826cb56b1dda3efc1311ec8fb0774e78225132f3c1acc988440ace667f14a838e297a822692b95758aa63da406e1f97a1 @@ -89,19 +82,7 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.23.0, @babel/generator@npm:^7.7.2": - version: 7.23.0 - resolution: "@babel/generator@npm:7.23.0" - dependencies: - "@babel/types": "npm:^7.23.0" - "@jridgewell/gen-mapping": "npm:^0.3.2" - "@jridgewell/trace-mapping": "npm:^0.3.17" - jsesc: "npm:^2.5.1" - checksum: b7d8727c574119b5ef06e5d5d0d8d939527d51537db4b08273caebb18f3f2b1d4517b874776085e161fd47d28f26b22c08e7f270b64f43b2afd4a60c5936d6cd - languageName: node - linkType: hard - -"@babel/generator@npm:^7.23.3": +"@babel/generator@npm:^7.23.3, @babel/generator@npm:^7.7.2": version: 7.23.3 resolution: "@babel/generator@npm:7.23.3" dependencies: @@ -383,16 +364,7 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/parser@npm:7.23.0" - bin: - parser: ./bin/babel-parser.js - checksum: ab4ea9360ed4ba3c728c5a9bf33035103ebde20a7e943c4ae1d42becb02a313d731d12a93c795c5a19777031e4022e64b92a52262eda902522a1a18649826283 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.23.3": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.3": version: 7.23.3 resolution: "@babel/parser@npm:7.23.3" bin: @@ -556,18 +528,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:7, @babel/plugin-syntax-jsx@npm:^7.22.5, @babel/plugin-syntax-jsx@npm:^7.7.2": - version: 7.22.5 - resolution: "@babel/plugin-syntax-jsx@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: b56ceaa9c6adc17fadfb48e1c801d07797195df2a581489e33c8034950e12e7778de6e1e70d6bcf7c5c7ada6222fe6bad5746187ab280df435f5a2799c8dd0d8 - languageName: node - linkType: hard - -"@babel/plugin-syntax-jsx@npm:^7.23.3": +"@babel/plugin-syntax-jsx@npm:7, @babel/plugin-syntax-jsx@npm:^7.22.5, @babel/plugin-syntax-jsx@npm:^7.23.3, @babel/plugin-syntax-jsx@npm:^7.7.2": version: 7.23.3 resolution: "@babel/plugin-syntax-jsx@npm:7.23.3" dependencies: @@ -666,7 +627,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.23.3": +"@babel/plugin-syntax-typescript@npm:^7.23.3, @babel/plugin-syntax-typescript@npm:^7.7.2": version: 7.23.3 resolution: "@babel/plugin-syntax-typescript@npm:7.23.3" dependencies: @@ -677,17 +638,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.22.5 - resolution: "@babel/plugin-syntax-typescript@npm:7.22.5" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 523a76627f17e67dc1999f4d7c7a71ed79e9f77f55a61cf05051101967ac23ec378ff0c93787b2cbd5d53720ad799658d796a649fa351682b2bf636f63b665a1 - languageName: node - linkType: hard - "@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6" @@ -1552,25 +1502,7 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:7, @babel/traverse@npm:^7.23.2": - version: 7.23.2 - resolution: "@babel/traverse@npm:7.23.2" - dependencies: - "@babel/code-frame": "npm:^7.22.13" - "@babel/generator": "npm:^7.23.0" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-hoist-variables": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.22.6" - "@babel/parser": "npm:^7.23.0" - "@babel/types": "npm:^7.23.0" - debug: "npm:^4.1.0" - globals: "npm:^11.1.0" - checksum: d096c7c4bab9262a2f658298a3c630ae4a15a10755bb257ae91d5ab3e3b2877438934859c8d34018b7727379fe6b26c4fa2efc81cf4c462a7fe00caf79fa02ff - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.23.3": +"@babel/traverse@npm:7, @babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.23.3": version: 7.23.3 resolution: "@babel/traverse@npm:7.23.3" dependencies: @@ -1588,18 +1520,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.23.0 - resolution: "@babel/types@npm:7.23.0" - dependencies: - "@babel/helper-string-parser": "npm:^7.22.5" - "@babel/helper-validator-identifier": "npm:^7.22.20" - to-fast-properties: "npm:^2.0.0" - checksum: 70e4db41acb6793d0eb8d81a2fa88f19ee661219b84bd5f703dbdb54eb3a4d3c0dfc55e69034c945b479df9f43fd4b1376480aaccfc19797ce5af1c5d2576b36 - languageName: node - linkType: hard - -"@babel/types@npm:^7.22.10, @babel/types@npm:^7.23.3": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.3, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": version: 7.23.3 resolution: "@babel/types@npm:7.23.3" dependencies: @@ -2438,7 +2359,7 @@ __metadata: "@formatjs/intl-pluralrules": "npm:^5.2.2" "@gamestdio/websocket": "npm:^0.3.2" "@github/webauthn-json": "npm:^2.1.1" - "@material-symbols/svg-600": "npm:^0.13.1" + "@material-symbols/svg-600": "npm:^0.14.0" "@rails/ujs": "npm:^7.1.1" "@reduxjs/toolkit": "npm:^1.9.5" "@svgr/webpack": "npm:^5.5.0" @@ -2621,10 +2542,10 @@ __metadata: languageName: unknown linkType: soft -"@material-symbols/svg-600@npm:^0.13.1": - version: 0.13.2 - resolution: "@material-symbols/svg-600@npm:0.13.2" - checksum: d467928fe07e640cef8767aaa144a5feda9f060596bf324bcbd0d4c19877073c8bb1b0dba126699b6830906d593bb63ea33ce3c58d102ce67efac674e5e5bfed +"@material-symbols/svg-600@npm:^0.14.0": + version: 0.14.0 + resolution: "@material-symbols/svg-600@npm:0.14.0" + checksum: e6547a9a0b2072f4109f2e4e0863367ea2507efce740c427a8544100db02ffff52f33608aac1a355f4977e2c0b2ce6cdd6bfee9177bb13cee0b28418f948b5a5 languageName: node linkType: hard @@ -11728,14 +11649,7 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": - version: 7.0.3 - resolution: "minipass@npm:7.0.3" - checksum: c85426bce6310368218aad1f20b8f242180b6c2058209c78840959d6fff8a4738076a3224c3a6b651080f95684d559be1bdb084939bc40011c653ec4552cf06e - languageName: node - linkType: hard - -"minipass@npm:^7.0.2, minipass@npm:^7.0.3": +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3": version: 7.0.4 resolution: "minipass@npm:7.0.4" checksum: 6c7370a6dfd257bf18222da581ba89a5eaedca10e158781232a8b5542a90547540b4b9b7e7f490e4cda43acfbd12e086f0453728ecf8c19e0ef6921bc5958ac5 From ac69f90098eba87d54f0bbfc0d76349d93c0792c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 10 Nov 2023 07:46:00 -0500 Subject: [PATCH 002/255] Add `Api::V1::Instances::BaseController` base controller class (#27797) --- app/controllers/api/v1/instances/activity_controller.rb | 6 +----- app/controllers/api/v1/instances/base_controller.rb | 8 ++++++++ .../api/v1/instances/domain_blocks_controller.rb | 4 +--- .../api/v1/instances/extended_descriptions_controller.rb | 5 +---- app/controllers/api/v1/instances/languages_controller.rb | 5 +---- app/controllers/api/v1/instances/peers_controller.rb | 5 +---- .../api/v1/instances/privacy_policies_controller.rb | 6 +----- app/controllers/api/v1/instances/rules_controller.rb | 5 +---- .../api/v1/instances/translation_languages_controller.rb | 6 +----- 9 files changed, 16 insertions(+), 34 deletions(-) create mode 100644 app/controllers/api/v1/instances/base_controller.rb diff --git a/app/controllers/api/v1/instances/activity_controller.rb b/app/controllers/api/v1/instances/activity_controller.rb index 9da77f8da..4c17bd79c 100644 --- a/app/controllers/api/v1/instances/activity_controller.rb +++ b/app/controllers/api/v1/instances/activity_controller.rb @@ -1,12 +1,8 @@ # frozen_string_literal: true -class Api::V1::Instances::ActivityController < Api::BaseController +class Api::V1::Instances::ActivityController < Api::V1::Instances::BaseController before_action :require_enabled_api! - skip_before_action :require_authenticated_user!, unless: :limited_federation_mode? - - vary_by '' - def show cache_even_if_authenticated! render_with_cache json: :activity, expires_in: 1.day diff --git a/app/controllers/api/v1/instances/base_controller.rb b/app/controllers/api/v1/instances/base_controller.rb new file mode 100644 index 000000000..ed0bebf0f --- /dev/null +++ b/app/controllers/api/v1/instances/base_controller.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class Api::V1::Instances::BaseController < Api::BaseController + skip_before_action :require_authenticated_user!, + unless: :limited_federation_mode? + + vary_by '' +end diff --git a/app/controllers/api/v1/instances/domain_blocks_controller.rb b/app/controllers/api/v1/instances/domain_blocks_controller.rb index c91234e08..566764dbf 100644 --- a/app/controllers/api/v1/instances/domain_blocks_controller.rb +++ b/app/controllers/api/v1/instances/domain_blocks_controller.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true -class Api::V1::Instances::DomainBlocksController < Api::BaseController - skip_before_action :require_authenticated_user!, unless: :limited_federation_mode? - +class Api::V1::Instances::DomainBlocksController < Api::V1::Instances::BaseController before_action :require_enabled_api! before_action :set_domain_blocks diff --git a/app/controllers/api/v1/instances/extended_descriptions_controller.rb b/app/controllers/api/v1/instances/extended_descriptions_controller.rb index 376fec906..73d224811 100644 --- a/app/controllers/api/v1/instances/extended_descriptions_controller.rb +++ b/app/controllers/api/v1/instances/extended_descriptions_controller.rb @@ -1,13 +1,10 @@ # frozen_string_literal: true -class Api::V1::Instances::ExtendedDescriptionsController < Api::BaseController - skip_before_action :require_authenticated_user!, unless: :limited_federation_mode? +class Api::V1::Instances::ExtendedDescriptionsController < Api::V1::Instances::BaseController skip_around_action :set_locale before_action :set_extended_description - vary_by '' - # Override `current_user` to avoid reading session cookies unless in whitelist mode def current_user super if limited_federation_mode? diff --git a/app/controllers/api/v1/instances/languages_controller.rb b/app/controllers/api/v1/instances/languages_controller.rb index 17509e748..ea184d90d 100644 --- a/app/controllers/api/v1/instances/languages_controller.rb +++ b/app/controllers/api/v1/instances/languages_controller.rb @@ -1,13 +1,10 @@ # frozen_string_literal: true -class Api::V1::Instances::LanguagesController < Api::BaseController - skip_before_action :require_authenticated_user!, unless: :limited_federation_mode? +class Api::V1::Instances::LanguagesController < Api::V1::Instances::BaseController skip_around_action :set_locale before_action :set_languages - vary_by '' - def show cache_even_if_authenticated! render json: @languages, each_serializer: REST::LanguageSerializer diff --git a/app/controllers/api/v1/instances/peers_controller.rb b/app/controllers/api/v1/instances/peers_controller.rb index 08a982f22..83116472b 100644 --- a/app/controllers/api/v1/instances/peers_controller.rb +++ b/app/controllers/api/v1/instances/peers_controller.rb @@ -1,13 +1,10 @@ # frozen_string_literal: true -class Api::V1::Instances::PeersController < Api::BaseController +class Api::V1::Instances::PeersController < Api::V1::Instances::BaseController before_action :require_enabled_api! - skip_before_action :require_authenticated_user!, unless: :limited_federation_mode? skip_around_action :set_locale - vary_by '' - # Override `current_user` to avoid reading session cookies unless in whitelist mode def current_user super if limited_federation_mode? diff --git a/app/controllers/api/v1/instances/privacy_policies_controller.rb b/app/controllers/api/v1/instances/privacy_policies_controller.rb index f5b1b4ec5..9f87317d5 100644 --- a/app/controllers/api/v1/instances/privacy_policies_controller.rb +++ b/app/controllers/api/v1/instances/privacy_policies_controller.rb @@ -1,12 +1,8 @@ # frozen_string_literal: true -class Api::V1::Instances::PrivacyPoliciesController < Api::BaseController - skip_before_action :require_authenticated_user!, unless: :limited_federation_mode? - +class Api::V1::Instances::PrivacyPoliciesController < Api::V1::Instances::BaseController before_action :set_privacy_policy - vary_by '' - def show cache_even_if_authenticated! render json: @privacy_policy, serializer: REST::PrivacyPolicySerializer diff --git a/app/controllers/api/v1/instances/rules_controller.rb b/app/controllers/api/v1/instances/rules_controller.rb index 2f71984b0..d240d7246 100644 --- a/app/controllers/api/v1/instances/rules_controller.rb +++ b/app/controllers/api/v1/instances/rules_controller.rb @@ -1,13 +1,10 @@ # frozen_string_literal: true -class Api::V1::Instances::RulesController < Api::BaseController - skip_before_action :require_authenticated_user!, unless: :limited_federation_mode? +class Api::V1::Instances::RulesController < Api::V1::Instances::BaseController skip_around_action :set_locale before_action :set_rules - vary_by '' - # Override `current_user` to avoid reading session cookies unless in whitelist mode def current_user super if limited_federation_mode? diff --git a/app/controllers/api/v1/instances/translation_languages_controller.rb b/app/controllers/api/v1/instances/translation_languages_controller.rb index 78423e40e..b8f7a1638 100644 --- a/app/controllers/api/v1/instances/translation_languages_controller.rb +++ b/app/controllers/api/v1/instances/translation_languages_controller.rb @@ -1,12 +1,8 @@ # frozen_string_literal: true -class Api::V1::Instances::TranslationLanguagesController < Api::BaseController - skip_before_action :require_authenticated_user!, unless: :limited_federation_mode? - +class Api::V1::Instances::TranslationLanguagesController < Api::V1::Instances::BaseController before_action :set_languages - vary_by '' - def show cache_even_if_authenticated! render json: @languages From 43e2f763b2f43b5bbcb3b80890ebc89b73545b3b Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 10 Nov 2023 07:47:38 -0500 Subject: [PATCH 003/255] Extract crutches_active_mentions from FeedManager (#27785) --- app/lib/feed_manager.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 2ed145784..4e645a11f 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -551,7 +551,7 @@ class FeedManager def build_crutches(receiver_id, statuses) crutches = {} - crutches[:active_mentions] = Mention.active.where(status_id: statuses.flat_map { |s| [s.id, s.reblog_of_id] }.compact).pluck(:status_id, :account_id).each_with_object({}) { |(id, account_id), mapping| (mapping[id] ||= []).push(account_id) } + crutches[:active_mentions] = crutches_active_mentions(statuses) check_for_blocks = statuses.flat_map do |s| arr = crutches[:active_mentions][s.id] || [] @@ -578,4 +578,12 @@ class FeedManager crutches end + + def crutches_active_mentions(statuses) + Mention + .active + .where(status_id: statuses.flat_map { |status| [status.id, status.reblog_of_id] }.compact) + .pluck(:status_id, :account_id) + .each_with_object({}) { |(id, account_id), mapping| (mapping[id] ||= []).push(account_id) } + end end From ac62b995efdf6fc71f3a1adf60da99ed7ddde26b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 10 Nov 2023 14:07:04 +0100 Subject: [PATCH 004/255] New Crowdin Translations (automated) (#27804) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/cy.json | 1 + app/javascript/mastodon/locales/da.json | 1 + app/javascript/mastodon/locales/de.json | 1 + app/javascript/mastodon/locales/es-AR.json | 1 + app/javascript/mastodon/locales/es-MX.json | 1 + app/javascript/mastodon/locales/es.json | 1 + app/javascript/mastodon/locales/eu.json | 1 + app/javascript/mastodon/locales/fr-QC.json | 1 + app/javascript/mastodon/locales/fr.json | 1 + app/javascript/mastodon/locales/gl.json | 1 + app/javascript/mastodon/locales/he.json | 1 + app/javascript/mastodon/locales/hu.json | 1 + app/javascript/mastodon/locales/is.json | 1 + app/javascript/mastodon/locales/it.json | 1 + app/javascript/mastodon/locales/ja.json | 1 + app/javascript/mastodon/locales/lt.json | 102 ++++++++++++++++++--- app/javascript/mastodon/locales/lv.json | 1 + app/javascript/mastodon/locales/nl.json | 1 + app/javascript/mastodon/locales/nn.json | 1 + app/javascript/mastodon/locales/pl.json | 1 + app/javascript/mastodon/locales/sq.json | 1 + app/javascript/mastodon/locales/sv.json | 1 + app/javascript/mastodon/locales/th.json | 1 + app/javascript/mastodon/locales/tr.json | 1 + app/javascript/mastodon/locales/uk.json | 1 + app/javascript/mastodon/locales/zh-CN.json | 1 + app/javascript/mastodon/locales/zh-HK.json | 1 + app/javascript/mastodon/locales/zh-TW.json | 1 + config/locales/doorkeeper.lt.yml | 68 ++++++++++++++ config/locales/fi.yml | 4 +- config/locales/ja.yml | 10 +- config/locales/lt.yml | 23 +++-- config/locales/lv.yml | 15 ++- config/locales/simple_form.ja.yml | 4 +- 34 files changed, 222 insertions(+), 31 deletions(-) diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 28c7ae178..183ab6955 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Canlyniadau chwilio", "emoji_button.symbols": "Symbolau", "emoji_button.travel": "Teithio a Llefydd", + "empty_column.account_hides_collections": "Mae'r defnyddiwr wedi dewis i beidio rhannu'r wybodaeth yma", "empty_column.account_suspended": "Cyfrif wedi'i atal", "empty_column.account_timeline": "Dim postiadau yma!", "empty_column.account_unavailable": "Nid yw'r proffil ar gael", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index 0a8a4a147..bb8b72bca 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Søgeresultater", "emoji_button.symbols": "Symboler", "emoji_button.travel": "Rejser og steder", + "empty_column.account_hides_collections": "Brugeren har valgt ikke at gøre denne information tilgængelig", "empty_column.account_suspended": "Konto suspenderet", "empty_column.account_timeline": "Ingen indlæg hér!", "empty_column.account_unavailable": "Profil utilgængelig", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 0b9390581..e4f7fe6ce 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Suchergebnisse", "emoji_button.symbols": "Symbole", "emoji_button.travel": "Reisen & Orte", + "empty_column.account_hides_collections": "Das Konto hat sich dazu entschieden, diese Information nicht zu veröffentlichen", "empty_column.account_suspended": "Konto gesperrt", "empty_column.account_timeline": "Keine Beiträge vorhanden!", "empty_column.account_unavailable": "Profil nicht verfügbar", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 7aeb66b54..71d6e3119 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Resultados de búsqueda", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viajes y lugares", + "empty_column.account_hides_collections": "Este usuario eligió no publicar esta información", "empty_column.account_suspended": "Cuenta suspendida", "empty_column.account_timeline": "¡No hay mensajes acá!", "empty_column.account_unavailable": "Perfil no disponible", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index f29a6fd0e..aadc901f9 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Resultados de búsqueda", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viajes y lugares", + "empty_column.account_hides_collections": "Este usuario ha elegido no hacer disponible esta información", "empty_column.account_suspended": "Cuenta suspendida", "empty_column.account_timeline": "¡No hay toots aquí!", "empty_column.account_unavailable": "Perfil no disponible", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 5684ec487..f3735d968 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Resultados de búsqueda", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viajes y lugares", + "empty_column.account_hides_collections": "Este usuario ha decidido no mostrar esta información", "empty_column.account_suspended": "Cuenta suspendida", "empty_column.account_timeline": "¡No hay publicaciones aquí!", "empty_column.account_unavailable": "Perfil no disponible", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index 5b4fef59c..7f109ea08 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Bilaketaren emaitzak", "emoji_button.symbols": "Sinboloak", "emoji_button.travel": "Bidaiak eta tokiak", + "empty_column.account_hides_collections": "Erabiltzaile honek informazio hau erabilgarri ez egotea aukeratu du.", "empty_column.account_suspended": "Kanporatutako kontua", "empty_column.account_timeline": "Ez dago bidalketarik hemen!", "empty_column.account_unavailable": "Profila ez dago eskuragarri", diff --git a/app/javascript/mastodon/locales/fr-QC.json b/app/javascript/mastodon/locales/fr-QC.json index 16a18048b..a6dd91bec 100644 --- a/app/javascript/mastodon/locales/fr-QC.json +++ b/app/javascript/mastodon/locales/fr-QC.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Résultats", "emoji_button.symbols": "Symboles", "emoji_button.travel": "Voyage et lieux", + "empty_column.account_hides_collections": "Cet utilisateur·ice préfère ne pas rendre publiques ces informations", "empty_column.account_suspended": "Compte suspendu", "empty_column.account_timeline": "Aucune publication ici!", "empty_column.account_unavailable": "Profil non disponible", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 947191854..0d2ba2bb9 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Résultats de la recherche", "emoji_button.symbols": "Symboles", "emoji_button.travel": "Voyage et lieux", + "empty_column.account_hides_collections": "Cet utilisateur·ice préfère ne pas rendre publiques ces informations", "empty_column.account_suspended": "Compte suspendu", "empty_column.account_timeline": "Aucun message ici !", "empty_column.account_unavailable": "Profil non disponible", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 14ff22b28..e79e54926 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Resultados da procura", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viaxes e Lugares", + "empty_column.account_hides_collections": "A usuaria decideu non facer pública esta información", "empty_column.account_suspended": "Conta suspendida", "empty_column.account_timeline": "Non hai publicacións aquí!", "empty_column.account_unavailable": "Perfil non dispoñible", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 13d323965..485e8313a 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "תוצאות חיפוש", "emoji_button.symbols": "סמלים", "emoji_button.travel": "טיולים ואתרים", + "empty_column.account_hides_collections": "המשתמש.ת בחר.ה להסתיר מידע זה", "empty_column.account_suspended": "חשבון מושהה", "empty_column.account_timeline": "אין עדיין אף הודעה!", "empty_column.account_unavailable": "פרופיל לא זמין", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 482dc48be..ca2027161 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Keresési találatok", "emoji_button.symbols": "Szimbólumok", "emoji_button.travel": "Utazás és Helyek", + "empty_column.account_hides_collections": "Ez a felhasználó úgy döntött, hogy nem teszi elérhetővé ezt az információt.", "empty_column.account_suspended": "Fiók felfüggesztve", "empty_column.account_timeline": "Itt nincs bejegyzés!", "empty_column.account_unavailable": "A profil nem érhető el", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index f2e6f1f44..0b6a8012a 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Leitarniðurstöður", "emoji_button.symbols": "Tákn", "emoji_button.travel": "Ferðalög og staðir", + "empty_column.account_hides_collections": "Notandinn hefur valið að gera ekki tiltækar þessar upplýsingar", "empty_column.account_suspended": "Notandaaðgangur í frysti", "empty_column.account_timeline": "Engar færslur hér!", "empty_column.account_unavailable": "Notandasnið ekki tiltækt", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 473a123ed..4a2f41ce6 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Risultati della ricerca", "emoji_button.symbols": "Simboli", "emoji_button.travel": "Viaggi & Luoghi", + "empty_column.account_hides_collections": "Questo utente ha scelto di non rendere disponibili queste informazioni", "empty_column.account_suspended": "Profilo sospeso", "empty_column.account_timeline": "Nessun post qui!", "empty_column.account_unavailable": "Profilo non disponibile", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index a01354463..72a57c8e3 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "検索結果", "emoji_button.symbols": "記号", "emoji_button.travel": "旅行と場所", + "empty_column.account_hides_collections": "このユーザーはこの情報を開示しないことにしています。", "empty_column.account_suspended": "アカウントは停止されています", "empty_column.account_timeline": "投稿がありません!", "empty_column.account_unavailable": "プロフィールは利用できません", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 62aaa8475..a1ab53131 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -1,25 +1,37 @@ { - "about.blocks": "Moderatorių prižiūrimi serveriai", - "about.contact": "Kontaktai:", - "about.disclaimer": "Mastodon, tai nemokama, atviro kodo programa, kuriuos prekybinis ženklas priklauso Mastodon GmbH.", + "about.blocks": "Prižiūrimi serveriai", + "about.contact": "Kontaktuoti:", + "about.disclaimer": "Mastodon – nemokama atvirojo šaltinio programa ir Mastodon gGmbH prekės ženklas.", "about.domain_blocks.no_reason_available": "Priežastis nežinoma", - "about.domain_blocks.suspended.title": "Uždraustas", - "about.not_available": "Šiame serveryje informacijos nėra.", + "about.domain_blocks.preamble": "Mastodon paprastai leidžia peržiūrėti turinį ir bendrauti su naudotojais iš bet kurio kito fediverse esančio serverio. Šios yra išimtys, kurios buvo padarytos šiame konkrečiame serveryje.", + "about.domain_blocks.silenced.explanation": "Paprastai nematysi profilių ir turinio iš šio serverio, nebent jį aiškiai ieškosi arba pasirinksi jį sekdamas (-a).", + "about.domain_blocks.silenced.title": "Ribota", + "about.domain_blocks.suspended.explanation": "Jokie duomenys iš šio serverio nebus apdorojami, saugomi ar keičiami, todėl bet kokia sąveika ar bendravimas su šio serverio naudotojais bus neįmanomas.", + "about.domain_blocks.suspended.title": "Uždrausta", + "about.not_available": "Ši informacija nebuvo pateikta šiame serveryje.", + "about.powered_by": "Decentralizuota socialinė žiniasklaida, kurią valdo {mastodon}", "about.rules": "Serverio taisyklės", "account.account_note_header": "Pastaba", - "account.add_or_remove_from_list": "Pridėti arba ištrinti iš sąrašo", - "account.badges.bot": "Robotas", + "account.add_or_remove_from_list": "Pridėti arba ištrinti iš sąrašų", + "account.badges.bot": "Automatizuotas", "account.badges.group": "Grupė", "account.block": "Užblokuoti @{name}", - "account.block_domain": "Hide everything from {domain}", + "account.block_domain": "Blokuoti domeną {domain}", + "account.block_short": "Blokuoti", "account.blocked": "Užblokuota", - "account.cancel_follow_request": "Withdraw follow request", - "account.domain_blocked": "Domain hidden", + "account.browse_more_on_origin_server": "Naršyti daugiau originaliame profilyje", + "account.cancel_follow_request": "Atšaukti sekimą", + "account.direct": "Privačiai paminėti @{name}", + "account.disable_notifications": "Nustoti man pranešti, kai @{name} paskelbia", + "account.domain_blocked": "Užblokuotas domenas", + "account.edit_profile": "Redaguoti profilį", "account.follow": "Sekti", "account.follows_you": "Seka jus", "account.go_to_profile": "Eiti į profilį", + "account.in_memoriam": "Atminimui.", "account.joined_short": "Prisijungė", - "account.media": "Media", + "account.locked_info": "Šios paskyros privatumo būsena nustatyta kaip užrakinta. Savininkas (-ė) rankiniu būdu peržiūri, kas gali sekti.", + "account.media": "Medija", "account.mute": "Užtildyti @{name}", "account.muted": "Užtildytas", "account.posts": "Toots", @@ -33,6 +45,10 @@ "account.unmute_short": "Atitildyti", "account_note.placeholder": "Click to add a note", "alert.unexpected.title": "Oi!", + "announcement.announcement": "Skelbimas", + "audio.hide": "Slėpti garsą", + "autosuggest_hashtag.per_week": "{count} per savaitę", + "bundle_column_error.error.title": "O, ne!", "column.domain_blocks": "Hidden domains", "column.lists": "Sąrašai", "column.mutes": "Užtildyti vartotojai", @@ -43,24 +59,50 @@ "column_header.show_settings": "Rodyti nustatymus", "column_header.unpin": "Atsegti", "column_subheading.settings": "Nustatymai", - "community.column_settings.media_only": "Media only", + "community.column_settings.media_only": "Tik medija", + "compose.language.change": "Keisti kalbą", + "compose.language.search": "Ieškoti kalbų...", + "compose.published.body": "Įrašas paskelbtas.", "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.", "compose_form.placeholder": "What is on your mind?", "compose_form.publish_form": "Publish", + "compose_form.sensitive.hide": "{count, plural, one {Žymėti mediją kaip jautrią} few {Žymėti medijas kaip jautrias} many {Žymėti medijos kaip jautrios} other {Žymėti medijų kaip jautrių}}", + "compose_form.sensitive.marked": "{count, plural, one {Medija pažymėta kaip jautri} few {Medijos pažymėtos kaip jautrios} many {Medijos pažymėta kaip jautrios} other {Medijų pažymėtos kaip jautrios}}", + "compose_form.sensitive.unmarked": "{count, plural, one {Medija nepažymėta kaip jautri} few {Medijos nepažymėtos kaip jautrios} many {Medijos nepažymėta kaip jautri} other {Medijų nepažymėta kaip jautrios}}", "compose_form.spoiler.marked": "Text is hidden behind warning", "compose_form.spoiler.unmarked": "Text is not hidden", + "confirmations.delete.confirm": "Ištrinti", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.discard_edit_media.confirm": "Atmesti", + "confirmations.discard_edit_media.message": "Turi neišsaugotų medijos aprašymo ar peržiūros pakeitimų, vis tiek juos atmesti?", "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.reply.confirm": "Atsakyti", + "confirmations.reply.message": "Atsakydamas (-a) dabar perrašysi šiuo metu rašomą žinutę. Ar tikrai nori tęsti?", + "confirmations.unfollow.confirm": "Nebesekti", "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", "embed.instructions": "Embed this status on your website by copying the code below.", + "emoji_button.search": "Paieška...", + "empty_column.account_hides_collections": "Šis naudotojas (-a) pasirinko nepadaryti šią informaciją prieinamą", "empty_column.account_timeline": "No toots here!", "empty_column.bookmarked_statuses": "You don't have any bookmarked toots yet. When you bookmark one, it will show up here.", "empty_column.domain_blocks": "There are no hidden domains yet.", + "empty_column.hashtag": "Nėra nieko šiame saitažodyje kol kas.", "empty_column.home": "Your home timeline is empty! Follow more people to fill it up. {suggestions}", "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", + "firehose.local": "Šis serveris", + "follow_requests.unlocked_explanation": "Nors tavo paskyra neužrakinta, {domain} personalas mano, kad galbūt norėsi rankiniu būdu patikrinti šių paskyrų sekimo užklausas.", + "followed_tags": "Sekamos saitažodžiai", + "footer.about": "Apie", + "footer.invite": "Kviesti žmones", "hashtag.column_settings.tag_toggle": "Include additional tags in this column", + "interaction_modal.no_account_yet": "Nesi Mastodon?", + "interaction_modal.on_another_server": "Kitame serveryje", + "interaction_modal.on_this_server": "Šiame serveryje", + "interaction_modal.sign_in": "Nesi prisijungęs (-usi) prie šio serverio. Kur yra laikoma tavo paskyra?", + "interaction_modal.sign_in_hint": "Patarimas: tai svetainė, kurioje užsiregistravai. Jei neprisimeni, ieškok sveikinimo el. laiško savo pašto dėžutėje. Taip pat gali įvesti visą savo naudotojo vardą (pvz., @Mastodon@mastodon.social).", + "interaction_modal.title.favourite": "Mėgstamiausias {name} įrašas", "keyboard_shortcuts.back": "to navigate back", "keyboard_shortcuts.blocked": "to open blocked users list", "keyboard_shortcuts.boost": "to boost", @@ -72,13 +114,14 @@ "keyboard_shortcuts.federated": "to open federated timeline", "keyboard_shortcuts.heading": "Keyboard Shortcuts", "keyboard_shortcuts.home": "to open home timeline", + "keyboard_shortcuts.hotkey": "Spartusis klavišas", "keyboard_shortcuts.legend": "to display this legend", "keyboard_shortcuts.local": "to open local timeline", "keyboard_shortcuts.mention": "to mention author", "keyboard_shortcuts.muted": "to open muted users list", "keyboard_shortcuts.my_profile": "to open your profile", "keyboard_shortcuts.notifications": "to open notifications column", - "keyboard_shortcuts.open_media": "to open media", + "keyboard_shortcuts.open_media": "Atidaryti mediją", "keyboard_shortcuts.pinned": "to open pinned toots list", "keyboard_shortcuts.profile": "to open author's profile", "keyboard_shortcuts.reply": "to reply", @@ -87,21 +130,39 @@ "keyboard_shortcuts.spoilers": "to show/hide CW field", "keyboard_shortcuts.start": "to open \"get started\" column", "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW", - "keyboard_shortcuts.toggle_sensitivity": "to show/hide media", + "keyboard_shortcuts.toggle_sensitivity": "Rodyti / slėpti mediją", "keyboard_shortcuts.toot": "to start a brand new toot", "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", "keyboard_shortcuts.up": "to move up in the list", + "lightbox.close": "Uždaryti", + "media_gallery.toggle_visible": "{number, plural, one {Slėpti vaizdą} few {Slėpti vaizdus} many {Slėpti vaizdo} other {Slėpti vaizdų}}", "navigation_bar.compose": "Compose new toot", "navigation_bar.domain_blocks": "Hidden domains", + "navigation_bar.follows_and_followers": "Sekimai ir sekėjai", + "navigation_bar.lists": "Sąrašai", + "navigation_bar.logout": "Atsijungti", + "navigation_bar.mutes": "Užtildyti naudotojai", + "navigation_bar.opened_in_classic_interface": "Įrašai, paskyros ir kiti konkretūs puslapiai pagal numatytuosius nustatymus atidaromi klasikinėje žiniatinklio sąsajoje.", + "navigation_bar.personal": "Asmeninis", "navigation_bar.pins": "Pinned toots", + "navigation_bar.preferences": "Nuostatos", "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", + "notification.own_poll": "Tavo apklausa baigėsi", + "notification.poll": "Apklausa, kurioje balsavai, pasibaigė", "notification.reblog": "{name} boosted your status", + "notification.status": "{name} ką tik paskelbė", + "notification.update": "{name} redagavo įrašą", + "notifications.clear": "Išvalyti pranešimus", + "notifications.clear_confirmation": "Ar tikrai nori visam laikui išvalyti visus pranešimus?", + "notifications.column_settings.admin.report": "Nauji ataskaitos:", "notifications.column_settings.status": "New toots:", + "notifications.filter.mentions": "Paminėjimai", "onboarding.actions.go_to_explore": "See what's trending", "onboarding.actions.go_to_home": "Go to your home feed", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", - "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", + "onboarding.share.message": "Aš {username} #Mastodon! Ateik sekti manęs adresu {url}", + "onboarding.start.lead": "Dabar esi Mastodon dalis – unikalios decentralizuotos socialinės žiniasklaidos platformos, kurioje tu, o ne algoritmas, pats nustatai savo patirtį. Pradėkime tavo kelionę šioje naujoje socialinėje erdvėje:", "onboarding.start.skip": "Want to skip right ahead?", "onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.", "onboarding.steps.follow_people.title": "Follow {count, plural, one {one person} other {# people}}", @@ -110,11 +171,17 @@ "onboarding.steps.setup_profile.title": "Customize your profile", "onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!", "onboarding.steps.share_profile.title": "Share your profile", + "poll.vote": "Balsuoti", + "poll.voted": "Tu balsavai už šį atsakymą", + "poll.votes": "{votes, plural, one {# balsas} few {# balsai} many {# balso} other {# balsų}}", "privacy.change": "Adjust status privacy", "privacy.direct.long": "Post to mentioned users only", "privacy.direct.short": "Direct", "privacy.private.long": "Post to followers only", "privacy.private.short": "Followers-only", + "privacy.unlisted.long": "Matomas visiems, bet atsisakyta atradimo funkcijų", + "privacy.unlisted.short": "Neįtrauktas į sąrašą", + "privacy_policy.last_updated": "Paskutinį kartą atnaujinta {date}", "report.placeholder": "Type or paste additional comments", "report.submit": "Submit report", "report.target": "Report {target}", @@ -124,14 +191,19 @@ "status.admin_status": "Open this status in the moderation interface", "status.copy": "Copy link to status", "status.edited_x_times": "Edited {count, plural, one {# time} other {# times}}", + "status.media.open": "Spausk, kad atidaryti", + "status.media.show": "Spausk, kad pamatyti", + "status.media_hidden": "Paslėpta medija", "status.open": "Expand this status", "status.pinned": "Pinned toot", "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}", + "status.uncached_media_warning": "Peržiūra nepasiekiama", "timeline_hint.resources.statuses": "Older toots", "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {# days}}", "upload_form.audio_description": "Describe for people with hearing loss", "upload_form.description": "Describe for the visually impaired", "upload_form.video_description": "Describe for people with hearing loss or visual impairment", + "upload_modal.edit_media": "Redaguoti mediją", "upload_progress.label": "Uploading…" } diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index 7f71d9318..5d681b829 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Meklēšanas rezultāti", "emoji_button.symbols": "Simboli", "emoji_button.travel": "Ceļošana un vietas", + "empty_column.account_hides_collections": "Šis lietotājs ir izvēlējies nedarīt šo informāciju pieejamu", "empty_column.account_suspended": "Konta darbība ir apturēta", "empty_column.account_timeline": "Šeit ziņojumu nav!", "empty_column.account_unavailable": "Profils nav pieejams", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 87a2af4f2..131d2e4aa 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Zoekresultaten", "emoji_button.symbols": "Symbolen", "emoji_button.travel": "Reizen en locaties", + "empty_column.account_hides_collections": "Deze gebruiker heeft ervoor gekozen deze informatie niet beschikbaar te maken", "empty_column.account_suspended": "Account opgeschort", "empty_column.account_timeline": "Hier zijn geen berichten!", "empty_column.account_unavailable": "Profiel is niet beschikbaar", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index 8ff390aab..aa30aef7d 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Søkeresultat", "emoji_button.symbols": "Symbol", "emoji_button.travel": "Reise & stader", + "empty_column.account_hides_collections": "Denne brukaren har valt å ikkje gjere denne informasjonen tilgjengeleg", "empty_column.account_suspended": "Kontoen er suspendert", "empty_column.account_timeline": "Ingen tut her!", "empty_column.account_unavailable": "Profil ikkje tilgjengeleg", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 84ea64bb9..643f78a88 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Wyniki wyszukiwania", "emoji_button.symbols": "Symbole", "emoji_button.travel": "Podróże i miejsca", + "empty_column.account_hides_collections": "Użytkownik postanowił nie udostępniać tych informacji", "empty_column.account_suspended": "Konto zawieszone", "empty_column.account_timeline": "Brak wpisów tutaj!", "empty_column.account_unavailable": "Profil niedostępny", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 2e908fdc5..8d54ef41b 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Përfundime kërkimi", "emoji_button.symbols": "Simbole", "emoji_button.travel": "Udhëtime & Vende", + "empty_column.account_hides_collections": "Ky përdorues ka zgjedhur të mos e japë këtë informacion", "empty_column.account_suspended": "Llogaria u pezullua", "empty_column.account_timeline": "S’ka mesazhe këtu!", "empty_column.account_unavailable": "Profil jashtë funksionimi", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index e0b6fc472..edf981e11 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Sökresultat", "emoji_button.symbols": "Symboler", "emoji_button.travel": "Resor & platser", + "empty_column.account_hides_collections": "Användaren har valt att inte göra denna information tillgänglig", "empty_column.account_suspended": "Kontot är avstängt", "empty_column.account_timeline": "Inga inlägg här!", "empty_column.account_unavailable": "Profilen ej tillgänglig", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index ff6e5a52d..80f862cbe 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "ผลลัพธ์การค้นหา", "emoji_button.symbols": "สัญลักษณ์", "emoji_button.travel": "การเดินทางและสถานที่", + "empty_column.account_hides_collections": "ผู้ใช้นี้ได้เลือกที่จะไม่ทำให้ข้อมูลนี้พร้อมใช้งาน", "empty_column.account_suspended": "ระงับบัญชีอยู่", "empty_column.account_timeline": "ไม่มีโพสต์ที่นี่!", "empty_column.account_unavailable": "โปรไฟล์ไม่พร้อมใช้งาน", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index de92b9b56..9ad259493 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Arama sonuçları", "emoji_button.symbols": "Semboller", "emoji_button.travel": "Seyahat ve Yerler", + "empty_column.account_hides_collections": "Bu kullanıcı bu bilgiyi sağlamayı tercih etmemiştir", "empty_column.account_suspended": "Hesap askıya alındı", "empty_column.account_timeline": "Burada hiç gönderi yok!", "empty_column.account_unavailable": "Profil kullanılamıyor", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index aa17e1254..09fa58fbf 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Результати пошуку", "emoji_button.symbols": "Символи", "emoji_button.travel": "Подорожі та місця", + "empty_column.account_hides_collections": "Цей користувач вирішив не робити цю інформацію доступною", "empty_column.account_suspended": "Обліковий запис заблоковано", "empty_column.account_timeline": "Тут немає дописів!", "empty_column.account_unavailable": "Профіль недоступний", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index c311b5ae3..f830aa298 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "搜索结果", "emoji_button.symbols": "符号", "emoji_button.travel": "旅行和地点", + "empty_column.account_hides_collections": "该用户选择不提供此信息", "empty_column.account_suspended": "账户已被停用", "empty_column.account_timeline": "这里没有嘟文!", "empty_column.account_unavailable": "个人资料不可用", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index 47880f711..7121a7d03 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "搜尋結果", "emoji_button.symbols": "符號", "emoji_button.travel": "旅遊景物", + "empty_column.account_hides_collections": "這位使用者選擇不公開此資訊", "empty_column.account_suspended": "帳號已停權", "empty_column.account_timeline": "這裡還沒有嘟文!", "empty_column.account_unavailable": "無法取得個人資料", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 5d3d74ea6..db4fe4eab 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "搜尋結果", "emoji_button.symbols": "符號", "emoji_button.travel": "旅遊與地點", + "empty_column.account_hides_collections": "這位使用者選擇不提供此資訊", "empty_column.account_suspended": "帳號已被停權", "empty_column.account_timeline": "這裡還沒有嘟文!", "empty_column.account_unavailable": "無法取得個人檔案", diff --git a/config/locales/doorkeeper.lt.yml b/config/locales/doorkeeper.lt.yml index 6c5cb837a..36f31e39e 100644 --- a/config/locales/doorkeeper.lt.yml +++ b/config/locales/doorkeeper.lt.yml @@ -1 +1,69 @@ +--- lt: + doorkeeper: + authorizations: + error: + title: Įvyko klaida. + new: + prompt_html: "%{client_name} norėtų gauti leidimą prieigos prie tavo paskyros. Tai trečiosios šalies programėlė. <strong>Jei ja nepasitiki, neturėtum jai leisti.</strong>" + authorized_applications: + index: + title: Tavo leidžiamos programėlės + grouped_scopes: + title: + blocks: Blokavimai + follow: Sekimai, nutildymai ir blokavimai + statuses: Įrašai + layouts: + admin: + nav: + applications: Programėlės + oauth2_provider: OAuth2 teikėjas + application: + title: Reikalingas OAuth įgaliojimas + scopes: + admin:read: skaityti visus serveryje esančius duomenis + admin:read:accounts: skaityti neskelbtiną visų paskyrų informaciją + admin:read:canonical_email_blocks: skaityti neskelbtiną visų kanoninių el. laiško blokavimų informaciją + admin:read:domain_allows: skaityti neskelbtiną visų domeno leidimus informaciją + admin:read:domain_blocks: skaityti neskelbtiną visų domeno blokavimų informaciją + admin:read:email_domain_blocks: skaityti neskelbtiną visų el. laiško domeno blokavimų informaciją + admin:read:ip_blocks: skaityti neskelbtiną visų IP blokavimų informaciją + admin:read:reports: skaityti neskelbtiną visų ataskaitų ir praneštų paskyrų informaciją + admin:write: modifikuoti visus serveryje esančius duomenis + admin:write:accounts: atlikti paskyrų prižiūrėjimo veiksmus + admin:write:canonical_email_blocks: atlikti kanoninių el. laiško blokavimų prižiūrėjimo veiksmus + admin:write:domain_allows: atlikti prižiūrėjimo veiksmus su domeno leidimais + admin:write:domain_blocks: atlikti prižiūrėjimo veiksmus su domenų blokavimais + admin:write:email_domain_blocks: atlikti prižiūrėjimo veiksmus su el. laiško domenų blokavimais + admin:write:ip_blocks: atlikti prižiūrėjimo veiksmus su IP blokavimais + crypto: naudoti galo iki galo šifravimą + follow: modifikuoti paskyros santykius + push: gauti tavo stumiamuosius pranešimus + read: skaityti tavo visus paskyros duomenis + read:accounts: matyti paskyrų informaciją + read:blocks: matyti tavo blokavimus + read:bookmarks: matyti tavo žymes + read:favourites: matyti tavo mėgstamiausius + read:filters: matyti tavo filtrus + read:follows: matyti tavo sekimus + read:lists: matyti tavo sąrašus + read:mutes: matyti tavo nutildymus + read:notifications: matyti tavo pranešimus + read:reports: matyti tavo ataskaitas + read:search: ieškoti tavo vardu + read:statuses: matyti visus įrašus + write: modifikuoti visus tavo paskyros duomenis + write:accounts: modifikuoti tavo profilį + write:blocks: blokuoti paskyras ir domenus + write:bookmarks: įrašyti įrašus + write:conversations: nutildyti ir ištrinti pokalbius + write:favourites: mėgti įrašai + write:filters: sukurti filtrus + write:follows: sekti žmones + write:lists: sukurti sąrašus + write:media: įkelti medijos failus + write:mutes: nutildyti žmones ir pokalbius + write:notifications: išvalyti tavo pranešimus + write:reports: pranešti kitus asmenus + write:statuses: skelbti įrašus diff --git a/config/locales/fi.yml b/config/locales/fi.yml index d6f327c32..4fe0179df 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -1041,13 +1041,13 @@ fi: hint_html: Vielä yksi juttu! Meidän on vahvistettava, että olet ihminen (tämän avulla pidämme roskapostin poissa!). Ratkaise alla oleva CAPTCHA-vahvistus ja paina "Jatka". title: Turvatarkastus confirmations: - awaiting_review: Sähköpostiosoitteesi on vahvistettu! Seuraavaksi palvelimen %{domain} ylläpito tarkistaa rekisteröitymisesi ja saat lopuksi ilmoituksen sähköpostitse, jos tilisi hyväksytään! + awaiting_review: Sähköpostiosoitteesi on vahvistettu! Seuraavaksi palvelimen %{domain} ylläpito tarkistaa rekisteröitymisesi, ja saat lopuksi ilmoituksen sähköpostitse, jos tilisi hyväksytään! awaiting_review_title: Rekisteröitymisesi on tarkistettavana clicking_this_link: tästä linkistä login_link: kirjautumalla sisään proceed_to_login_html: Voit nyt jatkaa %{login_link}. redirect_to_app_html: Sinun olisi pitänyt ohjautua sovellukseen <strong>%{app_name}</strong>. Jos näin ei tapahtunut, yritä avata se %{clicking_this_link} tai palaa sovellukseen manuaalisesti. - registration_complete: Rekisteröitymisesi palvelimelle %{domain} on suoritettu! + registration_complete: Rekisteröitymisesi palvelimelle %{domain} on nyt valmis! welcome_title: Tervetuloa, %{name}! wrong_email_hint: Jos sähköpostiosoite ei ole oikein, voit muuttaa sen tilin asetuksista. delete_account: Poista tili diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 0c805b9e5..ca438f53d 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -1025,12 +1025,12 @@ ja: confirmations: awaiting_review: メールアドレスは確認済みです。%{domain} のモデレーターによりアカウント登録の審査が完了すると、メールでお知らせします。 awaiting_review_title: 登録の審査待ちです - clicking_this_link: こちらのリンク - login_link: こちらのリンク - proceed_to_login_html: "%{login_link}から早速ログインしてみましょう。" - redirect_to_app_html: "<strong>%{app_name}</strong>に戻ります。自動で移動しない場合は%{clicking_this_link}を押すか、手動でアプリを切り替えてください。" + clicking_this_link: このリンクを押す + login_link: ログイン + proceed_to_login_html: それでは%{login_link}しましょう。 + redirect_to_app_html: 自動的に<strong>%{app_name}</strong>に戻らなかった場合、%{clicking_this_link}か、手動でアプリを切り替えてください。 registration_complete: "%{domain} へのアカウント登録が完了しました。" - welcome_title: Mastodonへようこそ、%{name}さん + welcome_title: ようこそ、%{name}さん! wrong_email_hint: メールアドレスが正しくない場合は、アカウント設定で変更できます。 delete_account: アカウントの削除 delete_account_html: アカウントを削除したい場合、<a href="%{path}">こちら</a>から手続きが行えます。削除する前に、確認画面があります。 diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 7ad63c5e3..2f4d813c9 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -58,6 +58,7 @@ lt: follows: Seka header: Antraštė inbox_url: Gautųjų URL + invite_request_text: Priežastys prisijungiant invited_by: Pakvietė ip: IP joined: Prisijungė @@ -183,10 +184,10 @@ lt: deactivate_all: Deaktyvuoti visus filter: all: Visi - available: Prieinamas + available: Pasiekiamas expired: Pasibaigęs title: Filtras - title: Pakvietimai + title: Kvietimai relays: add_new: Pridėti naują pamainą delete: Ištrinti @@ -236,6 +237,8 @@ lt: everyone: Numatytieji leidimai everyone_full_description_html: Tai – <strong>bazinis vaidmuo</strong>, turintis įtakos <strong>visiems naudotojams</strong>, net ir tiems, kurie neturi priskirto vaidmens. Visi kiti vaidmenys iš jo paveldi teises. settings: + captcha_enabled: + desc_html: Tai priklauso nuo hCaptcha išorinių skriptų, kurie gali kelti susirūpinimą dėl saugumo ir privatumo. Be to, <strong>dėl to registracijos procesas kai kuriems žmonėms (ypač neįgaliesiems) gali būti gerokai sunkiau prieinami</strong>. Dėl šių priežasčių apsvarstyk alternatyvias priemones, pavyzdžiui, patvirtinimu arba kvietimu grindžiamą registraciją. domain_blocks: all: Visiems statuses: @@ -285,6 +288,9 @@ lt: or_log_in_with: Arba prisijungti su register: Užsiregistruoti reset_password: Atstatyti slaptažodį + rules: + invited_by: 'Gali prisijungti prie %{domain} pagal kvietimą, kurį gavai iš:' + preamble_invited: Prieš tęsiant, atsižvelk į pagrindines taisykles, kurias nustatė %{domain} prižiūrėtojai. security: Apsauga set_new_password: Nustatyti naują slaptažodį datetime: @@ -367,7 +373,7 @@ lt: upload: Įkelti invites: delete: Deaktyvuoti - expired: Pasibaigęs + expired: Pasibaigė expires_in: '1800': 30 minučių '21600': 6 valandų @@ -378,10 +384,15 @@ lt: expires_in_prompt: Niekada generate: Generuoti invited_by: 'Jus pakvietė:' - max_uses_prompt: Be limito - prompt: Generuoti ir dalintis įrašais su kitais, kad sukurti prieigą prie serverio + max_uses: + few: "%{count} panaudojimai" + many: "%{count} panaudojimo" + one: 1 panaudojimas + other: "%{count} panaudojimų" + max_uses_prompt: Nėra limito + prompt: Generuok ir bendrink nuorodas su kitais, kad suteiktum prieigą prie šio serverio table: - expires_at: Pasibaigia + expires_at: Baigsis uses: Naudojimai title: Pakviesti žmones media_attachments: diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 28a1a33dc..4bcf23de4 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -343,7 +343,7 @@ lv: title: Pielāgotās emocijzīmes uncategorized: Nekategorizētās unlist: Izslēgt - unlisted: Nerindota + unlisted: Neminētie update_failed_msg: Nevarēja atjaunināt šo emocijzīmi updated_msg: Emocijzīme veiksmīgi atjaunināta! upload: Augšupielādēt @@ -545,6 +545,7 @@ lv: total_reported: Ziņojumi par viņiem total_storage: Multividesu pielikumi totals_time_period_hint_html: Tālāk redzamajās summās ir iekļauti dati par visu laiku. + unknown_instance: Pašlaik šajā serverī nav ierakstu par šo domēnu. invites: deactivate_all: Deaktivēt visu filter: @@ -1058,6 +1059,14 @@ lv: hint_html: Vēl tikai viena lieta! Mums ir jāapstiprina, ka tu esi cilvēks (tas ir tāpēc, lai mēs varētu nepieļaut surogātpasta izsūtīšanu!). Atrisini tālāk norādīto CAPTCHA un noklikšķini uz "Turpināt". title: Drošības pārbaude confirmations: + awaiting_review: Tava e-pasta adrese ir apstiprināta! %{domain} darbinieki tagad pārskata tavu reģistrāciju. Tu saņemsi e-pastu, ja viņi apstiprinās tavu kontu! + awaiting_review_title: Tava reģistrācija tiek izskatīta + clicking_this_link: klikšķinot šo saiti + login_link: pieteikties + proceed_to_login_html: Tagad vari doties uz %{login_link}. + redirect_to_app_html: Tev vajadzētu būt novirzītam uz lietotni <strong>%{app_name}</strong>. Ja tas nenotika, mēģini %{clicking_this_link} vai manuāli atgriezieties lietotnē. + registration_complete: Tava reģistrācija domēnā %{domain} tagad ir pabeigta! + welcome_title: Laipni lūdzam, %{name}! wrong_email_hint: Ja šī e-pasta adrese nav pareiza, varat to mainīt konta iestatījumos. delete_account: Dzēst kontu delete_account_html: Ja vēlies dzēst savu kontu, tu vari <a href="%{path}">turpināt šeit</a>. Tev tiks lūgts apstiprinājums. @@ -1119,6 +1128,7 @@ lv: functional: Tavs konts ir pilnībā darboties spējīgs. pending: Tavu pieteikumu gaida mūsu darbinieku izskatīšana. Tas var aizņemt kādu laiku. Ja tavs pieteikums tiks apstiprināts, tu saņemsi e-pastu. redirecting_to: Tavs konts ir neaktīvs, jo pašlaik tas tiek novirzīts uz %{acct}. + self_destruct: Tā kā %{domain} tiek slēgts, tu iegūsi tikai ierobežotu piekļuvi savam kontam. view_strikes: Skati iepriekšējos brīdinājumus par savu kontu too_fast: Veidlapa ir iesniegta pārāk ātri, mēģini vēlreiz. use_security_key: Lietot drošības atslēgu @@ -1596,6 +1606,9 @@ lv: over_daily_limit: Tu esi pārsniedzis šodien ieplānoto %{limit} ziņu ierobežojumu over_total_limit: Tu esi pārsniedzis ieplānoto %{limit} ziņu ierobežojumu too_soon: Ieplānotajam datumam ir jābūt nākotnē + self_destruct: + lead_html: Diemžēl domēns <strong>%{domain}</strong> tiek neatgriezeniski slēgts. Ja tev tur bija konts, tu nevarēsi turpināt to lietot, taču joprojām vari pieprasīt savu datu kopiju. + title: Šis serveris tiek slēgts sessions: activity: Pēdējā aktivitāte browser: Pārlūks diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index 41ae838b2..08e866b55 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -247,7 +247,7 @@ ja: mascot: カスタムマスコット(レガシー) media_cache_retention_period: メディアキャッシュの保持期間 peers_api_enabled: 発見したサーバーのリストをAPIで公開する - profile_directory: ディレクトリを有効にする + profile_directory: プロフィール一覧を有効にする registrations_mode: 新規登録が可能な人 require_invite_text: 申請事由の入力を必須にする show_domain_blocks: ドメインブロックを表示 @@ -258,7 +258,7 @@ ja: site_short_description: サーバーの説明 site_terms: プライバシーポリシー site_title: サーバーの名前 - status_page_url: ステータスページのURL + status_page_url: サーバーの状態ページのURL theme: デフォルトテーマ thumbnail: サーバーのサムネイル timeline_preview: 公開タイムラインへの未認証のアクセスを許可する From 9dc3ce878b51ab80b19365b2a74101cb3e5a8903 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 10 Nov 2023 10:13:42 -0500 Subject: [PATCH 005/255] Speed-up in `Settings::` controllers specs (#27808) --- .../settings/aliases_controller_spec.rb | 5 +- .../settings/applications_controller_spec.rb | 66 ++++++------------ .../settings/deletes_controller_spec.rb | 21 +----- .../settings/exports_controller_spec.rb | 5 +- .../settings/imports_controller_spec.rb | 69 ++++--------------- .../login_activities_controller_spec.rb | 5 +- .../migration/redirects_controller_spec.rb | 5 +- .../settings/migrations_controller_spec.rb | 21 +++--- .../preferences/appearance_controller_spec.rb | 5 +- .../notifications_controller_spec.rb | 5 +- .../preferences/other_controller_spec.rb | 5 +- .../settings/profiles_controller_spec.rb | 5 +- .../webauthn_credentials_controller_spec.rb | 59 +++------------- ..._authentication_methods_controller_spec.rb | 5 +- 14 files changed, 65 insertions(+), 216 deletions(-) diff --git a/spec/controllers/settings/aliases_controller_spec.rb b/spec/controllers/settings/aliases_controller_spec.rb index 9636c1ac5..18e568be0 100644 --- a/spec/controllers/settings/aliases_controller_spec.rb +++ b/spec/controllers/settings/aliases_controller_spec.rb @@ -17,11 +17,8 @@ describe Settings::AliasesController do get :index end - it 'returns http success' do + it 'returns http success with private cache control headers', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end end diff --git a/spec/controllers/settings/applications_controller_spec.rb b/spec/controllers/settings/applications_controller_spec.rb index 169304b3e..ccbb63491 100644 --- a/spec/controllers/settings/applications_controller_spec.rb +++ b/spec/controllers/settings/applications_controller_spec.rb @@ -18,11 +18,8 @@ describe Settings::ApplicationsController do get :index end - it 'returns http success' do + it 'returns http success with private cache control headers', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end end @@ -51,7 +48,7 @@ describe Settings::ApplicationsController do describe 'POST #create' do context 'when success (passed scopes as a String)' do - def call_create + subject do post :create, params: { doorkeeper_application: { name: 'My New App', @@ -60,20 +57,16 @@ describe Settings::ApplicationsController do scopes: 'read write follow', }, } - response end - it 'creates an entry in the database' do - expect { call_create }.to change(Doorkeeper::Application, :count) - end - - it 'redirects back to applications page' do - expect(call_create).to redirect_to(settings_applications_path) + it 'creates an entry in the database', :aggregate_failures do + expect { subject }.to change(Doorkeeper::Application, :count) + expect(response).to redirect_to(settings_applications_path) end end context 'when success (passed scopes as an Array)' do - def call_create + subject do post :create, params: { doorkeeper_application: { name: 'My New App', @@ -82,15 +75,11 @@ describe Settings::ApplicationsController do scopes: %w(read write follow), }, } - response end - it 'creates an entry in the database' do - expect { call_create }.to change(Doorkeeper::Application, :count) - end - - it 'redirects back to applications page' do - expect(call_create).to redirect_to(settings_applications_path) + it 'creates an entry in the database', :aggregate_failures do + expect { subject }.to change(Doorkeeper::Application, :count) + expect(response).to redirect_to(settings_applications_path) end end @@ -106,11 +95,8 @@ describe Settings::ApplicationsController do } end - it 'returns http success' do + it 'returns http success and renders form', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'renders form again' do expect(response).to render_template(:new) end end @@ -118,13 +104,7 @@ describe Settings::ApplicationsController do describe 'PATCH #update' do context 'when success' do - let(:opts) do - { - website: 'https://foo.bar/', - } - end - - def call_update + subject do patch :update, params: { id: app.id, doorkeeper_application: opts, @@ -132,13 +112,17 @@ describe Settings::ApplicationsController do response end - it 'updates existing application' do - call_update - expect(app.reload.website).to eql(opts[:website]) + let(:opts) do + { + website: 'https://foo.bar/', + } end - it 'redirects back to applications page' do - expect(call_update).to redirect_to(settings_application_path(app)) + it 'updates existing application' do + subject + + expect(app.reload.website).to eql(opts[:website]) + expect(response).to redirect_to(settings_application_path(app)) end end @@ -155,11 +139,8 @@ describe Settings::ApplicationsController do } end - it 'returns http success' do + it 'returns http success and renders form', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'renders form again' do expect(response).to render_template(:show) end end @@ -170,11 +151,8 @@ describe Settings::ApplicationsController do post :destroy, params: { id: app.id } end - it 'redirects back to applications page' do + it 'redirects back to applications page and removes the app' do expect(response).to redirect_to(settings_applications_path) - end - - it 'removes the app' do expect(Doorkeeper::Application.find_by(id: app.id)).to be_nil end end diff --git a/spec/controllers/settings/deletes_controller_spec.rb b/spec/controllers/settings/deletes_controller_spec.rb index 7ee18f9fb..2c1532ecd 100644 --- a/spec/controllers/settings/deletes_controller_spec.rb +++ b/spec/controllers/settings/deletes_controller_spec.rb @@ -14,22 +14,16 @@ describe Settings::DeletesController do get :show end - it 'renders confirmation page' do + it 'renders confirmation page with private cache control headers', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end context 'when suspended' do let(:user) { Fabricate(:user, account_attributes: { suspended_at: Time.now.utc }) } - it 'returns http forbidden' do + it 'returns http forbidden with private cache control headers', :aggregate_failures do expect(response).to have_http_status(403) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end end @@ -56,19 +50,10 @@ describe Settings::DeletesController do delete :destroy, params: { form_delete_confirmation: { password: 'petsmoldoggos' } } end - it 'redirects to sign in page' do + it 'removes user record and redirects', :aggregate_failures do expect(response).to redirect_to '/auth/sign_in' - end - - it 'removes user record' do expect(User.find_by(id: user.id)).to be_nil - end - - it 'marks account as suspended' do expect(user.account.reload).to be_suspended - end - - it 'does not create an email block' do expect(CanonicalEmailBlock.block?(user.email)).to be false end diff --git a/spec/controllers/settings/exports_controller_spec.rb b/spec/controllers/settings/exports_controller_spec.rb index 6a4202131..c8c11c3be 100644 --- a/spec/controllers/settings/exports_controller_spec.rb +++ b/spec/controllers/settings/exports_controller_spec.rb @@ -14,11 +14,8 @@ describe Settings::ExportsController do get :show end - it 'returns http success' do + it 'returns http success with private cache control headers', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end end diff --git a/spec/controllers/settings/imports_controller_spec.rb b/spec/controllers/settings/imports_controller_spec.rb index 900d0eb90..1e7b75893 100644 --- a/spec/controllers/settings/imports_controller_spec.rb +++ b/spec/controllers/settings/imports_controller_spec.rb @@ -19,15 +19,9 @@ RSpec.describe Settings::ImportsController do get :index end - it 'assigns the expected imports' do - expect(assigns(:recent_imports)).to eq [import] - end - - it 'returns http success' do + it 'assigns the expected imports', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do + expect(assigns(:recent_imports)).to eq [import] expect(response.headers['Cache-Control']).to include('private, no-store') end end @@ -72,17 +66,10 @@ RSpec.describe Settings::ImportsController do context 'with someone else\'s import' do let(:bulk_import) { Fabricate(:bulk_import, state: :unconfirmed) } - it 'does not change the import\'s state' do + it 'does not change the import\'s state and returns missing', :aggregate_failures do expect { subject }.to_not(change { bulk_import.reload.state }) - end - it 'does not fire the import worker' do - subject expect(BulkImportWorker).to_not have_received(:perform_async) - end - - it 'returns http not found' do - subject expect(response).to have_http_status(404) end end @@ -90,17 +77,10 @@ RSpec.describe Settings::ImportsController do context 'with an already-confirmed import' do let(:bulk_import) { Fabricate(:bulk_import, account: user.account, state: :in_progress) } - it 'does not change the import\'s state' do + it 'does not change the import\'s state and returns missing', :aggregate_failures do expect { subject }.to_not(change { bulk_import.reload.state }) - end - it 'does not fire the import worker' do - subject expect(BulkImportWorker).to_not have_received(:perform_async) - end - - it 'returns http not found' do - subject expect(response).to have_http_status(404) end end @@ -108,17 +88,10 @@ RSpec.describe Settings::ImportsController do context 'with an unconfirmed import' do let(:bulk_import) { Fabricate(:bulk_import, account: user.account, state: :unconfirmed) } - it 'changes the import\'s state to scheduled' do + it 'changes the import\'s state to scheduled and redirects', :aggregate_failures do expect { subject }.to change { bulk_import.reload.state.to_sym }.from(:unconfirmed).to(:scheduled) - end - it 'fires the import worker on the expected import' do - subject expect(BulkImportWorker).to have_received(:perform_async).with(bulk_import.id) - end - - it 'redirects to imports path' do - subject expect(response).to redirect_to(settings_imports_path) end end @@ -130,12 +103,9 @@ RSpec.describe Settings::ImportsController do context 'with someone else\'s import' do let(:bulk_import) { Fabricate(:bulk_import, state: :unconfirmed) } - it 'does not delete the import' do + it 'does not delete the import and returns missing', :aggregate_failures do expect { subject }.to_not(change { BulkImport.exists?(bulk_import.id) }) - end - it 'returns http not found' do - subject expect(response).to have_http_status(404) end end @@ -143,12 +113,9 @@ RSpec.describe Settings::ImportsController do context 'with an already-confirmed import' do let(:bulk_import) { Fabricate(:bulk_import, account: user.account, state: :in_progress) } - it 'does not delete the import' do + it 'does not delete the import and returns missing', :aggregate_failures do expect { subject }.to_not(change { BulkImport.exists?(bulk_import.id) }) - end - it 'returns http not found' do - subject expect(response).to have_http_status(404) end end @@ -156,12 +123,9 @@ RSpec.describe Settings::ImportsController do context 'with an unconfirmed import' do let(:bulk_import) { Fabricate(:bulk_import, account: user.account, state: :unconfirmed) } - it 'deletes the import' do + it 'deletes the import and redirects', :aggregate_failures do expect { subject }.to change { BulkImport.exists?(bulk_import.id) }.from(true).to(false) - end - it 'redirects to imports path' do - subject expect(response).to redirect_to(settings_imports_path) end end @@ -177,13 +141,10 @@ RSpec.describe Settings::ImportsController do bulk_import.update(total_items: bulk_import.rows.count, processed_items: bulk_import.rows.count, imported_items: 0) end - it 'returns http success' do + it 'returns expected contents', :aggregate_failures do subject - expect(response).to have_http_status(200) - end - it 'returns expected contents' do - subject + expect(response).to have_http_status(200) expect(response.body).to eq expected_contents end end @@ -283,12 +244,9 @@ RSpec.describe Settings::ImportsController do let(:import_file) { file } let(:import_mode) { mode } - it 'creates an unconfirmed bulk_import with expected type' do + it 'creates an unconfirmed bulk_import with expected type and redirects', :aggregate_failures do expect { subject }.to change { user.account.bulk_imports.pluck(:state, :type) }.from([]).to([['unconfirmed', import_type]]) - end - it 'redirects to confirmation page for the import' do - subject expect(response).to redirect_to(settings_import_path(user.account.bulk_imports.first)) end end @@ -298,12 +256,9 @@ RSpec.describe Settings::ImportsController do let(:import_file) { file } let(:import_mode) { mode } - it 'does not creates an unconfirmed bulk_import' do + it 'does not creates an unconfirmed bulk_import', :aggregate_failures do expect { subject }.to_not(change { user.account.bulk_imports.count }) - end - it 'sets error to the import' do - subject expect(assigns(:import).errors).to_not be_empty end end diff --git a/spec/controllers/settings/login_activities_controller_spec.rb b/spec/controllers/settings/login_activities_controller_spec.rb index 80c8f484c..4f266e03d 100644 --- a/spec/controllers/settings/login_activities_controller_spec.rb +++ b/spec/controllers/settings/login_activities_controller_spec.rb @@ -16,11 +16,8 @@ describe Settings::LoginActivitiesController do get :index end - it 'returns http success' do + it 'returns http success with private cache control headers', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end end diff --git a/spec/controllers/settings/migration/redirects_controller_spec.rb b/spec/controllers/settings/migration/redirects_controller_spec.rb index aa6df64cf..b909a0266 100644 --- a/spec/controllers/settings/migration/redirects_controller_spec.rb +++ b/spec/controllers/settings/migration/redirects_controller_spec.rb @@ -16,11 +16,8 @@ describe Settings::Migration::RedirectsController do get :new end - it 'returns http success' do + it 'returns http success with private cache control headers', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end end diff --git a/spec/controllers/settings/migrations_controller_spec.rb b/spec/controllers/settings/migrations_controller_spec.rb index 9b12bc40f..f3340574d 100644 --- a/spec/controllers/settings/migrations_controller_spec.rb +++ b/spec/controllers/settings/migrations_controller_spec.rb @@ -71,24 +71,22 @@ describe Settings::MigrationsController do context 'when acct is the current account' do let(:acct) { user.account } - it 'renders show' do - expect(subject).to render_template :show - end + it 'does not update the moved account', :aggregate_failures do + subject - it 'does not update the moved account' do expect(user.account.reload.moved_to_account_id).to be_nil + expect(response).to render_template :show end end context 'when target account does not reference the account being moved from' do let(:acct) { Fabricate(:account, also_known_as: []) } - it 'renders show' do - expect(subject).to render_template :show - end + it 'does not update the moved account', :aggregate_failures do + subject - it 'does not update the moved account' do expect(user.account.reload.moved_to_account_id).to be_nil + expect(response).to render_template :show end end @@ -100,12 +98,11 @@ describe Settings::MigrationsController do user.account.migrations.create!(acct: moved_to.acct) end - it 'renders show' do - expect(subject).to render_template :show - end + it 'does not update the moved account', :aggregate_failures do + subject - it 'does not update the moved account' do expect(user.account.reload.moved_to_account_id).to be_nil + expect(response).to render_template :show end end end diff --git a/spec/controllers/settings/preferences/appearance_controller_spec.rb b/spec/controllers/settings/preferences/appearance_controller_spec.rb index 9a98a4188..ee0ded1b9 100644 --- a/spec/controllers/settings/preferences/appearance_controller_spec.rb +++ b/spec/controllers/settings/preferences/appearance_controller_spec.rb @@ -16,11 +16,8 @@ describe Settings::Preferences::AppearanceController do get :show end - it 'returns http success' do + it 'returns http success with private cache control headers', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end end diff --git a/spec/controllers/settings/preferences/notifications_controller_spec.rb b/spec/controllers/settings/preferences/notifications_controller_spec.rb index 6a04df9ed..b61d7461c 100644 --- a/spec/controllers/settings/preferences/notifications_controller_spec.rb +++ b/spec/controllers/settings/preferences/notifications_controller_spec.rb @@ -16,11 +16,8 @@ describe Settings::Preferences::NotificationsController do get :show end - it 'returns http success' do + it 'returns http success with private cache control headers', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end end diff --git a/spec/controllers/settings/preferences/other_controller_spec.rb b/spec/controllers/settings/preferences/other_controller_spec.rb index 750510b04..61a94a414 100644 --- a/spec/controllers/settings/preferences/other_controller_spec.rb +++ b/spec/controllers/settings/preferences/other_controller_spec.rb @@ -16,11 +16,8 @@ describe Settings::Preferences::OtherController do get :show end - it 'returns http success' do + it 'returns http success with private cache control headers', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end end diff --git a/spec/controllers/settings/profiles_controller_spec.rb b/spec/controllers/settings/profiles_controller_spec.rb index 806fad19a..e3197f0a6 100644 --- a/spec/controllers/settings/profiles_controller_spec.rb +++ b/spec/controllers/settings/profiles_controller_spec.rb @@ -17,11 +17,8 @@ RSpec.describe Settings::ProfilesController do get :show end - it 'returns http success' do + it 'returns http success with private cache control headers', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end end diff --git a/spec/controllers/settings/two_factor_authentication/webauthn_credentials_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/webauthn_credentials_controller_spec.rb index 2ffad13c6..719ed2f88 100644 --- a/spec/controllers/settings/two_factor_authentication/webauthn_credentials_controller_spec.rb +++ b/spec/controllers/settings/two_factor_authentication/webauthn_credentials_controller_spec.rb @@ -121,24 +121,12 @@ describe Settings::TwoFactorAuthentication::WebauthnCredentialsController do add_webauthn_credential(user) end - it 'returns http success' do - get :options + it 'includes existing credentials in list of excluded credentials', :aggregate_failures do + expect { get :options }.to_not change(user, :webauthn_id) expect(response).to have_http_status(200) - end - - it 'stores the challenge on the session' do - get :options expect(controller.session[:webauthn_challenge]).to be_present - end - - it 'does not change webauthn_id' do - expect { get :options }.to_not change(user, :webauthn_id) - end - - it 'includes existing credentials in list of excluded credentials' do - get :options excluded_credentials_ids = response.parsed_body['excludeCredentials'].pluck('id') expect(excluded_credentials_ids).to match_array(user.webauthn_credentials.pluck(:external_id)) @@ -146,21 +134,11 @@ describe Settings::TwoFactorAuthentication::WebauthnCredentialsController do end context 'when user does not have webauthn enabled' do - it 'returns http success' do + it 'stores the challenge on the session and sets user webauthn_id', :aggregate_failures do get :options expect(response).to have_http_status(200) - end - - it 'stores the challenge on the session' do - get :options - expect(controller.session[:webauthn_challenge]).to be_present - end - - it 'sets user webauthn_id' do - get :options - expect(user.reload.webauthn_id).to be_present end end @@ -217,28 +195,15 @@ describe Settings::TwoFactorAuthentication::WebauthnCredentialsController do end context 'when creation succeeds' do - it 'returns http success' do - controller.session[:webauthn_challenge] = challenge - - post :create, params: { credential: new_webauthn_credential, nickname: nickname } - - expect(response).to have_http_status(200) - end - - it 'adds a new credential to user credentials' do + it 'adds a new credential to user credentials and does not change webauthn_id', :aggregate_failures do controller.session[:webauthn_challenge] = challenge expect do post :create, params: { credential: new_webauthn_credential, nickname: nickname } end.to change { user.webauthn_credentials.count }.by(1) - end + .and not_change(user, :webauthn_id) - it 'does not change webauthn_id' do - controller.session[:webauthn_challenge] = challenge - - expect do - post :create, params: { credential: new_webauthn_credential, nickname: nickname } - end.to_not change(user, :webauthn_id) + expect(response).to have_http_status(200) end end @@ -328,17 +293,13 @@ describe Settings::TwoFactorAuthentication::WebauthnCredentialsController do end context 'when deletion succeeds' do - it 'redirects to 2FA methods list and shows flash success' do - delete :destroy, params: { id: user.webauthn_credentials.take.id } - - expect(response).to redirect_to settings_two_factor_authentication_methods_path - expect(flash[:success]).to be_present - end - - it 'deletes the credential' do + it 'redirects to 2FA methods list and shows flash success and deletes the credential', :aggregate_failures do expect do delete :destroy, params: { id: user.webauthn_credentials.take.id } end.to change { user.webauthn_credentials.count }.by(-1) + + expect(response).to redirect_to settings_two_factor_authentication_methods_path + expect(flash[:success]).to be_present end end end diff --git a/spec/controllers/settings/two_factor_authentication_methods_controller_spec.rb b/spec/controllers/settings/two_factor_authentication_methods_controller_spec.rb index 3e61912ad..de0d28463 100644 --- a/spec/controllers/settings/two_factor_authentication_methods_controller_spec.rb +++ b/spec/controllers/settings/two_factor_authentication_methods_controller_spec.rb @@ -29,11 +29,8 @@ describe Settings::TwoFactorAuthenticationMethodsController do get :index end - it 'returns http success' do + it 'returns http success with private cache control headers', :aggregate_failures do expect(response).to have_http_status(200) - end - - it 'returns private cache control headers' do expect(response.headers['Cache-Control']).to include('private, no-store') end end From 0d14fcebae0b9a0e5da73049c960064338dfee8e Mon Sep 17 00:00:00 2001 From: Eugen Rochko <eugen@zeonfederated.com> Date: Mon, 13 Nov 2023 10:58:28 +0100 Subject: [PATCH 006/255] Change link previews to keep original URL from the status (#27312) --- app/chewy/public_statuses_index.rb | 2 +- app/chewy/statuses_index.rb | 2 +- .../api/v1/conversations_controller.rb | 2 +- app/models/admin/status_batch_action.rb | 2 +- app/models/concerns/status_search_concern.rb | 2 +- app/models/preview_card.rb | 7 ++++++- app/models/preview_cards_status.rb | 18 ++++++++++++++++++ app/models/status.rb | 15 ++++++++++----- app/models/trends/links.rb | 4 +--- .../rest/preview_card_serializer.rb | 4 ++++ .../process_status_update_service.rb | 2 +- app/services/fetch_link_card_service.rb | 6 +++--- app/services/update_status_service.rb | 2 +- ...183200_add_url_to_preview_cards_statuses.rb | 7 +++++++ db/schema.rb | 3 ++- lib/tasks/tests.rake | 2 +- spec/helpers/media_component_helper_spec.rb | 4 +++- spec/services/fetch_link_card_service_spec.rb | 8 ++++---- spec/services/update_status_service_spec.rb | 8 ++++---- 19 files changed, 70 insertions(+), 30 deletions(-) create mode 100644 app/models/preview_cards_status.rb create mode 100644 db/migrate/20231006183200_add_url_to_preview_cards_statuses.rb diff --git a/app/chewy/public_statuses_index.rb b/app/chewy/public_statuses_index.rb index 4be204d4a..b5f0be5e5 100644 --- a/app/chewy/public_statuses_index.rb +++ b/app/chewy/public_statuses_index.rb @@ -53,7 +53,7 @@ class PublicStatusesIndex < Chewy::Index index_scope ::Status.unscoped .kept .indexable - .includes(:media_attachments, :preloadable_poll, :preview_cards, :tags) + .includes(:media_attachments, :preloadable_poll, :tags, preview_cards_status: :preview_card) root date_detection: false do field(:id, type: 'long') diff --git a/app/chewy/statuses_index.rb b/app/chewy/statuses_index.rb index 6b25dc9df..e315a2030 100644 --- a/app/chewy/statuses_index.rb +++ b/app/chewy/statuses_index.rb @@ -50,7 +50,7 @@ class StatusesIndex < Chewy::Index }, } - index_scope ::Status.unscoped.kept.without_reblogs.includes(:media_attachments, :preview_cards, :local_mentioned, :local_favorited, :local_reblogged, :local_bookmarked, :tags, preloadable_poll: :local_voters), delete_if: ->(status) { status.searchable_by.empty? } + index_scope ::Status.unscoped.kept.without_reblogs.includes(:media_attachments, :local_mentioned, :local_favorited, :local_reblogged, :local_bookmarked, :tags, preview_cards_status: :preview_card, preloadable_poll: :local_voters), delete_if: ->(status) { status.searchable_by.empty? } root date_detection: false do field(:id, type: 'long') diff --git a/app/controllers/api/v1/conversations_controller.rb b/app/controllers/api/v1/conversations_controller.rb index b3ca2f790..6a3567e62 100644 --- a/app/controllers/api/v1/conversations_controller.rb +++ b/app/controllers/api/v1/conversations_controller.rb @@ -41,10 +41,10 @@ class Api::V1::ConversationsController < Api::BaseController account: :account_stat, last_status: [ :media_attachments, - :preview_cards, :status_stat, :tags, { + preview_cards_status: :preview_card, active_mentions: [account: :account_stat], account: :account_stat, }, diff --git a/app/models/admin/status_batch_action.rb b/app/models/admin/status_batch_action.rb index 24c3979aa..8a8e2fa37 100644 --- a/app/models/admin/status_batch_action.rb +++ b/app/models/admin/status_batch_action.rb @@ -74,7 +74,7 @@ class Admin::StatusBatchAction # Can't use a transaction here because UpdateStatusService queues # Sidekiq jobs - statuses.includes(:media_attachments, :preview_cards).find_each do |status| + statuses.includes(:media_attachments, preview_cards_status: :preview_card).find_each do |status| next if status.discarded? || !(status.with_media? || status.with_preview_card?) authorize([:admin, status], :update?) diff --git a/app/models/concerns/status_search_concern.rb b/app/models/concerns/status_search_concern.rb index 3ef45754a..7252fde73 100644 --- a/app/models/concerns/status_search_concern.rb +++ b/app/models/concerns/status_search_concern.rb @@ -40,7 +40,7 @@ module StatusSearchConcern properties << 'media' if with_media? properties << 'poll' if with_poll? properties << 'link' if with_preview_card? - properties << 'embed' if preview_cards.any?(&:video?) + properties << 'embed' if preview_card&.video? properties << 'sensitive' if sensitive? properties << 'reply' if reply? end diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb index a1751c426..837592743 100644 --- a/app/models/preview_card.rb +++ b/app/models/preview_card.rb @@ -50,7 +50,9 @@ class PreviewCard < ApplicationRecord enum type: { link: 0, photo: 1, video: 2, rich: 3 } enum link_type: { unknown: 0, article: 1 } - has_and_belongs_to_many :statuses + has_many :preview_cards_statuses, dependent: :delete_all, inverse_of: :preview_card + has_many :statuses, through: :preview_cards_statuses + has_one :trend, class_name: 'PreviewCardTrend', inverse_of: :preview_card, dependent: :destroy has_attached_file :image, processors: [:thumbnail, :blurhash_transcoder], styles: ->(f) { image_styles(f) }, convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, validate_media_type: false @@ -64,6 +66,9 @@ class PreviewCard < ApplicationRecord before_save :extract_dimensions, if: :link? + # This can be set by the status when retrieving the preview card using the join model + attr_accessor :original_url + def appropriate_for_trends? link? && article? && title.present? && description.present? && image.present? && provider_name.present? end diff --git a/app/models/preview_cards_status.rb b/app/models/preview_cards_status.rb new file mode 100644 index 000000000..341771e4d --- /dev/null +++ b/app/models/preview_cards_status.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: preview_cards_statuses +# +# preview_card_id :bigint(8) not null +# status_id :bigint(8) not null +# url :string +# +class PreviewCardsStatus < ApplicationRecord + # Composite primary keys are not properly supported in Rails. However, + # we shouldn't need this anyway... + self.primary_key = nil + + belongs_to :preview_card + belongs_to :status +end diff --git a/app/models/status.rb b/app/models/status.rb index 1c41ef1d5..41c895029 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -79,8 +79,8 @@ class Status < ApplicationRecord has_many :local_bookmarked, -> { merge(Account.local) }, through: :bookmarks, source: :account has_and_belongs_to_many :tags - has_and_belongs_to_many :preview_cards + has_one :preview_cards_status, inverse_of: :status # Because of a composite primary key, the dependent option cannot be used has_one :notification, as: :activity, dependent: :destroy has_one :status_stat, inverse_of: :status has_one :poll, inverse_of: :status, dependent: :destroy @@ -142,24 +142,25 @@ class Status < ApplicationRecord # The `prepend: true` option below ensures this runs before # the `dependent: destroy` callbacks remove relevant records before_destroy :unlink_from_conversations!, prepend: true + before_destroy :reset_preview_card! cache_associated :application, :media_attachments, :conversation, :status_stat, :tags, - :preview_cards, :preloadable_poll, + preview_cards_status: [:preview_card], account: [:account_stat, user: :role], active_mentions: { account: :account_stat }, reblog: [ :application, :tags, - :preview_cards, :media_attachments, :conversation, :status_stat, :preloadable_poll, + preview_cards_status: [:preview_card], account: [:account_stat, user: :role], active_mentions: { account: :account_stat }, ], @@ -226,7 +227,11 @@ class Status < ApplicationRecord end def preview_card - preview_cards.first + preview_cards_status&.preview_card&.tap { |x| x.original_url = preview_cards_status.url } + end + + def reset_preview_card! + PreviewCardsStatus.where(status_id: id).delete_all end def hidden? @@ -244,7 +249,7 @@ class Status < ApplicationRecord end def with_preview_card? - preview_cards.any? + preview_cards_status.present? end def with_poll? diff --git a/app/models/trends/links.rb b/app/models/trends/links.rb index fcbdb1a5f..b4eae9f70 100644 --- a/app/models/trends/links.rb +++ b/app/models/trends/links.rb @@ -54,9 +54,7 @@ class Trends::Links < Trends::Base !(original_status.account.silenced? || status.account.silenced?) && !(original_status.spoiler_text? || original_status.sensitive?) - original_status.preview_cards.each do |preview_card| - add(preview_card, status.account_id, at_time) if preview_card.appropriate_for_trends? - end + add(original_status.preview_card, status.account_id, at_time) if original_status.preview_card&.appropriate_for_trends? end def add(preview_card, account_id, at_time = Time.now.utc) diff --git a/app/serializers/rest/preview_card_serializer.rb b/app/serializers/rest/preview_card_serializer.rb index 3e1c4bde3..039262cd5 100644 --- a/app/serializers/rest/preview_card_serializer.rb +++ b/app/serializers/rest/preview_card_serializer.rb @@ -8,6 +8,10 @@ class REST::PreviewCardSerializer < ActiveModel::Serializer :provider_url, :html, :width, :height, :image, :image_description, :embed_url, :blurhash, :published_at + def url + object.original_url.presence || object.url + end + def image object.image? ? full_asset_url(object.image.url(:original)) : nil end diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index 4ff92da01..2db0e80e7 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -280,7 +280,7 @@ class ActivityPub::ProcessStatusUpdateService < BaseService end def reset_preview_card! - @status.preview_cards.clear + @status.reset_preview_card! LinkCrawlWorker.perform_in(rand(1..59).seconds, @status.id) end diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index 13775e63c..c6b600dd7 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -19,7 +19,7 @@ class FetchLinkCardService < BaseService @status = status @original_url = parse_urls - return if @original_url.nil? || @status.preview_cards.any? + return if @original_url.nil? || @status.with_preview_card? @url = @original_url.to_s @@ -62,9 +62,9 @@ class FetchLinkCardService < BaseService def attach_card with_redis_lock("attach_card:#{@status.id}") do - return if @status.preview_cards.any? + return if @status.with_preview_card? - @status.preview_cards << @card + PreviewCardsStatus.create(status: @status, preview_card: @card, url: @original_url) Rails.cache.delete(@status) Trends.links.register(@status) end diff --git a/app/services/update_status_service.rb b/app/services/update_status_service.rb index d1c2b990f..cdfe28365 100644 --- a/app/services/update_status_service.rb +++ b/app/services/update_status_service.rb @@ -123,7 +123,7 @@ class UpdateStatusService < BaseService def reset_preview_card! return unless @status.text_previously_changed? - @status.preview_cards.clear + @status.reset_preview_card! LinkCrawlWorker.perform_async(@status.id) end diff --git a/db/migrate/20231006183200_add_url_to_preview_cards_statuses.rb b/db/migrate/20231006183200_add_url_to_preview_cards_statuses.rb new file mode 100644 index 000000000..f7c6de462 --- /dev/null +++ b/db/migrate/20231006183200_add_url_to_preview_cards_statuses.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddURLToPreviewCardsStatuses < ActiveRecord::Migration[7.0] + def change + add_column :preview_cards_statuses, :url, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 37020c2d7..a0062c8ce 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_09_07_150100) do +ActiveRecord::Schema[7.0].define(version: 2023_10_06_183200) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -811,6 +811,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_09_07_150100) do create_table "preview_cards_statuses", primary_key: ["status_id", "preview_card_id"], force: :cascade do |t| t.bigint "preview_card_id", null: false t.bigint "status_id", null: false + t.string "url" end create_table "relays", force: :cascade do |t| diff --git a/lib/tasks/tests.rake b/lib/tasks/tests.rake index 7f8e72dd8..209a73efa 100644 --- a/lib/tasks/tests.rake +++ b/lib/tasks/tests.rake @@ -69,7 +69,7 @@ namespace :tests do exit(1) end - unless Status.find(12).preview_cards.pluck(:url) == ['https://joinmastodon.org/'] + unless PreviewCard.where(id: PreviewCardsStatus.where(status_id: 12).select(:preview_card_id)).pluck(:url) == ['https://joinmastodon.org/'] puts 'Preview cards not deduplicated as expected' exit(1) end diff --git a/spec/helpers/media_component_helper_spec.rb b/spec/helpers/media_component_helper_spec.rb index 71a9af6f3..149f6a83a 100644 --- a/spec/helpers/media_component_helper_spec.rb +++ b/spec/helpers/media_component_helper_spec.rb @@ -49,10 +49,12 @@ describe MediaComponentHelper do end describe 'render_card_component' do - let(:status) { Fabricate(:status, preview_cards: [Fabricate(:preview_card)]) } + let(:status) { Fabricate(:status) } let(:result) { helper.render_card_component(status) } before do + PreviewCardsStatus.create(status: status, preview_card: Fabricate(:preview_card)) + without_partial_double_verification do allow(helper).to receive(:current_account).and_return(status.account) end diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb index f44cbb750..d8ca310b2 100644 --- a/spec/services/fetch_link_card_service_spec.rb +++ b/spec/services/fetch_link_card_service_spec.rb @@ -120,7 +120,7 @@ RSpec.describe FetchLinkCardService, type: :service do let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis') } it 'decodes the HTML' do - expect(status.preview_cards.first.title).to eq('SJISのページ') + expect(status.preview_card.title).to eq('SJISのページ') end end @@ -128,7 +128,7 @@ RSpec.describe FetchLinkCardService, type: :service do let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis_with_wrong_charset') } it 'decodes the HTML despite the wrong charset header' do - expect(status.preview_cards.first.title).to eq('SJISのページ') + expect(status.preview_card.title).to eq('SJISのページ') end end @@ -136,7 +136,7 @@ RSpec.describe FetchLinkCardService, type: :service do let(:status) { Fabricate(:status, text: 'Check out http://example.com/koi8-r') } it 'decodes the HTML' do - expect(status.preview_cards.first.title).to eq('Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.') + expect(status.preview_card.title).to eq('Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.') end end @@ -144,7 +144,7 @@ RSpec.describe FetchLinkCardService, type: :service do let(:status) { Fabricate(:status, text: 'Check out http://example.com/windows-1251') } it 'decodes the HTML' do - expect(status.preview_cards.first.title).to eq('сэмпл текст') + expect(status.preview_card.title).to eq('сэмпл текст') end end diff --git a/spec/services/update_status_service_spec.rb b/spec/services/update_status_service_spec.rb index 9c53ebb2f..eb38230b0 100644 --- a/spec/services/update_status_service_spec.rb +++ b/spec/services/update_status_service_spec.rb @@ -23,11 +23,11 @@ RSpec.describe UpdateStatusService, type: :service do end context 'when text changes' do - let!(:status) { Fabricate(:status, text: 'Foo') } + let(:status) { Fabricate(:status, text: 'Foo') } let(:preview_card) { Fabricate(:preview_card) } before do - status.preview_cards << preview_card + PreviewCardsStatus.create(status: status, preview_card: preview_card) subject.call(status, status.account_id, text: 'Bar') end @@ -45,11 +45,11 @@ RSpec.describe UpdateStatusService, type: :service do end context 'when content warning changes' do - let!(:status) { Fabricate(:status, text: 'Foo', spoiler_text: '') } + let(:status) { Fabricate(:status, text: 'Foo', spoiler_text: '') } let(:preview_card) { Fabricate(:preview_card) } before do - status.preview_cards << preview_card + PreviewCardsStatus.create(status: status, preview_card: preview_card) subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar') end From da4f37020b6ef15235fd5bcaf3ed7cd2fd15437f Mon Sep 17 00:00:00 2001 From: Renaud Chaput <renchap@gmail.com> Date: Mon, 13 Nov 2023 13:19:41 +0100 Subject: [PATCH 007/255] Fix Jest config (#27834) --- .watchmanconfig | 3 +++ jest.config.js | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 .watchmanconfig diff --git a/.watchmanconfig b/.watchmanconfig new file mode 100644 index 000000000..29e4f231e --- /dev/null +++ b/.watchmanconfig @@ -0,0 +1,3 @@ +{ + "ignore_dirs": ["node_modules/", "public/"] +} diff --git a/jest.config.js b/jest.config.js index 83eae46cb..b4a34a5ab 100644 --- a/jest.config.js +++ b/jest.config.js @@ -19,7 +19,7 @@ const config = { // Those packages are ESM, so we need them to be processed by Babel transformIgnorePatterns: ['/node_modules/(?!(redent|strip-indent)/)'], coverageDirectory: '<rootDir>/coverage', - moduleDirectories: ['<rootDir>/node_modules', '<rootDir>/app/javascript'], + moduleDirectories: ['node_modules', '<rootDir>/app/javascript'], moduleNameMapper: { '\\.svg$': '<rootDir>/app/javascript/__mocks__/svg.js', }, From 3b989e4d644d2c5e1b191e2740cd700cf9dc291d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:13:53 +0100 Subject: [PATCH 008/255] Update dependency rails to v7.1.2 (#27812) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 121 ++++++++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 83693812f..84ad19b80 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -39,50 +39,51 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (7.1.1) - actionpack (= 7.1.1) - activesupport (= 7.1.1) + actioncable (7.1.2) + actionpack (= 7.1.2) + activesupport (= 7.1.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.1) - actionpack (= 7.1.1) - activejob (= 7.1.1) - activerecord (= 7.1.1) - activestorage (= 7.1.1) - activesupport (= 7.1.1) + actionmailbox (7.1.2) + actionpack (= 7.1.2) + activejob (= 7.1.2) + activerecord (= 7.1.2) + activestorage (= 7.1.2) + activesupport (= 7.1.2) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.1.1) - actionpack (= 7.1.1) - actionview (= 7.1.1) - activejob (= 7.1.1) - activesupport (= 7.1.1) + actionmailer (7.1.2) + actionpack (= 7.1.2) + actionview (= 7.1.2) + activejob (= 7.1.2) + activesupport (= 7.1.2) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.2) - actionpack (7.1.1) - actionview (= 7.1.1) - activesupport (= 7.1.1) + actionpack (7.1.2) + actionview (= 7.1.2) + activesupport (= 7.1.2) nokogiri (>= 1.8.5) + racc rack (>= 2.2.4) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.1) - actionpack (= 7.1.1) - activerecord (= 7.1.1) - activestorage (= 7.1.1) - activesupport (= 7.1.1) + actiontext (7.1.2) + actionpack (= 7.1.2) + activerecord (= 7.1.2) + activestorage (= 7.1.2) + activesupport (= 7.1.2) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.1) - activesupport (= 7.1.1) + actionview (7.1.2) + activesupport (= 7.1.2) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) @@ -92,22 +93,22 @@ GEM activemodel (>= 4.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - activejob (7.1.1) - activesupport (= 7.1.1) + activejob (7.1.2) + activesupport (= 7.1.2) globalid (>= 0.3.6) - activemodel (7.1.1) - activesupport (= 7.1.1) - activerecord (7.1.1) - activemodel (= 7.1.1) - activesupport (= 7.1.1) + activemodel (7.1.2) + activesupport (= 7.1.2) + activerecord (7.1.2) + activemodel (= 7.1.2) + activesupport (= 7.1.2) timeout (>= 0.4.0) - activestorage (7.1.1) - actionpack (= 7.1.1) - activejob (= 7.1.1) - activerecord (= 7.1.1) - activesupport (= 7.1.1) + activestorage (7.1.2) + actionpack (= 7.1.2) + activejob (= 7.1.2) + activerecord (= 7.1.2) + activesupport (= 7.1.2) marcel (~> 1.0) - activesupport (7.1.1) + activesupport (7.1.2) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -218,7 +219,7 @@ GEM activerecord (>= 5.a) database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) - date (3.3.3) + date (3.3.4) debug_inspector (1.1.0) devise (4.9.3) bcrypt (~> 3.0) @@ -369,7 +370,7 @@ GEM terminal-table (>= 1.5.1) idn-ruby (0.1.5) io-console (0.6.0) - irb (1.8.1) + irb (1.8.3) rdoc reline (>= 0.3.8) jmespath (1.6.2) @@ -462,13 +463,13 @@ GEM uri net-http-persistent (4.0.2) connection_pool (~> 2.2) - net-imap (0.4.1) + net-imap (0.4.4) date net-protocol net-ldap (0.18.0) net-pop (0.1.2) net-protocol - net-protocol (0.2.1) + net-protocol (0.2.2) timeout net-smtp (0.4.0) net-protocol @@ -526,7 +527,7 @@ GEM net-smtp premailer (~> 1.7, >= 1.7.9) private_address_check (0.5.0) - psych (5.1.1) + psych (5.1.1.1) stringio public_suffix (5.0.3) puma (6.4.0) @@ -557,20 +558,20 @@ GEM rackup (1.0.0) rack (< 3) webrick - rails (7.1.1) - actioncable (= 7.1.1) - actionmailbox (= 7.1.1) - actionmailer (= 7.1.1) - actionpack (= 7.1.1) - actiontext (= 7.1.1) - actionview (= 7.1.1) - activejob (= 7.1.1) - activemodel (= 7.1.1) - activerecord (= 7.1.1) - activestorage (= 7.1.1) - activesupport (= 7.1.1) + rails (7.1.2) + actioncable (= 7.1.2) + actionmailbox (= 7.1.2) + actionmailer (= 7.1.2) + actionpack (= 7.1.2) + actiontext (= 7.1.2) + actionview (= 7.1.2) + activejob (= 7.1.2) + activemodel (= 7.1.2) + activerecord (= 7.1.2) + activestorage (= 7.1.2) + activesupport (= 7.1.2) bundler (>= 1.15.0) - railties (= 7.1.1) + railties (= 7.1.2) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -585,9 +586,9 @@ GEM rails-i18n (7.0.8) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - railties (7.1.1) - actionpack (= 7.1.1) - activesupport (= 7.1.1) + railties (7.1.2) + actionpack (= 7.1.2) + activesupport (= 7.1.2) irb rackup (>= 1.0.0) rake (>= 12.2) @@ -737,7 +738,7 @@ GEM statsd-ruby (1.5.0) stoplight (3.0.2) redlock (~> 1.0) - stringio (3.0.8) + stringio (3.0.9) strong_migrations (1.6.4) activerecord (>= 5.2) swd (1.3.0) @@ -753,7 +754,7 @@ GEM test-prof (1.2.3) thor (1.3.0) tilt (2.3.0) - timeout (0.4.0) + timeout (0.4.1) tpm-key_attestation (0.12.0) bindata (~> 2.4) openssl (> 2.0) From a7117bbef635735d4f01fc2fb6eaa085568862fa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:13:57 +0100 Subject: [PATCH 009/255] Update dependency @rails/ujs to v7.1.2 (#27811) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4c70859d0..0058a6837 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2661,9 +2661,9 @@ __metadata: linkType: hard "@rails/ujs@npm:^7.1.1": - version: 7.1.1 - resolution: "@rails/ujs@npm:7.1.1" - checksum: 79aa50400097d9254e194979cc011aaa92b456631fd0087a7bfc6b74ff47821c005b34a0fbb421361741c68133ac9bb35f1bb8f97de1c501144dad4e2c7440f3 + version: 7.1.2 + resolution: "@rails/ujs@npm:7.1.2" + checksum: 072962733c371fa0fff5e88a0aecd8e91c892f9dc2d31723b7586b45c723206d6b82ac71b0d7db26ea0a5ce60e0832430b061e4669b8f2aa813c3ea975aac98a languageName: node linkType: hard From e5a7b73ef4ca8934bb967d15d17c8ee1bd1c2cf0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:21:02 +0100 Subject: [PATCH 010/255] New Crowdin Translations (automated) (#27815) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/be.json | 1 + app/javascript/mastodon/locales/et.json | 1 + app/javascript/mastodon/locales/fa.json | 5 +- app/javascript/mastodon/locales/fi.json | 1 + app/javascript/mastodon/locales/fo.json | 1 + app/javascript/mastodon/locales/ig.json | 18 +++ app/javascript/mastodon/locales/ja.json | 4 +- app/javascript/mastodon/locales/ko.json | 1 + app/javascript/mastodon/locales/lt.json | 13 ++- app/javascript/mastodon/locales/no.json | 1 + app/javascript/mastodon/locales/pt-BR.json | 1 + app/javascript/mastodon/locales/pt-PT.json | 1 + app/javascript/mastodon/locales/vi.json | 1 + config/locales/doorkeeper.lt.yml | 128 ++++++++++++++++++++- config/locales/fa.yml | 8 +- config/locales/ig.yml | 4 + config/locales/ja.yml | 2 +- config/locales/ko.yml | 4 +- config/locales/nn.yml | 8 ++ config/locales/no.yml | 17 +++ config/locales/simple_form.he.yml | 2 +- config/locales/simple_form.no.yml | 1 + 22 files changed, 210 insertions(+), 13 deletions(-) diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 6262d24e2..7c2d652b6 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Вынікі пошуку", "emoji_button.symbols": "Сімвалы", "emoji_button.travel": "Падарожжы і месцы", + "empty_column.account_hides_collections": "Гэты карыстальнік вырашыў схаваць гэтую інфармацыю", "empty_column.account_suspended": "Уліковы запіс прыпынены", "empty_column.account_timeline": "Тут няма допісаў!", "empty_column.account_unavailable": "Профіль недаступны", diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index 0b0a8110d..c4182a073 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Otsitulemused", "emoji_button.symbols": "Sümbolid", "emoji_button.travel": "Reisimine & kohad", + "empty_column.account_hides_collections": "See kasutaja otsustas mitte teha seda infot saadavaks", "empty_column.account_suspended": "Konto kustutatud", "empty_column.account_timeline": "Siin postitusi ei ole!", "empty_column.account_unavailable": "Profiil pole saadaval", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index f4a2e09e7..246f21899 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "نتایج جستوجو", "emoji_button.symbols": "نمادها", "emoji_button.travel": "سفر و مکان", + "empty_column.account_hides_collections": "کاربر خواسته که این اطّلاعات در دسترس نباشند", "empty_column.account_suspended": "حساب معلق شد", "empty_column.account_timeline": "هیچ فرستهای اینجا نیست!", "empty_column.account_unavailable": "نمایهٔ موجود نیست", @@ -358,13 +359,13 @@ "keyboard_shortcuts.profile": "گشودن نمایهٔ نویسنده", "keyboard_shortcuts.reply": "پاسخ به فرسته", "keyboard_shortcuts.requests": "گشودن سیاههٔ درخواستهای پیگیری", - "keyboard_shortcuts.search": "تمرکز روی جستوجو", + "keyboard_shortcuts.search": "تمرکز روی نوار جستوجو", "keyboard_shortcuts.spoilers": "نمایش/نهفتن زمینهٔ هشدار محتوا", "keyboard_shortcuts.start": "گشودن ستون «آغاز کنید»", "keyboard_shortcuts.toggle_hidden": "نمایش/نهفتن نوشتهٔ پشت هشدار محتوا", "keyboard_shortcuts.toggle_sensitivity": "نمایش/نهفتن رسانه", "keyboard_shortcuts.toot": "شروع یک فرستهٔ جدید", - "keyboard_shortcuts.unfocus": "برداشتن تمرکز از نوشتن/جستوجو", + "keyboard_shortcuts.unfocus": "برداشتن تمرکز از ناحیهٔ نوشتن یا جستوجو", "keyboard_shortcuts.up": "بالا بردن در سیاهه", "lightbox.close": "بستن", "lightbox.compress": "فشردهسازی جعبهٔ نمایش تصویر", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index cc4a9391a..9aa2e7355 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Hakutulokset", "emoji_button.symbols": "Symbolit", "emoji_button.travel": "Matkailu ja paikat", + "empty_column.account_hides_collections": "Käyttäjä on päättänyt olla julkaisematta näitä tietoja", "empty_column.account_suspended": "Tili jäädytetty", "empty_column.account_timeline": "Ei viestejä täällä.", "empty_column.account_unavailable": "Profiilia ei löydy", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index d6130deb0..42a1317db 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Leitiúrslit", "emoji_button.symbols": "Ímyndir", "emoji_button.travel": "Ferðing og støð", + "empty_column.account_hides_collections": "Hesin brúkarin hevur valt, at hesar upplýsingarnar ikki skulu vera tøkar", "empty_column.account_suspended": "Kontan gjørd óvirkin", "empty_column.account_timeline": "Einki uppslag her!", "empty_column.account_unavailable": "Vangin er ikki tøkur", diff --git a/app/javascript/mastodon/locales/ig.json b/app/javascript/mastodon/locales/ig.json index 3eec2158b..201bebc05 100644 --- a/app/javascript/mastodon/locales/ig.json +++ b/app/javascript/mastodon/locales/ig.json @@ -1,8 +1,11 @@ { "account.add_or_remove_from_list": "Tinye ma ọ bụ Wepu na ndepụta", "account.badges.bot": "Bot", + "account.badges.group": "Otù", "account.cancel_follow_request": "Withdraw follow request", "account.follow": "Soro", + "account.followers": "Ndị na-eso", + "account.following": "Na-eso", "account.follows_you": "Na-eso gị", "account.mute": "Mee ogbi @{name}", "account.unfollow": "Kwụsị iso", @@ -11,16 +14,20 @@ "audio.hide": "Zoo ụda", "bundle_column_error.retry": "Nwaa ọzọ", "bundle_column_error.routing.title": "404", + "bundle_modal_error.close": "Mechie", "bundle_modal_error.retry": "Nwaa ọzọ", "column.about": "Maka", "column.blocks": "Ojiarụ egbochiri", "column.bookmarks": "Ebenrụtụakā", "column.home": "Be", + "column.lists": "Ndepụta", "column.pins": "Pinned post", + "column_header.pin": "Gbado na profaịlụ gị", "column_subheading.settings": "Mwube", "community.column_settings.media_only": "Media only", "compose.language.change": "Gbanwee asụsụ", "compose.language.search": "Chọọ asụsụ...", + "compose.published.open": "Mepe", "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.", "compose_form.placeholder": "What is on your mind?", @@ -32,7 +39,10 @@ "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.delete_list.confirm": "Hichapụ", "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.edit.confirm": "Dezie", + "confirmations.mute.confirm": "Mee ogbi", "confirmations.reply.confirm": "Zaa", + "confirmations.unfollow.confirm": "Kwụsị iso", "conversation.delete": "Hichapụ nkata", "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", @@ -76,6 +86,7 @@ "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", "keyboard_shortcuts.up": "to move up in the list", "lists.delete": "Hichapụ ndepụta", + "lists.edit": "Dezie ndepụta", "lists.subheading": "Ndepụta gị", "loading_indicator.label": "Na-adọnye...", "navigation_bar.about": "Maka", @@ -100,20 +111,27 @@ "privacy.change": "Adjust status privacy", "privacy.direct.short": "Direct", "privacy.private.short": "Followers-only", + "relative_time.full.just_now": "kịta", "relative_time.just_now": "kịta", "relative_time.today": "taa", "reply_indicator.cancel": "Kagbuo", "report.categories.other": "Ọzọ", + "report.categories.spam": "Nzipụ Ozièlètrọniìk Nkeāchọghị", + "report.mute": "Mee ogbi", "report.placeholder": "Type or paste additional comments", "report.submit": "Submit report", "report.target": "Report {target}", "report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached", + "report_notification.categories.other": "Ọzọ", + "search.placeholder": "Chọọ", "server_banner.active_users": "ojiarụ dị ìrè", + "server_banner.learn_more": "Mụtakwuo", "sign_in_banner.sign_in": "Sign in", "status.admin_status": "Open this status in the moderation interface", "status.bookmark": "Kee ebenrụtụakā", "status.copy": "Copy link to status", "status.delete": "Hichapụ", + "status.edit": "Dezie", "status.edited_x_times": "Edited {count, plural, one {# time} other {# times}}", "status.open": "Expand this status", "status.remove_bookmark": "Wepu ebenrụtụakā", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 72a57c8e3..4cd7228c8 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -586,8 +586,8 @@ "search.no_recent_searches": "検索履歴はありません", "search.placeholder": "検索", "search.quick_action.account_search": "{x}に該当するプロフィール", - "search.quick_action.go_to_account": "{x}のプロフィールを見る", - "search.quick_action.go_to_hashtag": "{x}に該当するハッシュタグ", + "search.quick_action.go_to_account": "プロフィール {x} を見る", + "search.quick_action.go_to_hashtag": "ハッシュタグ {x} を見る", "search.quick_action.open_url": "MastodonでURLを開く", "search.quick_action.status_search": "{x}に該当する投稿", "search.search_or_paste": "検索またはURLを入力", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 269063b7c..574d8e211 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "검색 결과", "emoji_button.symbols": "기호", "emoji_button.travel": "여행과 장소", + "empty_column.account_hides_collections": "이 사용자는 이 정보를 사용할 수 없도록 설정했습니다", "empty_column.account_suspended": "계정 정지됨", "empty_column.account_timeline": "이곳에는 게시물이 없습니다!", "empty_column.account_unavailable": "프로필 사용 불가", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index a1ab53131..75f4a239e 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -15,7 +15,7 @@ "account.add_or_remove_from_list": "Pridėti arba ištrinti iš sąrašų", "account.badges.bot": "Automatizuotas", "account.badges.group": "Grupė", - "account.block": "Užblokuoti @{name}", + "account.block": "Blokuoti @{name}", "account.block_domain": "Blokuoti domeną {domain}", "account.block_short": "Blokuoti", "account.blocked": "Užblokuota", @@ -25,11 +25,20 @@ "account.disable_notifications": "Nustoti man pranešti, kai @{name} paskelbia", "account.domain_blocked": "Užblokuotas domenas", "account.edit_profile": "Redaguoti profilį", + "account.enable_notifications": "Pranešti man, kai @{name} paskelbia", + "account.featured_tags.last_status_at": "Paskutinį kartą paskelbta {date}", + "account.featured_tags.last_status_never": "Nėra įrašų", "account.follow": "Sekti", - "account.follows_you": "Seka jus", + "account.followers": "Sekėjai", + "account.followers.empty": "Šio naudotojo dar niekas neseka.", + "account.followers_counter": "{count, plural, one {{counter} sekėjas (-a)} few {{counter} sekėjai} many {{counter} sekėjo} other {{counter} sekėjų}}", + "account.following": "Seka", + "account.follows.empty": "Šis naudotojas (-a) dar nieko neseka.", + "account.follows_you": "Seka tave", "account.go_to_profile": "Eiti į profilį", "account.in_memoriam": "Atminimui.", "account.joined_short": "Prisijungė", + "account.languages": "Keisti prenumeruojamas kalbas", "account.locked_info": "Šios paskyros privatumo būsena nustatyta kaip užrakinta. Savininkas (-ė) rankiniu būdu peržiūri, kas gali sekti.", "account.media": "Medija", "account.mute": "Užtildyti @{name}", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index 449fdfb1a..7421c780f 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Søkeresultat", "emoji_button.symbols": "Symboler", "emoji_button.travel": "Reise & steder", + "empty_column.account_hides_collections": "Denne brukeren har valgt å ikke gjøre denne informasjonen tilgjengelig", "empty_column.account_suspended": "Kontoen er suspendert", "empty_column.account_timeline": "Ingen innlegg her!", "empty_column.account_unavailable": "Profilen er utilgjengelig", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index dfb464dbb..9c09e2d71 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Resultado da pesquisa", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viagem e Lugares", + "empty_column.account_hides_collections": "A pessoa optou por não disponibilizar esta informação", "empty_column.account_suspended": "Conta suspensa", "empty_column.account_timeline": "Nada aqui.", "empty_column.account_unavailable": "Perfil indisponível", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index f33dd2fb8..988bec9b0 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Resultados da pesquisa", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viagens & Lugares", + "empty_column.account_hides_collections": "Este utilizador escolheu não disponibilizar esta informação", "empty_column.account_suspended": "Conta suspensa", "empty_column.account_timeline": "Sem publicações por aqui!", "empty_column.account_unavailable": "Perfil indisponível", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 3a7e75b91..aa229eceb 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Kết quả tìm kiếm", "emoji_button.symbols": "Biểu tượng", "emoji_button.travel": "Du lịch", + "empty_column.account_hides_collections": "Người này đã chọn ẩn thông tin", "empty_column.account_suspended": "Tài khoản vô hiệu hóa", "empty_column.account_timeline": "Chưa có tút nào!", "empty_column.account_unavailable": "Tài khoản bị đình chỉ", diff --git a/config/locales/doorkeeper.lt.yml b/config/locales/doorkeeper.lt.yml index 36f31e39e..1012160f6 100644 --- a/config/locales/doorkeeper.lt.yml +++ b/config/locales/doorkeeper.lt.yml @@ -1,18 +1,143 @@ --- lt: + activerecord: + attributes: + doorkeeper/application: + name: Programėlės pavadinimas + redirect_uri: Peradresavimo URI + scopes: Aprėptys + website: Programėlės svetainė + errors: + models: + doorkeeper/application: + attributes: + redirect_uri: + fragment_present: negali turėti fragmento. + invalid_uri: turi būti tinkamas URI. + relative_uri: turi būti absoliutus URI. + secured_uri: turi būti HTTPS/SSL URI. doorkeeper: + applications: + buttons: + authorize: Įgalinti + cancel: Atšaukti + destroy: Sunaikinti + edit: Redaguoti + submit: Pateikti + confirmations: + destroy: Ar esi įsitikinęs (-usi)? + edit: + title: Redaguoti programėlę + form: + error: Ups! Patikrink, ar formoje nėra galimų klaidų. + help: + native_redirect_uri: Naudoti %{native_redirect_uri} vietiniams bandymams + redirect_uri: Naudoti po vieną eilutę kiekvienam URI + scopes: Atskirk aprėptis tarpais. Palik tuščią, jei nori naudoti numatytąsias aprėtis. + index: + application: Programėlė + callback_url: Atgalinis URL + delete: Ištrinti + empty: Neturi jokių programėlių. + name: Pavadinimas + new: Nauja programėlė + scopes: Aprėptys + show: Rodyti + title: Tavo programėlės + new: + title: Nauja programėlė + show: + actions: Veiksmai + application_id: Kliento raktas + callback_urls: Atgalinių URL adresų + scopes: Aprėptys + secret: Kliento paslaptis + title: 'Programėlė: %{name}' authorizations: + buttons: + authorize: Įgalinti + deny: Atmesti error: title: Įvyko klaida. new: prompt_html: "%{client_name} norėtų gauti leidimą prieigos prie tavo paskyros. Tai trečiosios šalies programėlė. <strong>Jei ja nepasitiki, neturėtum jai leisti.</strong>" + review_permissions: Peržiūrėti leidimus + title: Reikalingas įgaliojimas + show: + title: Nukopijuok šį įgaliojimo kodą ir įklijuok jį į programėlę. authorized_applications: + buttons: + revoke: Naikinti + confirmations: + revoke: Ar esi įsitikinęs (-usi)? index: - title: Tavo leidžiamos programėlės + authorized_at: Įgaliota %{date} + description_html: Tai programėlės, kurios gali pasiekti tavo paskyrą naudojant API. Jei čia yra programėlių, kurių neatpažįsti, arba jei programėlė elgiasi netinkamai, gali panaikinti jos prieigą. + last_used_at: Paskutinį kartą naudota %{date} + never_used: Niekada nenaudotas + scopes: Leidimai + superapp: Vidinis + title: Tavo įgaliotos programėlės + errors: + messages: + access_denied: Išteklių savininkas (-ė) arba įgaliojimų serveris atmetė užklausą. + credential_flow_not_configured: Išteklių savininko slaptažodžio kredencialų srautas nepavyko, nes Doorkeeper.configure.resource_owner_from_credentials nėra nesukonfigūruotas. + invalid_client: Kliento tapatybės nustatymas nepavyko dėl nežinomo kliento, neįtraukto kliento tapatybės nustatymo arba nepalaikomo tapatybės nustatymo metodo. + invalid_grant: Pateiktas įgaliojimas yra netinkamas, pasibaigęs, panaikintas, neatitinka įgaliojimo užklausoje naudoto nukreipimo URI arba buvo išduotas kitam klientui. + invalid_redirect_uri: Nukreipimo uri įtrauktas yra netinkamas. + invalid_request: + missing_param: 'Trūksta privalomo parametro: %{value}.' + request_not_authorized: Užklausą reikia įgalioti. Reikalingo parametro užklausai įgalioti trūksta arba jis netinkamas. + unknown: Užklausoje trūksta privalomo parametro, turi nepalaikomą parametro reikšmę arba yra kitaip netinkamai suformuota. + invalid_resource_owner: Pateikti išteklių savininko įgaliojimai yra netinkami arba išteklių savininko negalima surasti. + invalid_scope: Užklausos aprėptis yra netinkama, nežinoma arba netinkamai suformuota. + invalid_token: + expired: Baigėsi prieigos rakto galiojimas. + revoked: Prieigos raktas buvo panaikintas. + unknown: Prieigos raktas yra netinkamas. + resource_owner_authenticator_not_configured: Išteklių savininko suradimas nepavyko dėl to, kad Doorkeeper.configure.resource_owner_authenticator nėra sukonfigūruotas. + server_error: Įgaliojimų serveris susidūrė su netikėta sąlyga, dėl kurios negalėjo užpildyti užklausos. + temporarily_unavailable: Įgaliojimų serveris šiuo metu negali apdoroti užklausos dėl laikinos serverio perkrovos arba techninės priežiūros. + unauthorized_client: Klientas nėra įgaliotas atlikti šią užklausą šiuo metodu. + unsupported_grant_type: Įgaliojimų suteikimo tipas nepalaikomas įgaliojimų serveryje. + unsupported_response_type: Įgaliojimų serveris nepalaiko šio atsako tipo. + flash: + applications: + create: + notice: Programėlė sukurta. + destroy: + notice: Programėlė ištrinta. + update: + notice: Programėlė atnaujinta. + authorized_applications: + destroy: + notice: Programėlė panaikinta. grouped_scopes: + access: + read: Tik skaitymo prieiga + read/write: Skaitymo ir rašymo prieiga + write: Tik rašymo prieiga title: + accounts: Paskyros + admin/accounts: Paskyrų administravimas + admin/all: Visi administraciniai funkcijos + admin/reports: Ataskaitų administravimas + all: Pilna prieiga prie tavo Mastodon paskyros blocks: Blokavimai + bookmarks: Žymės + conversations: Pokalbiai + crypto: Galo iki galo užšifravimas + favourites: Mėgstami + filters: Filtrai follow: Sekimai, nutildymai ir blokavimai + follows: Sekimai + lists: Sąrašai + media: Medijos priedai + mutes: Užtildymai + notifications: Pranešimai + push: Stumdomieji pranešimai + reports: Ataskaitos + search: Paieška statuses: Įrašai layouts: admin: @@ -37,6 +162,7 @@ lt: admin:write:domain_blocks: atlikti prižiūrėjimo veiksmus su domenų blokavimais admin:write:email_domain_blocks: atlikti prižiūrėjimo veiksmus su el. laiško domenų blokavimais admin:write:ip_blocks: atlikti prižiūrėjimo veiksmus su IP blokavimais + admin:write:reports: atlikti paskyrų prižiūrėjimo veiksmus atsakaitams crypto: naudoti galo iki galo šifravimą follow: modifikuoti paskyros santykius push: gauti tavo stumiamuosius pranešimus diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 8e076878a..8569d2e37 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -131,7 +131,7 @@ fa: reset_password: بازنشانی گذرواژه resubscribe: اشتراک دوباره role: نقش - search: جستجو + search: جستوجو search_same_email_domain: دیگر کاربران با دامنهٔ رایانامهٔ یکسان search_same_ip: دیگر کاربران با IP یکسان security: امنیت @@ -386,6 +386,10 @@ fa: confirm_suspension: cancel: لغو confirm: تعلیق + permanent_action: برگرداندن تعلیق هیچ داده یا ارتباطی را برنخواهد گرداند. + preamble_html: در حال تعلیق <strong>%{domain}</strong> و همهٔ زیردامنههایش هستید. + remove_all_data: این کار همهٔ دادههای نمایه، محتوا و رسانههای حسابهای این دامنه را از کارسازتان برمیدارد. + stop_communication: کارسازتان دیگر با این کارسازها ارتباط برقرار نخواهد کرد. title: تأیید انسداد دامنه برای %{domain} created_msg: مسدودسازی دامنه در حال پردازش است destroyed_msg: انسداد دامنه واگردانده شد @@ -1219,7 +1223,7 @@ fa: followers: این کار همهٔ پیگیران شما را از حساب فعلی به حساب تازه منتقل خواهد کرد only_redirect_html: شما همچنین میتوانید حساب خود را <a href="%{path}">به یک حساب دیگر اشاره دهید</a>. other_data: هیچ دادهٔ دیگری خودبهخود منتقل نخواهد شد - redirect: نمایهٔ حساب فعلی شما به حساب تازه اشاره خواهد کرد و خودش در نتیجهٔ جستجوها ظاهر نخواهد شد + redirect: نمایهٔ حساب کنونیتان به حساب تازه اشاره خواهد کرد و از جستوجوها حذف خواهد شد moderation: title: مدیریت کاربران move_handler: diff --git a/config/locales/ig.yml b/config/locales/ig.yml index 7c264f0d7..9db771fdc 100644 --- a/config/locales/ig.yml +++ b/config/locales/ig.yml @@ -1 +1,5 @@ +--- ig: + filters: + contexts: + home: Ụlọ na ndepụta diff --git a/config/locales/ja.yml b/config/locales/ja.yml index ca438f53d..3318b690a 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -1023,7 +1023,7 @@ ja: hint_html: もう一つだけ!あなたが人間であることを確認する必要があります(スパムを防ぐためです!)。 以下のCAPTCHAを解き、「続ける」をクリックします。 title: セキュリティチェック confirmations: - awaiting_review: メールアドレスは確認済みです。%{domain} のモデレーターによりアカウント登録の審査が完了すると、メールでお知らせします。 + awaiting_review: メールアドレスが確認できました。%{domain} のスタッフが登録審査を行います。承認されたらメールでお知らせします! awaiting_review_title: 登録の審査待ちです clicking_this_link: このリンクを押す login_link: ログイン diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 530cf6a44..72eafc8fb 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -1689,8 +1689,8 @@ ko: keep_polls_hint: 설문을 삭제하지 않았음 keep_self_bookmark: 북마크한 게시물 유지 keep_self_bookmark_hint: 북마크한 본인의 게시물을 삭제하지 않습니다 - keep_self_fav: 마음에 들어한 게시물 유지 - keep_self_fav_hint: 내 스스로 마음에 들어한 본인의 게시물을 삭제하지 않습니다 + keep_self_fav: 내가 좋아요한 게시물 유지 + keep_self_fav_hint: 스스로 좋아요를 누른 본인의 게시물을 삭제하지 않습니다 min_age: '1209600': 2 주 '15778476': 6 개월 diff --git a/config/locales/nn.yml b/config/locales/nn.yml index 551824e80..acd6b206e 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -1041,6 +1041,14 @@ nn: hint_html: Berre ein ting til! Vi må bekrefte at du er et menneske (så vi kan halde spam ute!). Løys CAPTCHA-en nedanfor og klikk "Fortsett". title: Sikkerheitssjekk confirmations: + awaiting_review: Din e-post adresse er bekreftet! %{domain} ansatte gjennomgår nå registreringen din. Du vil motta en e-post hvis de godkjenner din konto! + awaiting_review_title: Din registrering blir vurdert + clicking_this_link: klikke på denne lenken + login_link: logg inn + proceed_to_login_html: Du kan nå fortsette til %{login_link}. + redirect_to_app_html: Du burde bli omdirigert til <strong>%{app_name}</strong> -appen. Hvis det ikke skjedde, kan du prøve %{clicking_this_link} eller manuelt gå tilbake til appen. + registration_complete: Registreringen på %{domain} er nå fullført! + welcome_title: Velkommen, %{name}! wrong_email_hint: Viss epostadressa er feil, kan du endra ho i kontoinnstillingane. delete_account: Slett konto delete_account_html: Om du vil sletta kontoen din, kan du <a href="%{path}">gå hit</a>. Du vert spurd etter stadfesting. diff --git a/config/locales/no.yml b/config/locales/no.yml index 1abfbdb97..75085fa5a 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -772,6 +772,11 @@ approved: Godkjenning kreves for påmelding none: Ingen kan melde seg inn open: Hvem som helst kan melde seg inn + security: + authorized_fetch: Krev autentisering fra fødererte servere + authorized_fetch_hint: Krav om godkjenning fra fødererte servere muliggjør strengere håndhevelse av blokker på både brukernivå og servernivå. Dette går imidlertid på bekostning av en ytelsesstraff, reduserer rekkevidden til svarene dine og kan introdusere kompatibilitetsproblemer med enkelte fødererte tjenester. I tillegg vil dette ikke hindre dedikerte aktører i å hente dine offentlige innlegg og kontoer. + authorized_fetch_overridden_hint: Du kan for øyeblikket ikke endre denne innstillingen fordi den overstyres av en miljøvariabel. + federation_authentication: Håndheving av føderasjonsautentisering title: Serverinnstillinger site_uploads: delete: Slett den opplastede filen @@ -1036,6 +1041,14 @@ hint_html: Bare en ting til! Vi må bekrefte at du er et menneske (dette er slik at vi kan holde spam ute!). Løs CAPTCHA nedenfor og klikk "Fortsett". title: Sikkerhetskontroll confirmations: + awaiting_review: Din e-post adresse er bekreftet! %{domain} ansatte gjennomgår nå registreringen din. Du vil motta en e-post hvis de godkjenner din konto! + awaiting_review_title: Din registrering blir vurdert + clicking_this_link: klikke på denne lenken + login_link: logg inn + proceed_to_login_html: Du kan nå fortsette til %{login_link}. + redirect_to_app_html: Du burde bli omdirigert til <strong>%{app_name}</strong> -appen. Hvis det ikke skjedde, kan du prøve %{clicking_this_link} eller manuelt gå tilbake til appen. + registration_complete: Registreringen på %{domain} er nå fullført! + welcome_title: Velkommen, %{name}! wrong_email_hint: Hvis e-postadressen ikke er riktig, kan du endre den i kontoinnstillingene. delete_account: Slett konto delete_account_html: Hvis du ønsker å slette kontoen din, kan du <a href="%{path}">gå hit</a>. Du vil bli spurt om bekreftelse. @@ -1739,6 +1752,10 @@ month: "%b %Y" time: "%H:%M" with_time_zone: "%-d. %b %Y, %H:%M %Z" + translation: + errors: + quota_exceeded: Den serveromfattende brukskvoten for oversettelsestjenesten er overskredet. + too_many_requests: Det har nylig vært for mange forespørsler til oversettelsestjenesten. two_factor_authentication: add: Legg til disable: Skru av diff --git a/config/locales/simple_form.he.yml b/config/locales/simple_form.he.yml index 581a66807..13ea8a0c4 100644 --- a/config/locales/simple_form.he.yml +++ b/config/locales/simple_form.he.yml @@ -5,7 +5,7 @@ he: account: discoverable: הפוסטים והפרופיל שלך עשויים להיות מוצגים או מומלצים באזורים שונים באתר וייתכן שהפרופיל שלך יוצע למשתמשים אחרים. display_name: שמך המלא או שם הכיף שלך. - fields: עמוד הבית שלך, כינויי גוף, גיל, וכל מידע אחר לפי העדפתך האישית. + fields: עמוד הבית שלך, לשון הפנייה, גיל, וכל מידע אחר לפי העדפתך האישית. indexable: ההודעות הפומביות שלך עשויות להופיע בתוצאות חיפוש במסטודון. אחרים שהדהדו, חיבבו או ענו להודעות האלו יוכלו למצוא אותן בחיפוש בכל מקרה. note: 'ניתן לאזכר @אחרים או #תגיות.' show_collections: אנשים יוכלו לדפדף בין העוקבים והנעקבים שלך. אנשים שאת.ה עוקב.ת אחריהם יראו את המעקב אחריהם כרגיל. diff --git a/config/locales/simple_form.no.yml b/config/locales/simple_form.no.yml index a9d5465f3..ca2020e21 100644 --- a/config/locales/simple_form.no.yml +++ b/config/locales/simple_form.no.yml @@ -323,6 +323,7 @@ url: Endepunkt lenke 'no': Nei not_recommended: Ikke anbefalt + overridden: Overstyrt recommended: Anbefalt required: mark: "*" From 5bca5c4c5b036c922144e713e776727cd06615bf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 14:24:14 +0100 Subject: [PATCH 011/255] Update formatjs monorepo (#27823) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 142 +++++++++++++++++++++++++++--------------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0058a6837..c1e9ec9a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1800,13 +1800,13 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:1.17.3": - version: 1.17.3 - resolution: "@formatjs/ecma402-abstract@npm:1.17.3" +"@formatjs/ecma402-abstract@npm:1.17.4": + version: 1.17.4 + resolution: "@formatjs/ecma402-abstract@npm:1.17.4" dependencies: - "@formatjs/intl-localematcher": "npm:0.5.0" + "@formatjs/intl-localematcher": "npm:0.5.1" tslib: "npm:^2.4.0" - checksum: 00eb87301272d22dcdb0f2de74df22fa96c0062a9c1b1d718da5b8d8a4d9841aa59f909da624bd7f99db97d19c8a0338e511ad57a01d6fcfc02e67c6627035ce + checksum: c24bf58cd3152ad64a29dfab185d1fde91e44423aabb041f332216b37a23256618efee1e252c0015e735bc688708ee279348e2a4a67a77f6cf918028848ef071 languageName: node linkType: hard @@ -1830,14 +1830,14 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-messageformat-parser@npm:2.7.1": - version: 2.7.1 - resolution: "@formatjs/icu-messageformat-parser@npm:2.7.1" +"@formatjs/icu-messageformat-parser@npm:2.7.2": + version: 2.7.2 + resolution: "@formatjs/icu-messageformat-parser@npm:2.7.2" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.3" - "@formatjs/icu-skeleton-parser": "npm:1.6.3" + "@formatjs/ecma402-abstract": "npm:1.17.4" + "@formatjs/icu-skeleton-parser": "npm:1.6.4" tslib: "npm:^2.4.0" - checksum: 4bfc01538ef385e8bcc7c86f08b20ab87ce22c355cf3ea322c8f8d941260e00484f10aa43266f5eea096879f782fa6cdb8fe649dcb13d2745868beea36316ecb + checksum: c7a2f7daecec9ba36acda2c5b7ef21f515883b886d4d9965d83c93bc55fc604f56c1097d4641608633c32917aaa0b9b0c65c0d162723428249dc29271270a064 languageName: node linkType: hard @@ -1851,35 +1851,35 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-skeleton-parser@npm:1.6.3": - version: 1.6.3 - resolution: "@formatjs/icu-skeleton-parser@npm:1.6.3" +"@formatjs/icu-skeleton-parser@npm:1.6.4": + version: 1.6.4 + resolution: "@formatjs/icu-skeleton-parser@npm:1.6.4" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.3" + "@formatjs/ecma402-abstract": "npm:1.17.4" tslib: "npm:^2.4.0" - checksum: 97a05fef16c93d9d663c5d7dadf9dcc72217d7a8afedda3a441ceedf085d45e500022dd67d3c578a1a508dd334538e4eca07129a9994c39c0c36e205e567c04b + checksum: 3688aad6d12fe677ef0ce3d6a3424c5bde9ed223dc49841de8dd33c547bdd2858f8bce4437fcc135048b4f92385374776ab48e39b3cc5063a45bdb1ce85ad2d4 languageName: node linkType: hard -"@formatjs/intl-displaynames@npm:6.6.2": - version: 6.6.2 - resolution: "@formatjs/intl-displaynames@npm:6.6.2" +"@formatjs/intl-displaynames@npm:6.6.3": + version: 6.6.3 + resolution: "@formatjs/intl-displaynames@npm:6.6.3" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.3" - "@formatjs/intl-localematcher": "npm:0.5.0" + "@formatjs/ecma402-abstract": "npm:1.17.4" + "@formatjs/intl-localematcher": "npm:0.5.1" tslib: "npm:^2.4.0" - checksum: e0dbf749b19b93e009d487e70f4926bac4f94b0a4e60b435d4f925f686a54a869fd871902f6af322843437b8f80725981136be20cfb145c7d7c3b9826bfc43e3 + checksum: b0520cb744a51290fbcde80860f39ed9c9df9b81beae98986e1fc089ef635f7699c750631fa42a559f3678d1dd02b14904614e70360477d18e68d3eba6592390 languageName: node linkType: hard -"@formatjs/intl-listformat@npm:7.5.1": - version: 7.5.1 - resolution: "@formatjs/intl-listformat@npm:7.5.1" +"@formatjs/intl-listformat@npm:7.5.2": + version: 7.5.2 + resolution: "@formatjs/intl-listformat@npm:7.5.2" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.3" - "@formatjs/intl-localematcher": "npm:0.5.0" + "@formatjs/ecma402-abstract": "npm:1.17.4" + "@formatjs/intl-localematcher": "npm:0.5.1" tslib: "npm:^2.4.0" - checksum: bb972ad9078db197699452a2958dea74cfd62fcea84015a8786ac8e399738c9fe08c3c71dd1ea34ff46f24783daa20d26d5af4b5d1df5ee0ca9af7530788d2a5 + checksum: 54fa03da4ea45504681d6d87d72d1cac574809ce43f965fa4b845e83be3072d92324c58cec57ad386827087fb1d6ecae438d29576f30176bf52eb212e454bce2 languageName: node linkType: hard @@ -1892,43 +1892,43 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-localematcher@npm:0.5.0": - version: 0.5.0 - resolution: "@formatjs/intl-localematcher@npm:0.5.0" +"@formatjs/intl-localematcher@npm:0.5.1": + version: 0.5.1 + resolution: "@formatjs/intl-localematcher@npm:0.5.1" dependencies: tslib: "npm:^2.4.0" - checksum: adc82cad4c37dfff2ba1d00216e2056ce4c91b85fd39c60474849ccd74ec1262a8203d460d0ee863b71eb399297c3e087f5ccbbf3a874d682b021e6e3fd2c943 + checksum: 2282db3e623d3f65681b6a2a2dbffc4f948b8411789f51af1b221610105f809ebec7f58f9afd5008e72c62ed5524c8c321f85c78cab0cffb632e20c0064b701b languageName: node linkType: hard "@formatjs/intl-pluralrules@npm:^5.2.2": - version: 5.2.8 - resolution: "@formatjs/intl-pluralrules@npm:5.2.8" + version: 5.2.9 + resolution: "@formatjs/intl-pluralrules@npm:5.2.9" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.3" - "@formatjs/intl-localematcher": "npm:0.5.0" + "@formatjs/ecma402-abstract": "npm:1.17.4" + "@formatjs/intl-localematcher": "npm:0.5.1" tslib: "npm:^2.4.0" - checksum: cc5826774829a9c424b05010c398192aef93d89cca0144ebdc91df29032b808b235e7dde8def27887c5cddb695affd518993d728a908911897599d67d10e1954 + checksum: a6ca5c498ce542facacf8ce8640d4ba068f9119b758547a23614b50611eb385a46abd386ff88fa423211355ec463cf102c2c908b74f6e23a5bc9e2a23873dc29 languageName: node linkType: hard -"@formatjs/intl@npm:2.9.6": - version: 2.9.6 - resolution: "@formatjs/intl@npm:2.9.6" +"@formatjs/intl@npm:2.9.8": + version: 2.9.8 + resolution: "@formatjs/intl@npm:2.9.8" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.3" + "@formatjs/ecma402-abstract": "npm:1.17.4" "@formatjs/fast-memoize": "npm:2.2.0" - "@formatjs/icu-messageformat-parser": "npm:2.7.1" - "@formatjs/intl-displaynames": "npm:6.6.2" - "@formatjs/intl-listformat": "npm:7.5.1" - intl-messageformat: "npm:10.5.5" + "@formatjs/icu-messageformat-parser": "npm:2.7.2" + "@formatjs/intl-displaynames": "npm:6.6.3" + "@formatjs/intl-listformat": "npm:7.5.2" + intl-messageformat: "npm:10.5.7" tslib: "npm:^2.4.0" peerDependencies: typescript: 5 peerDependenciesMeta: typescript: optional: true - checksum: 6dadbf3dfcd1534735899fb5eed3e340a547d92ca4b0c33857e7ec3a19bddbf7787d0ab2aa014f3c2d7288e81d0ed1cb3308b0ede8299fda6d12b0bd6b1ad89d + checksum: 6341f4bfb56a0e14373395b1232e1eeb8e64588a8c3d4614cd2b06f71d4e65dbd4a79e3a1c07e1b6c20c48e399ac2385977b01a559e1d2bd1a1d226e0eae3058 languageName: node linkType: hard @@ -1952,11 +1952,11 @@ __metadata: languageName: node linkType: hard -"@formatjs/ts-transformer@npm:3.13.7": - version: 3.13.7 - resolution: "@formatjs/ts-transformer@npm:3.13.7" +"@formatjs/ts-transformer@npm:3.13.8": + version: 3.13.8 + resolution: "@formatjs/ts-transformer@npm:3.13.8" dependencies: - "@formatjs/icu-messageformat-parser": "npm:2.7.1" + "@formatjs/icu-messageformat-parser": "npm:2.7.2" "@types/json-stable-stringify": "npm:^1.0.32" "@types/node": "npm:14 || 16 || 17" chalk: "npm:^4.0.0" @@ -1968,7 +1968,7 @@ __metadata: peerDependenciesMeta: ts-jest: optional: true - checksum: 1ce528a01fa831a4a07890ae6c447c1b1cb63870c98b5f5dfbbd9f69c7e42dcd3cfd58d2717cc7214b41ddb4c3949f69525e52b6f6001d1b494573036d1478c8 + checksum: 32b13b75732739ca016d9d654e5f40077cafa3ff2f924fbb5fd91155cd6af3292c5fee9be022bb224fb69d2ab60ed9cdda49ee83fbf9e1e8de470ee33ceae4f3 languageName: node linkType: hard @@ -4735,21 +4735,21 @@ __metadata: linkType: hard "babel-plugin-formatjs@npm:^10.5.1": - version: 10.5.8 - resolution: "babel-plugin-formatjs@npm:10.5.8" + version: 10.5.9 + resolution: "babel-plugin-formatjs@npm:10.5.9" dependencies: "@babel/core": "npm:^7.10.4" "@babel/helper-plugin-utils": "npm:^7.10.4" "@babel/plugin-syntax-jsx": "npm:7" "@babel/traverse": "npm:7" "@babel/types": "npm:^7.12.11" - "@formatjs/icu-messageformat-parser": "npm:2.7.1" - "@formatjs/ts-transformer": "npm:3.13.7" + "@formatjs/icu-messageformat-parser": "npm:2.7.2" + "@formatjs/ts-transformer": "npm:3.13.8" "@types/babel__core": "npm:^7.1.7" "@types/babel__helper-plugin-utils": "npm:^7.10.0" "@types/babel__traverse": "npm:^7.1.7" tslib: "npm:^2.4.0" - checksum: 837f031e46a771ac6874b7dbe852ebb0919da81af97d2a6d38e47cc798502ee0e02ce247c6f0d0665108aa336ef3b15b321070d444b6d6994499b931ab178537 + checksum: 5e4127cf7b4b9b3306a9d0ab5b029831712d22db5e2117225ce706b55d222d09a7eba1f3720fdad7a99f61843b5cba107296fc11ae00a6f0941217d9322aa02e languageName: node linkType: hard @@ -9276,15 +9276,15 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:10.5.5, intl-messageformat@npm:^10.3.5": - version: 10.5.5 - resolution: "intl-messageformat@npm:10.5.5" +"intl-messageformat@npm:10.5.7, intl-messageformat@npm:^10.3.5": + version: 10.5.7 + resolution: "intl-messageformat@npm:10.5.7" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.3" + "@formatjs/ecma402-abstract": "npm:1.17.4" "@formatjs/fast-memoize": "npm:2.2.0" - "@formatjs/icu-messageformat-parser": "npm:2.7.1" + "@formatjs/icu-messageformat-parser": "npm:2.7.2" tslib: "npm:^2.4.0" - checksum: 223f48d719585b572f07012e2432c742e0acc371950c01a6fc9d7cb3e022d8486593ab8b7ed50849444035cdce119484e49f7c32b3646a8601a4d8f312395cf2 + checksum: 7f341b3eb5b3d402167c99ca7fb98720c7ad553bed8a490b2210bd90ea9009a09f9030939307fecb111fce1454f31b4298b4f0a346999af627c86f8164a5c547 languageName: node linkType: hard @@ -13663,18 +13663,18 @@ __metadata: linkType: hard "react-intl@npm:^6.4.2": - version: 6.5.2 - resolution: "react-intl@npm:6.5.2" + version: 6.5.4 + resolution: "react-intl@npm:6.5.4" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.3" - "@formatjs/icu-messageformat-parser": "npm:2.7.1" - "@formatjs/intl": "npm:2.9.6" - "@formatjs/intl-displaynames": "npm:6.6.2" - "@formatjs/intl-listformat": "npm:7.5.1" + "@formatjs/ecma402-abstract": "npm:1.17.4" + "@formatjs/icu-messageformat-parser": "npm:2.7.2" + "@formatjs/intl": "npm:2.9.8" + "@formatjs/intl-displaynames": "npm:6.6.3" + "@formatjs/intl-listformat": "npm:7.5.2" "@types/hoist-non-react-statics": "npm:^3.3.1" "@types/react": "npm:16 || 17 || 18" hoist-non-react-statics: "npm:^3.3.2" - intl-messageformat: "npm:10.5.5" + intl-messageformat: "npm:10.5.7" tslib: "npm:^2.4.0" peerDependencies: react: ^16.6.0 || 17 || 18 @@ -13682,7 +13682,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 8c2cbad85c4fc3647f9498a5dab13c11490a77936dcf14cb769b5659b361e7070c7528bf0d8708eec06a6dbca93b34cccf5cc919005d33c645739865cfccb878 + checksum: 1117a7f866b103abf88a4087f5fe8b854d9c069c69444c592f8431e7d28c9b90423f7b50e550be0f2f173b7563e943bcc9238e80f6747181f81861275f6e2ce7 languageName: node linkType: hard From 07a4059901e8723cd3d986a0aefb216faa42b5fe Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Mon, 13 Nov 2023 14:27:00 +0100 Subject: [PATCH 012/255] Add support for invite codes in the registration API (#27805) --- app/controllers/api/v1/accounts_controller.rb | 18 ++-- app/controllers/api/v1/invites_controller.rb | 30 ++++++ .../auth/registrations_controller.rb | 15 +-- app/helpers/registration_helper.rb | 21 +++++ app/services/app_sign_up_service.rb | 30 ++---- config/locales/en.yml | 1 + config/routes.rb | 2 + spec/requests/invite_spec.rb | 27 ++++++ spec/services/app_sign_up_service_spec.rb | 92 ++++++++++++------- 9 files changed, 158 insertions(+), 78 deletions(-) create mode 100644 app/controllers/api/v1/invites_controller.rb create mode 100644 app/helpers/registration_helper.rb create mode 100644 spec/requests/invite_spec.rb diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index ddb94d5ca..653529316 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class Api::V1::AccountsController < Api::BaseController + include RegistrationHelper + before_action -> { authorize_if_got_token! :read, :'read:accounts' }, except: [:create, :follow, :unfollow, :remove_from_followers, :block, :unblock, :mute, :unmute] before_action -> { doorkeeper_authorize! :follow, :write, :'write:follows' }, only: [:follow, :unfollow, :remove_from_followers] before_action -> { doorkeeper_authorize! :follow, :write, :'write:mutes' }, only: [:mute, :unmute] @@ -90,18 +92,14 @@ class Api::V1::AccountsController < Api::BaseController end def account_params - params.permit(:username, :email, :password, :agreement, :locale, :reason, :time_zone) + params.permit(:username, :email, :password, :agreement, :locale, :reason, :time_zone, :invite_code) + end + + def invite + Invite.find_by(code: params[:invite_code]) if params[:invite_code].present? end def check_enabled_registrations - forbidden if single_user_mode? || omniauth_only? || !allowed_registrations? - end - - def allowed_registrations? - Setting.registrations_mode != 'none' - end - - def omniauth_only? - ENV['OMNIAUTH_ONLY'] == 'true' + forbidden unless allowed_registration?(request.remote_ip, invite) end end diff --git a/app/controllers/api/v1/invites_controller.rb b/app/controllers/api/v1/invites_controller.rb new file mode 100644 index 000000000..ea17ba740 --- /dev/null +++ b/app/controllers/api/v1/invites_controller.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class Api::V1::InvitesController < Api::BaseController + include RegistrationHelper + + skip_before_action :require_authenticated_user! + skip_around_action :set_locale + + before_action :set_invite + before_action :check_enabled_registrations! + + # Override `current_user` to avoid reading session cookies + def current_user; end + + def show + render json: { invite_code: params[:invite_code], instance_api_url: api_v2_instance_url }, status: 200 + end + + private + + def set_invite + @invite = Invite.find_by!(code: params[:invite_code]) + end + + def check_enabled_registrations! + return render json: { error: I18n.t('invites.invalid') }, status: 401 unless @invite.valid_for_use? + + raise Mastodon::NotPermittedError unless allowed_registration?(request.remote_ip, @invite) + end +end diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index 331484f36..8be7c5f19 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true class Auth::RegistrationsController < Devise::RegistrationsController + include RegistrationHelper include RegistrationSpamConcern layout :determine_layout @@ -82,19 +83,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController end def check_enabled_registrations - redirect_to root_path if single_user_mode? || omniauth_only? || !allowed_registrations? || ip_blocked? - end - - def allowed_registrations? - Setting.registrations_mode != 'none' || @invite&.valid_for_use? - end - - def omniauth_only? - ENV['OMNIAUTH_ONLY'] == 'true' - end - - def ip_blocked? - IpBlock.where(severity: :sign_up_block).where('ip >>= ?', request.remote_ip.to_s).exists? + redirect_to root_path unless allowed_registration?(request.remote_ip, @invite) end def invite_code diff --git a/app/helpers/registration_helper.rb b/app/helpers/registration_helper.rb new file mode 100644 index 000000000..ef5462ac8 --- /dev/null +++ b/app/helpers/registration_helper.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module RegistrationHelper + extend ActiveSupport::Concern + + def allowed_registration?(remote_ip, invite) + !Rails.configuration.x.single_user_mode && !omniauth_only? && (registrations_open? || invite&.valid_for_use?) && !ip_blocked?(remote_ip) + end + + def registrations_open? + Setting.registrations_mode != 'none' + end + + def omniauth_only? + ENV['OMNIAUTH_ONLY'] == 'true' + end + + def ip_blocked?(remote_ip) + IpBlock.where(severity: :sign_up_block).exists?(['ip >>= ?', remote_ip.to_s]) + end +end diff --git a/app/services/app_sign_up_service.rb b/app/services/app_sign_up_service.rb index 94547b61b..766588011 100644 --- a/app/services/app_sign_up_service.rb +++ b/app/services/app_sign_up_service.rb @@ -1,12 +1,14 @@ # frozen_string_literal: true class AppSignUpService < BaseService + include RegistrationHelper + def call(app, remote_ip, params) @app = app @remote_ip = remote_ip @params = params - raise Mastodon::NotPermittedError unless allowed_registrations? + raise Mastodon::NotPermittedError unless allowed_registration?(remote_ip, invite) ApplicationRecord.transaction do create_user! @@ -34,8 +36,12 @@ class AppSignUpService < BaseService ) end + def invite + Invite.find_by(code: @params[:invite_code]) if @params[:invite_code].present? + end + def user_params - @params.slice(:email, :password, :agreement, :locale, :time_zone) + @params.slice(:email, :password, :agreement, :locale, :time_zone, :invite_code) end def account_params @@ -45,24 +51,4 @@ class AppSignUpService < BaseService def invite_request_params { text: @params[:reason] } end - - def allowed_registrations? - registrations_open? && !single_user_mode? && !omniauth_only? && !ip_blocked? - end - - def registrations_open? - Setting.registrations_mode != 'none' - end - - def single_user_mode? - Rails.configuration.x.single_user_mode - end - - def omniauth_only? - ENV['OMNIAUTH_ONLY'] == 'true' - end - - def ip_blocked? - IpBlock.where(severity: :sign_up_block).where('ip >>= ?', @remote_ip.to_s).exists? - end end diff --git a/config/locales/en.yml b/config/locales/en.yml index c298c47d3..7319de53d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1368,6 +1368,7 @@ en: '86400': 1 day expires_in_prompt: Never generate: Generate invite link + invalid: This invite is not valid invited_by: 'You were invited by:' max_uses: one: 1 use diff --git a/config/routes.rb b/config/routes.rb index 3adda3b82..82431f6ec 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -81,6 +81,8 @@ Rails.application.routes.draw do resource :outbox, only: [:show], module: :activitypub end + get '/invite/:invite_code', constraints: ->(req) { req.format == :json }, to: 'api/v1/invites#show' + devise_scope :user do get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite diff --git a/spec/requests/invite_spec.rb b/spec/requests/invite_spec.rb new file mode 100644 index 000000000..c44ef2419 --- /dev/null +++ b/spec/requests/invite_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'invites' do + let(:invite) { Fabricate(:invite) } + + context 'when requesting a JSON document' do + it 'returns a JSON document with expected attributes' do + get "/invite/#{invite.code}", headers: { 'Accept' => 'application/activity+json' } + + expect(response).to have_http_status(200) + expect(response.media_type).to eq 'application/json' + + expect(body_as_json[:invite_code]).to eq invite.code + end + end + + context 'when not requesting a JSON document' do + it 'returns an HTML page' do + get "/invite/#{invite.code}" + + expect(response).to have_http_status(200) + expect(response.media_type).to eq 'text/html' + end + end +end diff --git a/spec/services/app_sign_up_service_spec.rb b/spec/services/app_sign_up_service_spec.rb index 253230496..d5946cf9b 100644 --- a/spec/services/app_sign_up_service_spec.rb +++ b/spec/services/app_sign_up_service_spec.rb @@ -10,46 +10,72 @@ RSpec.describe AppSignUpService, type: :service do let(:remote_ip) { IPAddr.new('198.0.2.1') } describe '#call' do - it 'returns nil when registrations are closed' do - tmp = Setting.registrations_mode - Setting.registrations_mode = 'none' - expect { subject.call(app, remote_ip, good_params) }.to raise_error Mastodon::NotPermittedError - Setting.registrations_mode = tmp + let(:params) { good_params } + + shared_examples 'successful registration' do + it 'creates an unconfirmed user with access token and the app\'s scope', :aggregate_failures do + access_token = subject.call(app, remote_ip, params) + expect(access_token).to_not be_nil + expect(access_token.scopes.to_s).to eq 'read write' + + user = User.find_by(id: access_token.resource_owner_id) + expect(user).to_not be_nil + expect(user.confirmed?).to be false + + expect(user.account).to_not be_nil + expect(user.invite_request).to be_nil + end + end + + context 'when registrations are closed' do + around do |example| + tmp = Setting.registrations_mode + Setting.registrations_mode = 'none' + + example.run + + Setting.registrations_mode = tmp + end + + it 'raises an error', :aggregate_failures do + expect { subject.call(app, remote_ip, good_params) }.to raise_error Mastodon::NotPermittedError + end + + context 'when using a valid invite' do + let(:params) { good_params.merge({ invite_code: invite.code }) } + let(:invite) { Fabricate(:invite) } + + before do + invite.user.approve! + end + + it_behaves_like 'successful registration' + end + + context 'when using an invalid invite' do + let(:params) { good_params.merge({ invite_code: invite.code }) } + let(:invite) { Fabricate(:invite, uses: 1, max_uses: 1) } + + it 'raises an error', :aggregate_failures do + expect { subject.call(app, remote_ip, params) }.to raise_error Mastodon::NotPermittedError + end + end end it 'raises an error when params are missing' do expect { subject.call(app, remote_ip, {}) }.to raise_error ActiveRecord::RecordInvalid end - it 'creates an unconfirmed user with access token' do - access_token = subject.call(app, remote_ip, good_params) - expect(access_token).to_not be_nil - user = User.find_by(id: access_token.resource_owner_id) - expect(user).to_not be_nil - expect(user.confirmed?).to be false - end + it_behaves_like 'successful registration' - it 'creates access token with the app\'s scopes' do - access_token = subject.call(app, remote_ip, good_params) - expect(access_token).to_not be_nil - expect(access_token.scopes.to_s).to eq 'read write' - end - - it 'creates an account' do - access_token = subject.call(app, remote_ip, good_params) - expect(access_token).to_not be_nil - user = User.find_by(id: access_token.resource_owner_id) - expect(user).to_not be_nil - expect(user.account).to_not be_nil - expect(user.invite_request).to be_nil - end - - it 'creates an account with invite request text' do - access_token = subject.call(app, remote_ip, good_params.merge(reason: 'Foo bar')) - expect(access_token).to_not be_nil - user = User.find_by(id: access_token.resource_owner_id) - expect(user).to_not be_nil - expect(user.invite_request&.text).to eq 'Foo bar' + context 'when given an invite request text' do + it 'creates an account with invite request text' do + access_token = subject.call(app, remote_ip, good_params.merge(reason: 'Foo bar')) + expect(access_token).to_not be_nil + user = User.find_by(id: access_token.resource_owner_id) + expect(user).to_not be_nil + expect(user.invite_request&.text).to eq 'Foo bar' + end end end end From ed79713f3ad20a78640f113d44454bab387a2d8c Mon Sep 17 00:00:00 2001 From: pajowu <pajowu@pajowu.de> Date: Mon, 13 Nov 2023 14:27:50 +0100 Subject: [PATCH 013/255] Fix modal content not being selectable (#27813) --- app/javascript/styles/mastodon/components.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index ae8e23f53..c8cfe46a8 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -5226,6 +5226,7 @@ a.status-card { .modal-root__modal { pointer-events: auto; + user-select: text; display: flex; } From 0c98a9d9becec126ea9a53619045dbb1b88f555a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:01:07 +0100 Subject: [PATCH 014/255] Update devDependencies (non-major) (#25612) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 828 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 434 insertions(+), 394 deletions(-) diff --git a/yarn.lock b/yarn.lock index c1e9ec9a4..891eb59fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,10 +12,10 @@ __metadata: languageName: node linkType: hard -"@adobe/css-tools@npm:^4.0.1": - version: 4.3.0 - resolution: "@adobe/css-tools@npm:4.3.0" - checksum: 70401c49ab6b7d715147c3637fc6467608276253150c1a5fa933ee45d7c1472b5188e31c1760d06c8a19c5bc2b2914583daa33486d7eac1e8fc7c6dc76a57b3c +"@adobe/css-tools@npm:^4.3.1": + version: 4.3.1 + resolution: "@adobe/css-tools@npm:4.3.1" + checksum: 05672719b544cc0c21ae3ed0eb6349bf458e9d09457578eeeb07cf0f696469ac6417e9c9be1b129e5d6a18098a061c1db55b2275591760ef30a79822436fcbfa languageName: node linkType: hard @@ -1538,29 +1538,29 @@ __metadata: languageName: node linkType: hard -"@csstools/css-parser-algorithms@npm:^2.3.0": - version: 2.3.1 - resolution: "@csstools/css-parser-algorithms@npm:2.3.1" +"@csstools/css-parser-algorithms@npm:^2.3.1": + version: 2.3.2 + resolution: "@csstools/css-parser-algorithms@npm:2.3.2" peerDependencies: - "@csstools/css-tokenizer": ^2.2.0 - checksum: 0f1688cc5de75f41af4581a0b4df994e9af90f6df2b3f962e0680c4ed8e2aa32b23fbf3ba4fdaffc09a9afcf93fcf13a9743204f179bab57a7603ce88cb635e8 + "@csstools/css-tokenizer": ^2.2.1 + checksum: ccae373a3ab5c10716418b69ce1f6db10a26d3a2d60b65df5fe69099afe4fb1d3192925f3c0f93c3b17c3ab1964b0f39ad2b0e97312ec4a51caa55d6b6a31672 languageName: node linkType: hard -"@csstools/css-tokenizer@npm:^2.1.1": - version: 2.2.0 - resolution: "@csstools/css-tokenizer@npm:2.2.0" - checksum: 7a6178d5a148e426ea79d4b2761857daacd7cde00512b45697146228d59183b0043f9803b48be55299f5a331f07ff14477612c608f18df7550ee642467d74564 +"@csstools/css-tokenizer@npm:^2.2.0": + version: 2.2.1 + resolution: "@csstools/css-tokenizer@npm:2.2.1" + checksum: 0c6901d291e99c567893846a47068057c2a28b3edc4219b6da589a530f55f51ddd4675f906f707b393bfe7a508ab2604bf3f75708f064db857bb277636bd5a44 languageName: node linkType: hard -"@csstools/media-query-list-parser@npm:^2.1.2": - version: 2.1.4 - resolution: "@csstools/media-query-list-parser@npm:2.1.4" +"@csstools/media-query-list-parser@npm:^2.1.4": + version: 2.1.5 + resolution: "@csstools/media-query-list-parser@npm:2.1.5" peerDependencies: - "@csstools/css-parser-algorithms": ^2.3.1 - "@csstools/css-tokenizer": ^2.2.0 - checksum: a796ebc8df7d1c8bc2bb71f152b6bedd540bd6679a33a50c1d99f8c383a24d79e9cb8fa59b2ad8f39da12c9d4501fd799caa16da542c23b8dff8257b0b5a0ea7 + "@csstools/css-parser-algorithms": ^2.3.2 + "@csstools/css-tokenizer": ^2.2.1 + checksum: ae0692c6f92cdc82053291c7a50028b692094dfed795f0259571c5eb40f4b3fa580182ac3701e56c2834e40a62a122ea6639299e43ae88b3a835ae4c869a1a12 languageName: node linkType: hard @@ -1777,16 +1777,16 @@ __metadata: linkType: hard "@formatjs/cli@npm:^6.1.1": - version: 6.1.3 - resolution: "@formatjs/cli@npm:6.1.3" + version: 6.2.3 + resolution: "@formatjs/cli@npm:6.2.3" peerDependencies: - "@vue/compiler-sfc": ^3.2.34 + vue: ^3.3.4 peerDependenciesMeta: - "@vue/compiler-sfc": + vue: optional: true bin: formatjs: bin/formatjs - checksum: d7f069b4813c7c1a4fd7e16906da6bc024553c5df3d3ebb0b3da12ec23bb763d184c0424c562bc7ef89d62a963dadd114dd5acb5acec8f0c9160a36bb79f05c2 + checksum: 91eada7676333e2e647cbfbf9c0da88e4ca52e7b486dca73a7299594b0b0dea99de00e1b4110fac993633feb4bf5f26c97885b1a870dfd0ef95688d7f3234a03 languageName: node linkType: hard @@ -2061,50 +2061,50 @@ __metadata: languageName: node linkType: hard -"@jest/console@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/console@npm:29.6.2" +"@jest/console@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/console@npm:29.7.0" dependencies: - "@jest/types": "npm:^29.6.1" + "@jest/types": "npm:^29.6.3" "@types/node": "npm:*" chalk: "npm:^4.0.0" - jest-message-util: "npm:^29.6.2" - jest-util: "npm:^29.6.2" + jest-message-util: "npm:^29.7.0" + jest-util: "npm:^29.7.0" slash: "npm:^3.0.0" - checksum: cdd97d89df5e3e84ba7927ba58a297eb0eae25190575299fede876f7d09a08dc120094be08e49bf01859c54053470215194c0d9a64fc56beb735c5de4de8c5a8 + checksum: 7be408781d0a6f657e969cbec13b540c329671819c2f57acfad0dae9dbfe2c9be859f38fe99b35dba9ff1536937dc6ddc69fdcd2794812fa3c647a1619797f6c languageName: node linkType: hard -"@jest/core@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/core@npm:29.6.2" +"@jest/core@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/core@npm:29.7.0" dependencies: - "@jest/console": "npm:^29.6.2" - "@jest/reporters": "npm:^29.6.2" - "@jest/test-result": "npm:^29.6.2" - "@jest/transform": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/console": "npm:^29.7.0" + "@jest/reporters": "npm:^29.7.0" + "@jest/test-result": "npm:^29.7.0" + "@jest/transform": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" "@types/node": "npm:*" ansi-escapes: "npm:^4.2.1" chalk: "npm:^4.0.0" ci-info: "npm:^3.2.0" exit: "npm:^0.1.2" graceful-fs: "npm:^4.2.9" - jest-changed-files: "npm:^29.5.0" - jest-config: "npm:^29.6.2" - jest-haste-map: "npm:^29.6.2" - jest-message-util: "npm:^29.6.2" - jest-regex-util: "npm:^29.4.3" - jest-resolve: "npm:^29.6.2" - jest-resolve-dependencies: "npm:^29.6.2" - jest-runner: "npm:^29.6.2" - jest-runtime: "npm:^29.6.2" - jest-snapshot: "npm:^29.6.2" - jest-util: "npm:^29.6.2" - jest-validate: "npm:^29.6.2" - jest-watcher: "npm:^29.6.2" + jest-changed-files: "npm:^29.7.0" + jest-config: "npm:^29.7.0" + jest-haste-map: "npm:^29.7.0" + jest-message-util: "npm:^29.7.0" + jest-regex-util: "npm:^29.6.3" + jest-resolve: "npm:^29.7.0" + jest-resolve-dependencies: "npm:^29.7.0" + jest-runner: "npm:^29.7.0" + jest-runtime: "npm:^29.7.0" + jest-snapshot: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + jest-validate: "npm:^29.7.0" + jest-watcher: "npm:^29.7.0" micromatch: "npm:^4.0.4" - pretty-format: "npm:^29.6.2" + pretty-format: "npm:^29.7.0" slash: "npm:^3.0.0" strip-ansi: "npm:^6.0.0" peerDependencies: @@ -2112,23 +2112,23 @@ __metadata: peerDependenciesMeta: node-notifier: optional: true - checksum: 066fc9dc66bb3785c2670280f05cb4f01a776a2d88bc6106ad4224e4a1064b1dbe3752545b4d744d6e0e3203fb0a2a102e9864104f160f2266fd30e756d9d693 + checksum: 934f7bf73190f029ac0f96662c85cd276ec460d407baf6b0dbaec2872e157db4d55a7ee0b1c43b18874602f662b37cb973dda469a4e6d88b4e4845b521adeeb2 languageName: node linkType: hard -"@jest/environment@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/environment@npm:29.6.2" +"@jest/environment@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/environment@npm:29.7.0" dependencies: - "@jest/fake-timers": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/fake-timers": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" "@types/node": "npm:*" - jest-mock: "npm:^29.6.2" - checksum: 82f040b4f729e1a3ab9e61b33e009a7b4ccf572ff94fc157e6fe8ecd267c8af53c8c02853bfe7f023d0f6bf35edf06b6bc7873efc433f335a3774b6c2445662d + jest-mock: "npm:^29.7.0" + checksum: c7b1b40c618f8baf4d00609022d2afa086d9c6acc706f303a70bb4b67275868f620ad2e1a9efc5edd418906157337cce50589a627a6400bbdf117d351b91ef86 languageName: node linkType: hard -"@jest/expect-utils@npm:^29.6.2, @jest/expect-utils@npm:^29.7.0": +"@jest/expect-utils@npm:^29.7.0": version: 29.7.0 resolution: "@jest/expect-utils@npm:29.7.0" dependencies: @@ -2137,51 +2137,51 @@ __metadata: languageName: node linkType: hard -"@jest/expect@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/expect@npm:29.6.2" +"@jest/expect@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/expect@npm:29.7.0" dependencies: - expect: "npm:^29.6.2" - jest-snapshot: "npm:^29.6.2" - checksum: 2cd9a5613b1bae5300dd16d76c7790d1d3b43cb55654dc2b64b202d1522bb03844f88c7bc60b72e3095c8479873ade91009ab0cb8a851842dab00d4d9fc1e3cb + expect: "npm:^29.7.0" + jest-snapshot: "npm:^29.7.0" + checksum: b41f193fb697d3ced134349250aed6ccea075e48c4f803159db102b826a4e473397c68c31118259868fd69a5cba70e97e1c26d2c2ff716ca39dc73a2ccec037e languageName: node linkType: hard -"@jest/fake-timers@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/fake-timers@npm:29.6.2" +"@jest/fake-timers@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/fake-timers@npm:29.7.0" dependencies: - "@jest/types": "npm:^29.6.1" + "@jest/types": "npm:^29.6.3" "@sinonjs/fake-timers": "npm:^10.0.2" "@types/node": "npm:*" - jest-message-util: "npm:^29.6.2" - jest-mock: "npm:^29.6.2" - jest-util: "npm:^29.6.2" - checksum: 4f333b7f8f6bc8e0549e3838e68c3859de1faa3e0639f8ede2786602ec1c237f4691e7bd13649b308ddfaf3fd5aa6b75067fe34f6b6dfa9c0b570773611e0e73 + jest-message-util: "npm:^29.7.0" + jest-mock: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + checksum: cf0a8bcda801b28dc2e2b2ba36302200ee8104a45ad7a21e6c234148932f826cb3bc57c8df3b7b815aeea0861d7b6ca6f0d4778f93b9219398ef28749e03595c languageName: node linkType: hard -"@jest/globals@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/globals@npm:29.6.2" +"@jest/globals@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/globals@npm:29.7.0" dependencies: - "@jest/environment": "npm:^29.6.2" - "@jest/expect": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" - jest-mock: "npm:^29.6.2" - checksum: 3ee73f13d51a08b9fe3bc39305a3b9c0259a7610d89f17b9579684b80bdff3e079adc81d6aec298f5ebe07b43ba0dfdb305be2747b9dc87aa7f337bddc83fedc + "@jest/environment": "npm:^29.7.0" + "@jest/expect": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + jest-mock: "npm:^29.7.0" + checksum: a385c99396878fe6e4460c43bd7bb0a5cc52befb462cc6e7f2a3810f9e7bcce7cdeb51908fd530391ee452dc856c98baa2c5f5fa8a5b30b071d31ef7f6955cea languageName: node linkType: hard -"@jest/reporters@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/reporters@npm:29.6.2" +"@jest/reporters@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/reporters@npm:29.7.0" dependencies: "@bcoe/v8-coverage": "npm:^0.2.3" - "@jest/console": "npm:^29.6.2" - "@jest/test-result": "npm:^29.6.2" - "@jest/transform": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/console": "npm:^29.7.0" + "@jest/test-result": "npm:^29.7.0" + "@jest/transform": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" "@jridgewell/trace-mapping": "npm:^0.3.18" "@types/node": "npm:*" chalk: "npm:^4.0.0" @@ -2190,13 +2190,13 @@ __metadata: glob: "npm:^7.1.3" graceful-fs: "npm:^4.2.9" istanbul-lib-coverage: "npm:^3.0.0" - istanbul-lib-instrument: "npm:^5.1.0" + istanbul-lib-instrument: "npm:^6.0.0" istanbul-lib-report: "npm:^3.0.0" istanbul-lib-source-maps: "npm:^4.0.0" istanbul-reports: "npm:^3.1.3" - jest-message-util: "npm:^29.6.2" - jest-util: "npm:^29.6.2" - jest-worker: "npm:^29.6.2" + jest-message-util: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + jest-worker: "npm:^29.7.0" slash: "npm:^3.0.0" string-length: "npm:^4.0.1" strip-ansi: "npm:^6.0.0" @@ -2206,7 +2206,7 @@ __metadata: peerDependenciesMeta: node-notifier: optional: true - checksum: d4321978208fa8c64ff4e14694508ec8fa5712801b66db62a6c58456798ffc2fab5761db24b1c3596664f2ad0862fcabc69927f0ed54cc9f219689a77cc7db4a + checksum: a754402a799541c6e5aff2c8160562525e2a47e7d568f01ebfc4da66522de39cbb809bbb0a841c7052e4270d79214e70aec3c169e4eae42a03bc1a8a20cb9fa2 languageName: node linkType: hard @@ -2219,65 +2219,65 @@ __metadata: languageName: node linkType: hard -"@jest/source-map@npm:^29.6.0": - version: 29.6.0 - resolution: "@jest/source-map@npm:29.6.0" +"@jest/source-map@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/source-map@npm:29.6.3" dependencies: "@jridgewell/trace-mapping": "npm:^0.3.18" callsites: "npm:^3.0.0" graceful-fs: "npm:^4.2.9" - checksum: afa654e3634ad74d5f8388ccffd7ecbd745bdce7f6f0860b69c07827c3ee5bb408f52b6c3136b43157ef5874c099059484e43bd3aa391232ab27d8c330399789 + checksum: a2f177081830a2e8ad3f2e29e20b63bd40bade294880b595acf2fc09ec74b6a9dd98f126a2baa2bf4941acd89b13a4ade5351b3885c224107083a0059b60a219 languageName: node linkType: hard -"@jest/test-result@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/test-result@npm:29.6.2" +"@jest/test-result@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/test-result@npm:29.7.0" dependencies: - "@jest/console": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/console": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" "@types/istanbul-lib-coverage": "npm:^2.0.0" collect-v8-coverage: "npm:^1.0.0" - checksum: 9c373db297d6cc4b23b143592b3121da047890ba3609115e4db7b94220095d5e32a11f7179ca3dfa1ab29fa30a5e51cbdbbdf58dcd8ef3216e92e86d2aa3251c + checksum: 7de54090e54a674ca173470b55dc1afdee994f2d70d185c80236003efd3fa2b753fff51ffcdda8e2890244c411fd2267529d42c4a50a8303755041ee493e6a04 languageName: node linkType: hard -"@jest/test-sequencer@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/test-sequencer@npm:29.6.2" +"@jest/test-sequencer@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/test-sequencer@npm:29.7.0" dependencies: - "@jest/test-result": "npm:^29.6.2" + "@jest/test-result": "npm:^29.7.0" graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.6.2" + jest-haste-map: "npm:^29.7.0" slash: "npm:^3.0.0" - checksum: dc6a37f0eb93a72ce76a5100f8adb97e40bb0ab9b6f49b07476e0b83b07d1366803185b3d64da2219448312fa78a687f473f54e0c1da08efc4d2e1cb2d3c1dfb + checksum: 593a8c4272797bb5628984486080cbf57aed09c7cfdc0a634e8c06c38c6bef329c46c0016e84555ee55d1cd1f381518cf1890990ff845524c1123720c8c1481b languageName: node linkType: hard -"@jest/transform@npm:^29.6.2": - version: 29.6.2 - resolution: "@jest/transform@npm:29.6.2" +"@jest/transform@npm:^29.7.0": + version: 29.7.0 + resolution: "@jest/transform@npm:29.7.0" dependencies: "@babel/core": "npm:^7.11.6" - "@jest/types": "npm:^29.6.1" + "@jest/types": "npm:^29.6.3" "@jridgewell/trace-mapping": "npm:^0.3.18" babel-plugin-istanbul: "npm:^6.1.1" chalk: "npm:^4.0.0" convert-source-map: "npm:^2.0.0" fast-json-stable-stringify: "npm:^2.1.0" graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.6.2" - jest-regex-util: "npm:^29.4.3" - jest-util: "npm:^29.6.2" + jest-haste-map: "npm:^29.7.0" + jest-regex-util: "npm:^29.6.3" + jest-util: "npm:^29.7.0" micromatch: "npm:^4.0.4" pirates: "npm:^4.0.4" slash: "npm:^3.0.0" write-file-atomic: "npm:^4.0.2" - checksum: dce3a28ca01ce78923bb0faf7ff4fa6e64f1ec77a729a89f874b05a98c8f4408df52fc41a9e39755e9490660163ecebb58d2364530391a443fc2e4bd0e4195d6 + checksum: 7f4a7f73dcf45dfdf280c7aa283cbac7b6e5a904813c3a93ead7e55873761fc20d5c4f0191d2019004fac6f55f061c82eb3249c2901164ad80e362e7a7ede5a6 languageName: node linkType: hard -"@jest/types@npm:^29.6.1, @jest/types@npm:^29.6.3": +"@jest/types@npm:^29.6.3": version: 29.6.3 resolution: "@jest/types@npm:29.6.3" dependencies: @@ -2941,10 +2941,10 @@ __metadata: linkType: hard "@testing-library/jest-dom@npm:^6.0.0": - version: 6.0.0 - resolution: "@testing-library/jest-dom@npm:6.0.0" + version: 6.1.4 + resolution: "@testing-library/jest-dom@npm:6.1.4" dependencies: - "@adobe/css-tools": "npm:^4.0.1" + "@adobe/css-tools": "npm:^4.3.1" "@babel/runtime": "npm:^7.9.2" aria-query: "npm:^5.0.0" chalk: "npm:^3.0.0" @@ -2966,13 +2966,13 @@ __metadata: optional: true vitest: optional: true - checksum: dd5a7ff79dad99b08195cab8d7b818b3de0d02f6c84b5d28d5dbca265ceb867931a0ff79da2279a2d476db1cdafb81c14255d898f0bd1ace9d0b36896368cf96 + checksum: 2e23f120613fd8ae6d5169bbc94f1a2e4c82b07182057dc94db8ec54ebf32555833442e6c43a187e59715d83704ffb5df49ba88a71f6f32d2683f3d95ba721c7 languageName: node linkType: hard "@testing-library/react@npm:^14.0.0": - version: 14.0.0 - resolution: "@testing-library/react@npm:14.0.0" + version: 14.1.0 + resolution: "@testing-library/react@npm:14.1.0" dependencies: "@babel/runtime": "npm:^7.12.5" "@testing-library/dom": "npm:^9.0.0" @@ -2980,7 +2980,7 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 81035913024faf18ba7e163418af517b2c3b85aef496fbd6334bda38f6f6dd4072678c6b76c41148b46b7fc846764f875e1156cbfc7643ffa1b62ee069d78951 + checksum: 357ad80b11bdd4b6d10d2fb1bf86d5b39fb457cf09293033cf42bcc7a95738a86a2b12b760ae15bad326da0b9c074ca015d2bbf0baae7da38fdbc7c808925820 languageName: node linkType: hard @@ -4702,20 +4702,20 @@ __metadata: languageName: node linkType: hard -"babel-jest@npm:^29.5.0, babel-jest@npm:^29.6.2": - version: 29.6.2 - resolution: "babel-jest@npm:29.6.2" +"babel-jest@npm:^29.5.0, babel-jest@npm:^29.7.0": + version: 29.7.0 + resolution: "babel-jest@npm:29.7.0" dependencies: - "@jest/transform": "npm:^29.6.2" + "@jest/transform": "npm:^29.7.0" "@types/babel__core": "npm:^7.1.14" babel-plugin-istanbul: "npm:^6.1.1" - babel-preset-jest: "npm:^29.5.0" + babel-preset-jest: "npm:^29.6.3" chalk: "npm:^4.0.0" graceful-fs: "npm:^4.2.9" slash: "npm:^3.0.0" peerDependencies: "@babel/core": ^7.8.0 - checksum: c1ebaecd1323852867765a6920ab8b5e1e4236254415090a682e0ebf6a3339a9861f65791b23acad2e3a4c4bf5bca31c9abc154306ba7cf9725c2f6e78c92444 + checksum: 2eda9c1391e51936ca573dd1aedfee07b14c59b33dbe16ef347873ddd777bcf6e2fc739681e9e9661ab54ef84a3109a03725be2ac32cd2124c07ea4401cbe8c1 languageName: node linkType: hard @@ -4766,15 +4766,15 @@ __metadata: languageName: node linkType: hard -"babel-plugin-jest-hoist@npm:^29.5.0": - version: 29.5.0 - resolution: "babel-plugin-jest-hoist@npm:29.5.0" +"babel-plugin-jest-hoist@npm:^29.6.3": + version: 29.6.3 + resolution: "babel-plugin-jest-hoist@npm:29.6.3" dependencies: "@babel/template": "npm:^7.3.3" "@babel/types": "npm:^7.3.3" "@types/babel__core": "npm:^7.1.14" "@types/babel__traverse": "npm:^7.0.6" - checksum: 385547c4d81647848dc3e86fecf4381032be99ed97d87aee78d422631f651042600371ee31e37ec9bb6f4a0a4f296b3b5798d69c410626ea94eae76d9c64da63 + checksum: 7e6451caaf7dce33d010b8aafb970e62f1b0c0b57f4978c37b0d457bbcf0874d75a395a102daf0bae0bd14eafb9f6e9a165ee5e899c0a4f1f3bb2e07b304ed2e languageName: node linkType: hard @@ -4892,15 +4892,15 @@ __metadata: languageName: node linkType: hard -"babel-preset-jest@npm:^29.5.0": - version: 29.5.0 - resolution: "babel-preset-jest@npm:29.5.0" +"babel-preset-jest@npm:^29.6.3": + version: 29.6.3 + resolution: "babel-preset-jest@npm:29.6.3" dependencies: - babel-plugin-jest-hoist: "npm:^29.5.0" + babel-plugin-jest-hoist: "npm:^29.6.3" babel-preset-current-node-syntax: "npm:^1.0.0" peerDependencies: "@babel/core": ^7.0.0 - checksum: 752b8682c8cf55bca46d870003f4ce43a4ba0fcaa1138ff7f0e02340628e221810b0c2c3e77a7d5070168dc163eb11907f6c9256f187242abe0f14219d1f6b12 + checksum: ec5fd0276b5630b05f0c14bb97cc3815c6b31600c683ebb51372e54dcb776cff790bdeeabd5b8d01ede375a040337ccbf6a3ccd68d3a34219125945e167ad943 languageName: node linkType: hard @@ -6067,6 +6067,23 @@ __metadata: languageName: node linkType: hard +"create-jest@npm:^29.7.0": + version: 29.7.0 + resolution: "create-jest@npm:29.7.0" + dependencies: + "@jest/types": "npm:^29.6.3" + chalk: "npm:^4.0.0" + exit: "npm:^0.1.2" + graceful-fs: "npm:^4.2.9" + jest-config: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + prompts: "npm:^2.0.1" + bin: + create-jest: bin/create-jest.js + checksum: e7e54c280692470d3398f62a6238fd396327e01c6a0757002833f06d00afc62dd7bfe04ff2b9cd145264460e6b4d1eb8386f2925b7e567f97939843b7b0e812f + languageName: node + linkType: hard + "cross-env@npm:^7.0.3": version: 7.0.3 resolution: "cross-env@npm:7.0.3" @@ -6138,10 +6155,10 @@ __metadata: languageName: node linkType: hard -"css-functions-list@npm:^3.2.0": - version: 3.2.0 - resolution: "css-functions-list@npm:3.2.0" - checksum: 640a1760c6d63536def671b7ccd89c2525a7197fc845a5ae1ec9f380fedd1aa9634f547db81f02f1a3736492867e9333ee8d6bf9aa498d211e36feae0e71a672 +"css-functions-list@npm:^3.2.1": + version: 3.2.1 + resolution: "css-functions-list@npm:3.2.1" + checksum: e6e2d9580437ad6df9f2cf18cff3f941691ec5cbbaebd4cb17a5da40d8d5dac50004807ddd05c00a121d2f21a224e2c5d339fe8e13614af21c00181d7d1c22b9 languageName: node linkType: hard @@ -7820,7 +7837,7 @@ __metadata: languageName: node linkType: hard -"expect@npm:^29.0.0, expect@npm:^29.6.2": +"expect@npm:^29.0.0, expect@npm:^29.7.0": version: 29.7.0 resolution: "expect@npm:29.7.0" dependencies: @@ -7998,6 +8015,15 @@ __metadata: languageName: node linkType: hard +"file-entry-cache@npm:^7.0.0": + version: 7.0.1 + resolution: "file-entry-cache@npm:7.0.1" + dependencies: + flat-cache: "npm:^3.1.1" + checksum: fc0e4f830777e07087f97da9a6734820fdffa2945583355433f40d9819dd97b89f16ac87c07118737a6bc3eb9cf4bd896e7b38b07f0768aefcf44da33e797363 + languageName: node + linkType: hard + "file-loader@npm:^6.2.0": version: 6.2.0 resolution: "file-loader@npm:6.2.0" @@ -8128,14 +8154,14 @@ __metadata: languageName: node linkType: hard -"flat-cache@npm:^3.0.4": - version: 3.1.1 - resolution: "flat-cache@npm:3.1.1" +"flat-cache@npm:^3.0.4, flat-cache@npm:^3.1.1": + version: 3.2.0 + resolution: "flat-cache@npm:3.2.0" dependencies: flatted: "npm:^3.2.9" keyv: "npm:^4.5.3" rimraf: "npm:^3.0.2" - checksum: 15f7f854830089a903ea660809b67ee25632b8b1965da6a328d3dc59d451abe2e9f16ad0b7523571ece2b5424d1e1979469ba25870f76f49ce3bbffc836072ef + checksum: b76f611bd5f5d68f7ae632e3ae503e678d205cf97a17c6ab5b12f6ca61188b5f1f7464503efae6dc18683ed8f0b41460beb48ac4b9ac63fe6201296a91ba2f75 languageName: node linkType: hard @@ -9955,7 +9981,7 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-instrument@npm:^5.0.4, istanbul-lib-instrument@npm:^5.1.0": +"istanbul-lib-instrument@npm:^5.0.4": version: 5.2.1 resolution: "istanbul-lib-instrument@npm:5.2.1" dependencies: @@ -9968,6 +9994,19 @@ __metadata: languageName: node linkType: hard +"istanbul-lib-instrument@npm:^6.0.0": + version: 6.0.1 + resolution: "istanbul-lib-instrument@npm:6.0.1" + dependencies: + "@babel/core": "npm:^7.12.3" + "@babel/parser": "npm:^7.14.7" + "@istanbuljs/schema": "npm:^0.1.2" + istanbul-lib-coverage: "npm:^3.2.0" + semver: "npm:^7.5.4" + checksum: 313d61aca3f82a04ad9377841d05061d603ea3d4a4dd281fdda2479ec4ddbc86dc1792c73651f21c93480570d1ecadc5f63011e2df86f30ee662b62c0c00e3d8 + languageName: node + linkType: hard + "istanbul-lib-report@npm:^3.0.0": version: 3.0.1 resolution: "istanbul-lib-report@npm:3.0.1" @@ -10040,59 +10079,59 @@ __metadata: languageName: node linkType: hard -"jest-changed-files@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-changed-files@npm:29.5.0" +"jest-changed-files@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-changed-files@npm:29.7.0" dependencies: execa: "npm:^5.0.0" + jest-util: "npm:^29.7.0" p-limit: "npm:^3.1.0" - checksum: 96334c78507a13c0f11f1360d893ade78fba7fd169825ca4acf7565156ceddd89b952be81c00378fa87ab642d3f44902c34a20f21b561e985e79f6e81fa7e9a8 + checksum: e071384d9e2f6bb462231ac53f29bff86f0e12394c1b49ccafbad225ce2ab7da226279a8a94f421949920bef9be7ef574fd86aee22e8adfa149be73554ab828b languageName: node linkType: hard -"jest-circus@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-circus@npm:29.6.2" +"jest-circus@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-circus@npm:29.7.0" dependencies: - "@jest/environment": "npm:^29.6.2" - "@jest/expect": "npm:^29.6.2" - "@jest/test-result": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/environment": "npm:^29.7.0" + "@jest/expect": "npm:^29.7.0" + "@jest/test-result": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" "@types/node": "npm:*" chalk: "npm:^4.0.0" co: "npm:^4.6.0" dedent: "npm:^1.0.0" is-generator-fn: "npm:^2.0.0" - jest-each: "npm:^29.6.2" - jest-matcher-utils: "npm:^29.6.2" - jest-message-util: "npm:^29.6.2" - jest-runtime: "npm:^29.6.2" - jest-snapshot: "npm:^29.6.2" - jest-util: "npm:^29.6.2" + jest-each: "npm:^29.7.0" + jest-matcher-utils: "npm:^29.7.0" + jest-message-util: "npm:^29.7.0" + jest-runtime: "npm:^29.7.0" + jest-snapshot: "npm:^29.7.0" + jest-util: "npm:^29.7.0" p-limit: "npm:^3.1.0" - pretty-format: "npm:^29.6.2" + pretty-format: "npm:^29.7.0" pure-rand: "npm:^6.0.0" slash: "npm:^3.0.0" stack-utils: "npm:^2.0.3" - checksum: 04f3176bcc3adf0a5d5895f3ce2cb86fafa5d0d03d246cddd0a39021ec4bbc1092ef30792a9d8cdfb1cb6fcee75a277354d65aef6ca8c364fd3747d8ce67e255 + checksum: 8d15344cf7a9f14e926f0deed64ed190c7a4fa1ed1acfcd81e4cc094d3cc5bf7902ebb7b874edc98ada4185688f90c91e1747e0dfd7ac12463b097968ae74b5e languageName: node linkType: hard -"jest-cli@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-cli@npm:29.6.2" +"jest-cli@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-cli@npm:29.7.0" dependencies: - "@jest/core": "npm:^29.6.2" - "@jest/test-result": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/core": "npm:^29.7.0" + "@jest/test-result": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" chalk: "npm:^4.0.0" + create-jest: "npm:^29.7.0" exit: "npm:^0.1.2" - graceful-fs: "npm:^4.2.9" import-local: "npm:^3.0.2" - jest-config: "npm:^29.6.2" - jest-util: "npm:^29.6.2" - jest-validate: "npm:^29.6.2" - prompts: "npm:^2.0.1" + jest-config: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + jest-validate: "npm:^29.7.0" yargs: "npm:^17.3.1" peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -10101,34 +10140,34 @@ __metadata: optional: true bin: jest: bin/jest.js - checksum: 76d359427a573821b0b4f80a8b752e54778b8da1e09e737ae1ff5c29487d762a6f0d16becd5c1d2017cd337295945be82448539f90d04d173c72ee577c6cf897 + checksum: a658fd55050d4075d65c1066364595962ead7661711495cfa1dfeecf3d6d0a8ffec532f3dbd8afbb3e172dd5fd2fb2e813c5e10256e7cf2fea766314942fb43a languageName: node linkType: hard -"jest-config@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-config@npm:29.6.2" +"jest-config@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-config@npm:29.7.0" dependencies: "@babel/core": "npm:^7.11.6" - "@jest/test-sequencer": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" - babel-jest: "npm:^29.6.2" + "@jest/test-sequencer": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" + babel-jest: "npm:^29.7.0" chalk: "npm:^4.0.0" ci-info: "npm:^3.2.0" deepmerge: "npm:^4.2.2" glob: "npm:^7.1.3" graceful-fs: "npm:^4.2.9" - jest-circus: "npm:^29.6.2" - jest-environment-node: "npm:^29.6.2" - jest-get-type: "npm:^29.4.3" - jest-regex-util: "npm:^29.4.3" - jest-resolve: "npm:^29.6.2" - jest-runner: "npm:^29.6.2" - jest-util: "npm:^29.6.2" - jest-validate: "npm:^29.6.2" + jest-circus: "npm:^29.7.0" + jest-environment-node: "npm:^29.7.0" + jest-get-type: "npm:^29.6.3" + jest-regex-util: "npm:^29.6.3" + jest-resolve: "npm:^29.7.0" + jest-runner: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + jest-validate: "npm:^29.7.0" micromatch: "npm:^4.0.4" parse-json: "npm:^5.2.0" - pretty-format: "npm:^29.6.2" + pretty-format: "npm:^29.7.0" slash: "npm:^3.0.0" strip-json-comments: "npm:^3.1.1" peerDependencies: @@ -10139,11 +10178,11 @@ __metadata: optional: true ts-node: optional: true - checksum: 334b8cf02c9c9f5f3685fd6f673d634691a370c9a96f1a855234c7513c409a1cc842f2c8e786da9ef8734d33b6ee95d7b7b4d586c1a4f22bcae59118755d7d2a + checksum: bab23c2eda1fff06e0d104b00d6adfb1d1aabb7128441899c9bff2247bd26710b050a5364281ce8d52b46b499153bf7e3ee88b19831a8f3451f1477a0246a0f1 languageName: node linkType: hard -"jest-diff@npm:^29.6.2, jest-diff@npm:^29.7.0": +"jest-diff@npm:^29.7.0": version: 29.7.0 resolution: "jest-diff@npm:29.7.0" dependencies: @@ -10155,104 +10194,104 @@ __metadata: languageName: node linkType: hard -"jest-docblock@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-docblock@npm:29.4.3" +"jest-docblock@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-docblock@npm:29.7.0" dependencies: detect-newline: "npm:^3.0.0" - checksum: 25cdea8fe77ff09d958abd347e26dcd8766ca69d9935bc626a89d694c91d33be06d4c088b02e4b3f143f532f726a10dff0bfe1e2387a0972a95addf5d64ed407 + checksum: d932a8272345cf6b6142bb70a2bb63e0856cc0093f082821577ea5bdf4643916a98744dfc992189d2b1417c38a11fa42466f6111526bc1fb81366f56410f3be9 languageName: node linkType: hard -"jest-each@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-each@npm:29.6.2" +"jest-each@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-each@npm:29.7.0" dependencies: - "@jest/types": "npm:^29.6.1" + "@jest/types": "npm:^29.6.3" chalk: "npm:^4.0.0" - jest-get-type: "npm:^29.4.3" - jest-util: "npm:^29.6.2" - pretty-format: "npm:^29.6.2" - checksum: b586f5c811011589308f2d8e0d5e596fa26d101e1116b55c624342327b932d3644aac37ce7b6c4eb8ef018893d2a41610ed7edbabfe125c3b46cf9a2b0f03d9b + jest-get-type: "npm:^29.6.3" + jest-util: "npm:^29.7.0" + pretty-format: "npm:^29.7.0" + checksum: f7f9a90ebee80cc688e825feceb2613627826ac41ea76a366fa58e669c3b2403d364c7c0a74d862d469b103c843154f8456d3b1c02b487509a12afa8b59edbb4 languageName: node linkType: hard "jest-environment-jsdom@npm:^29.5.0": - version: 29.6.2 - resolution: "jest-environment-jsdom@npm:29.6.2" + version: 29.7.0 + resolution: "jest-environment-jsdom@npm:29.7.0" dependencies: - "@jest/environment": "npm:^29.6.2" - "@jest/fake-timers": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/environment": "npm:^29.7.0" + "@jest/fake-timers": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" "@types/jsdom": "npm:^20.0.0" "@types/node": "npm:*" - jest-mock: "npm:^29.6.2" - jest-util: "npm:^29.6.2" + jest-mock: "npm:^29.7.0" + jest-util: "npm:^29.7.0" jsdom: "npm:^20.0.0" peerDependencies: canvas: ^2.5.0 peerDependenciesMeta: canvas: optional: true - checksum: 7f5885f6fa42d7d14d7dbdc58186283d3ed409a0abc8289bf365a4a2e92ea84d0eeb2087cd5ce6db39394652d817e4c7505d28555e2594309a324634d2b45718 + checksum: 139b94e2c8ec1bb5a46ce17df5211da65ce867354b3fd4e00fa6a0d1da95902df4cf7881273fc6ea937e5c325d39d6773f0d41b6c469363334de9d489d2c321f languageName: node linkType: hard -"jest-environment-node@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-environment-node@npm:29.6.2" +"jest-environment-node@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-environment-node@npm:29.7.0" dependencies: - "@jest/environment": "npm:^29.6.2" - "@jest/fake-timers": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/environment": "npm:^29.7.0" + "@jest/fake-timers": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" "@types/node": "npm:*" - jest-mock: "npm:^29.6.2" - jest-util: "npm:^29.6.2" - checksum: fea7c71e2b6ef901679983809918f670551d0122380f60695df554ca1dc9a065ec347e14c516c9b5a184494572320cd1696bd5bc817853a3e6cdb89b44d4054e + jest-mock: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + checksum: 61f04fec077f8b1b5c1a633e3612fc0c9aa79a0ab7b05600683428f1e01a4d35346c474bde6f439f9fcc1a4aa9a2861ff852d079a43ab64b02105d1004b2592b languageName: node linkType: hard -"jest-get-type@npm:^29.4.3, jest-get-type@npm:^29.6.3": +"jest-get-type@npm:^29.6.3": version: 29.6.3 resolution: "jest-get-type@npm:29.6.3" checksum: 552e7a97a983d3c2d4e412a44eb7de0430ff773dd99f7500962c268d6dfbfa431d7d08f919c9d960530e5f7f78eb47f267ad9b318265e5092b3ff9ede0db7c2b languageName: node linkType: hard -"jest-haste-map@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-haste-map@npm:29.6.2" +"jest-haste-map@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-haste-map@npm:29.7.0" dependencies: - "@jest/types": "npm:^29.6.1" + "@jest/types": "npm:^29.6.3" "@types/graceful-fs": "npm:^4.1.3" "@types/node": "npm:*" anymatch: "npm:^3.0.3" fb-watchman: "npm:^2.0.0" fsevents: "npm:^2.3.2" graceful-fs: "npm:^4.2.9" - jest-regex-util: "npm:^29.4.3" - jest-util: "npm:^29.6.2" - jest-worker: "npm:^29.6.2" + jest-regex-util: "npm:^29.6.3" + jest-util: "npm:^29.7.0" + jest-worker: "npm:^29.7.0" micromatch: "npm:^4.0.4" walker: "npm:^1.0.8" dependenciesMeta: fsevents: optional: true - checksum: 12c921ff059613b67e8b3a0730fe8f5f38e39a1aeb2050948a5c6890c4705f39decd4f7da8ebc7ede22e0eeef37fef2e9256952ac6557dd3bcd62416cab0612f + checksum: 2683a8f29793c75a4728787662972fedd9267704c8f7ef9d84f2beed9a977f1cf5e998c07b6f36ba5603f53cb010c911fe8cd0ac9886e073fe28ca66beefd30c languageName: node linkType: hard -"jest-leak-detector@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-leak-detector@npm:29.6.2" +"jest-leak-detector@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-leak-detector@npm:29.7.0" dependencies: - jest-get-type: "npm:^29.4.3" - pretty-format: "npm:^29.6.2" - checksum: 70eb538bb137b769908d4d1e15d9b380a06285ea31c1d2ae05bcc9269863efe6369484cb33bf6c6f3e325dd53cd252cd7e868bdbd2b31367a9b41b449eb8e4a9 + jest-get-type: "npm:^29.6.3" + pretty-format: "npm:^29.7.0" + checksum: 71bb9f77fc489acb842a5c7be030f2b9acb18574dc9fb98b3100fc57d422b1abc55f08040884bd6e6dbf455047a62f7eaff12aa4058f7cbdc11558718ca6a395 languageName: node linkType: hard -"jest-matcher-utils@npm:^29.6.2, jest-matcher-utils@npm:^29.7.0": +"jest-matcher-utils@npm:^29.7.0": version: 29.7.0 resolution: "jest-matcher-utils@npm:29.7.0" dependencies: @@ -10264,7 +10303,7 @@ __metadata: languageName: node linkType: hard -"jest-message-util@npm:^29.6.2, jest-message-util@npm:^29.7.0": +"jest-message-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-message-util@npm:29.7.0" dependencies: @@ -10281,14 +10320,14 @@ __metadata: languageName: node linkType: hard -"jest-mock@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-mock@npm:29.6.2" +"jest-mock@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-mock@npm:29.7.0" dependencies: - "@jest/types": "npm:^29.6.1" + "@jest/types": "npm:^29.6.3" "@types/node": "npm:*" - jest-util: "npm:^29.6.2" - checksum: 34e8119876696d640db1b33b2c88f3bbd56b676f5e82ae65babdb56b0dab054d856b903785d38e1e8e3274549622b9a4556bfaa301d75fe4e2b30494cac5b8ee + jest-util: "npm:^29.7.0" + checksum: 7b9f8349ee87695a309fe15c46a74ab04c853369e5c40952d68061d9dc3159a0f0ed73e215f81b07ee97a9faaf10aebe5877a9d6255068a0977eae6a9ff1d5ac languageName: node linkType: hard @@ -10304,128 +10343,128 @@ __metadata: languageName: node linkType: hard -"jest-regex-util@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-regex-util@npm:29.4.3" - checksum: a7a4508bda47c5177e7337fb6fb22e9adab414ba141f224c9992c86973da1ccf5c69040e63636090ad26ef3a123d28bec950fa99496c157444b4f847e5e5a670 +"jest-regex-util@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-regex-util@npm:29.6.3" + checksum: 4e33fb16c4f42111159cafe26397118dcfc4cf08bc178a67149fb05f45546a91928b820894572679d62559839d0992e21080a1527faad65daaae8743a5705a3b languageName: node linkType: hard -"jest-resolve-dependencies@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-resolve-dependencies@npm:29.6.2" +"jest-resolve-dependencies@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-resolve-dependencies@npm:29.7.0" dependencies: - jest-regex-util: "npm:^29.4.3" - jest-snapshot: "npm:^29.6.2" - checksum: b80172d164fe36a3cd9b19c458c3e8075e7935cdaa191f6e2e335f9b5c603faf0785efc35f9cf6c496729de34a3bd98f6cb8dd877c11fa6e17adf385d1ca85a6 + jest-regex-util: "npm:^29.6.3" + jest-snapshot: "npm:^29.7.0" + checksum: b6e9ad8ae5b6049474118ea6441dfddd385b6d1fc471db0136f7c8fbcfe97137a9665e4f837a9f49f15a29a1deb95a14439b7aec812f3f99d08f228464930f0d languageName: node linkType: hard -"jest-resolve@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-resolve@npm:29.6.2" +"jest-resolve@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-resolve@npm:29.7.0" dependencies: chalk: "npm:^4.0.0" graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.6.2" + jest-haste-map: "npm:^29.7.0" jest-pnp-resolver: "npm:^1.2.2" - jest-util: "npm:^29.6.2" - jest-validate: "npm:^29.6.2" + jest-util: "npm:^29.7.0" + jest-validate: "npm:^29.7.0" resolve: "npm:^1.20.0" resolve.exports: "npm:^2.0.0" slash: "npm:^3.0.0" - checksum: df6ace45facf1f9d8f2911fcc1eefcc871afa107748f41a2f84a3d7b707d2211be1450ba5044fe8fa1ffc497b6814309f71f376aac139683ddc7b05b263d45f9 + checksum: 59da5c9c5b50563e959a45e09e2eace783d7f9ac0b5dcc6375dea4c0db938d2ebda97124c8161310082760e8ebbeff9f6b177c15ca2f57fb424f637a5d2adb47 languageName: node linkType: hard -"jest-runner@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-runner@npm:29.6.2" +"jest-runner@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-runner@npm:29.7.0" dependencies: - "@jest/console": "npm:^29.6.2" - "@jest/environment": "npm:^29.6.2" - "@jest/test-result": "npm:^29.6.2" - "@jest/transform": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/console": "npm:^29.7.0" + "@jest/environment": "npm:^29.7.0" + "@jest/test-result": "npm:^29.7.0" + "@jest/transform": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" "@types/node": "npm:*" chalk: "npm:^4.0.0" emittery: "npm:^0.13.1" graceful-fs: "npm:^4.2.9" - jest-docblock: "npm:^29.4.3" - jest-environment-node: "npm:^29.6.2" - jest-haste-map: "npm:^29.6.2" - jest-leak-detector: "npm:^29.6.2" - jest-message-util: "npm:^29.6.2" - jest-resolve: "npm:^29.6.2" - jest-runtime: "npm:^29.6.2" - jest-util: "npm:^29.6.2" - jest-watcher: "npm:^29.6.2" - jest-worker: "npm:^29.6.2" + jest-docblock: "npm:^29.7.0" + jest-environment-node: "npm:^29.7.0" + jest-haste-map: "npm:^29.7.0" + jest-leak-detector: "npm:^29.7.0" + jest-message-util: "npm:^29.7.0" + jest-resolve: "npm:^29.7.0" + jest-runtime: "npm:^29.7.0" + jest-util: "npm:^29.7.0" + jest-watcher: "npm:^29.7.0" + jest-worker: "npm:^29.7.0" p-limit: "npm:^3.1.0" source-map-support: "npm:0.5.13" - checksum: d0f2fc80b01c40b28bb86ace6a1f913a346dbdd81d8ed84e689bc0e21b27f7e9d1b963e6d8ece44df1a870ba14016730ce08444b15f3fdee92a15dff0c6c1aa3 + checksum: 2194b4531068d939f14c8d3274fe5938b77fa73126aedf9c09ec9dec57d13f22c72a3b5af01ac04f5c1cf2e28d0ac0b4a54212a61b05f10b5d6b47f2a1097bb4 languageName: node linkType: hard -"jest-runtime@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-runtime@npm:29.6.2" +"jest-runtime@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-runtime@npm:29.7.0" dependencies: - "@jest/environment": "npm:^29.6.2" - "@jest/fake-timers": "npm:^29.6.2" - "@jest/globals": "npm:^29.6.2" - "@jest/source-map": "npm:^29.6.0" - "@jest/test-result": "npm:^29.6.2" - "@jest/transform": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/environment": "npm:^29.7.0" + "@jest/fake-timers": "npm:^29.7.0" + "@jest/globals": "npm:^29.7.0" + "@jest/source-map": "npm:^29.6.3" + "@jest/test-result": "npm:^29.7.0" + "@jest/transform": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" "@types/node": "npm:*" chalk: "npm:^4.0.0" cjs-module-lexer: "npm:^1.0.0" collect-v8-coverage: "npm:^1.0.0" glob: "npm:^7.1.3" graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.6.2" - jest-message-util: "npm:^29.6.2" - jest-mock: "npm:^29.6.2" - jest-regex-util: "npm:^29.4.3" - jest-resolve: "npm:^29.6.2" - jest-snapshot: "npm:^29.6.2" - jest-util: "npm:^29.6.2" + jest-haste-map: "npm:^29.7.0" + jest-message-util: "npm:^29.7.0" + jest-mock: "npm:^29.7.0" + jest-regex-util: "npm:^29.6.3" + jest-resolve: "npm:^29.7.0" + jest-snapshot: "npm:^29.7.0" + jest-util: "npm:^29.7.0" slash: "npm:^3.0.0" strip-bom: "npm:^4.0.0" - checksum: 026a5fa33fa370561e6ab33a01b59e3e382b72f8eb7a42a85d1c9619bc9123a274ec791b823ad4bf58e20285758e9e895e53da6ae971c92124612f99fe7c7ffe + checksum: 7cd89a1deda0bda7d0941835434e44f9d6b7bd50b5c5d9b0fc9a6c990b2d4d2cab59685ab3cb2850ed4cc37059f6de903af5a50565d7f7f1192a77d3fd6dd2a6 languageName: node linkType: hard -"jest-snapshot@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-snapshot@npm:29.6.2" +"jest-snapshot@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-snapshot@npm:29.7.0" dependencies: "@babel/core": "npm:^7.11.6" "@babel/generator": "npm:^7.7.2" "@babel/plugin-syntax-jsx": "npm:^7.7.2" "@babel/plugin-syntax-typescript": "npm:^7.7.2" "@babel/types": "npm:^7.3.3" - "@jest/expect-utils": "npm:^29.6.2" - "@jest/transform": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/expect-utils": "npm:^29.7.0" + "@jest/transform": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" babel-preset-current-node-syntax: "npm:^1.0.0" chalk: "npm:^4.0.0" - expect: "npm:^29.6.2" + expect: "npm:^29.7.0" graceful-fs: "npm:^4.2.9" - jest-diff: "npm:^29.6.2" - jest-get-type: "npm:^29.4.3" - jest-matcher-utils: "npm:^29.6.2" - jest-message-util: "npm:^29.6.2" - jest-util: "npm:^29.6.2" + jest-diff: "npm:^29.7.0" + jest-get-type: "npm:^29.6.3" + jest-matcher-utils: "npm:^29.7.0" + jest-message-util: "npm:^29.7.0" + jest-util: "npm:^29.7.0" natural-compare: "npm:^1.4.0" - pretty-format: "npm:^29.6.2" + pretty-format: "npm:^29.7.0" semver: "npm:^7.5.3" - checksum: 79f02c2becf90a1b5c5d06833b0a4c9f6e0d7a9fcd36e69f81750ab147180dd06e3565e83c1d79a1ef8b7943c5af3eb3e0119c45e92f78e1189279c4fba2e136 + checksum: 6e9003c94ec58172b4a62864a91c0146513207bedf4e0a06e1e2ac70a4484088a2683e3a0538d8ea913bcfd53dc54a9b98a98cdfa562e7fe1d1339aeae1da570 languageName: node linkType: hard -"jest-util@npm:^29.6.2, jest-util@npm:^29.7.0": +"jest-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-util@npm:29.7.0" dependencies: @@ -10439,33 +10478,33 @@ __metadata: languageName: node linkType: hard -"jest-validate@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-validate@npm:29.6.2" +"jest-validate@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-validate@npm:29.7.0" dependencies: - "@jest/types": "npm:^29.6.1" + "@jest/types": "npm:^29.6.3" camelcase: "npm:^6.2.0" chalk: "npm:^4.0.0" - jest-get-type: "npm:^29.4.3" + jest-get-type: "npm:^29.6.3" leven: "npm:^3.1.0" - pretty-format: "npm:^29.6.2" - checksum: 79af1153268d896deb183230fba547398fde7b8a4f45fe33f1cd5c3b6b84d317e4b87ea7988d1137348c693e7f9450cce7af4529d5b190891bf493bc93024e40 + pretty-format: "npm:^29.7.0" + checksum: a20b930480c1ed68778c739f4739dce39423131bc070cd2505ddede762a5570a256212e9c2401b7ae9ba4d7b7c0803f03c5b8f1561c62348213aba18d9dbece2 languageName: node linkType: hard -"jest-watcher@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-watcher@npm:29.6.2" +"jest-watcher@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-watcher@npm:29.7.0" dependencies: - "@jest/test-result": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/test-result": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" "@types/node": "npm:*" ansi-escapes: "npm:^4.2.1" chalk: "npm:^4.0.0" emittery: "npm:^0.13.1" - jest-util: "npm:^29.6.2" + jest-util: "npm:^29.7.0" string-length: "npm:^4.0.1" - checksum: ba567798961d52b3ca1f853169a5860111ae764de90634b86a4a5cc676848c147bee5d95cd168b5c5941533ed384f677764474d009437a03b6b6a15da6232eb3 + checksum: ec6c75030562fc8f8c727cb8f3b94e75d831fc718785abfc196e1f2a2ebc9a2e38744a15147170039628a853d77a3b695561ce850375ede3a4ee6037a2574567 languageName: node linkType: hard @@ -10480,26 +10519,26 @@ __metadata: languageName: node linkType: hard -"jest-worker@npm:^29.6.2": - version: 29.6.2 - resolution: "jest-worker@npm:29.6.2" +"jest-worker@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-worker@npm:29.7.0" dependencies: "@types/node": "npm:*" - jest-util: "npm:^29.6.2" + jest-util: "npm:^29.7.0" merge-stream: "npm:^2.0.0" supports-color: "npm:^8.0.0" - checksum: 8b978cb4851222e536aef552bdc06a60db580d0f921107fe1a1b94cdc8b39ddeb076b23e5bb96b69752c2f936b803295cdff11484f7c5efaf4562952e2cc0897 + checksum: 5570a3a005b16f46c131968b8a5b56d291f9bbb85ff4217e31c80bd8a02e7de799e59a54b95ca28d5c302f248b54cbffde2d177c2f0f52ffcee7504c6eabf660 languageName: node linkType: hard "jest@npm:^29.5.0": - version: 29.6.2 - resolution: "jest@npm:29.6.2" + version: 29.7.0 + resolution: "jest@npm:29.7.0" dependencies: - "@jest/core": "npm:^29.6.2" - "@jest/types": "npm:^29.6.1" + "@jest/core": "npm:^29.7.0" + "@jest/types": "npm:^29.6.3" import-local: "npm:^3.0.2" - jest-cli: "npm:^29.6.2" + jest-cli: "npm:^29.7.0" peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -10507,7 +10546,7 @@ __metadata: optional: true bin: jest: bin/jest.js - checksum: fdb4df81f2bf1ad58f98f74b6d6f74d7727bd8fd5a8ddefc1e7612b8a68cbd0a4ae134060c5b987b01281f1fe93276c1abb034ef1ce06a0ea1468f288fafc7c1 + checksum: f40eb8171cf147c617cc6ada49d062fbb03b4da666cb8d39cdbfb739a7d75eea4c3ca150fb072d0d273dce0c753db4d0467d54906ad0293f59c54f9db4a09d8b languageName: node linkType: hard @@ -10824,10 +10863,10 @@ __metadata: languageName: node linkType: hard -"known-css-properties@npm:^0.27.0": - version: 0.27.0 - resolution: "known-css-properties@npm:0.27.0" - checksum: 49bf8d0a773039d07726d263c92145fa73be9a18990d54c3b3cebf472fdfb0095124a3fcfca3ccd1225231d4bdf9615c82e029b2d0d508de130f6be7467af9e4 +"known-css-properties@npm:^0.29.0": + version: 0.29.0 + resolution: "known-css-properties@npm:0.29.0" + checksum: f66e9992097b8f54e97dbe729943d4a11b8d3ba15f68dbb3deb8bb0122cb89c22c90c9221ecb1e3f2e236838fe3c0faae319b43908c81b6e254ac43cafde2906 languageName: node linkType: hard @@ -10879,8 +10918,8 @@ __metadata: linkType: hard "lint-staged@npm:^15.0.0": - version: 15.0.2 - resolution: "lint-staged@npm:15.0.2" + version: 15.1.0 + resolution: "lint-staged@npm:15.1.0" dependencies: chalk: "npm:5.3.0" commander: "npm:11.1.0" @@ -10891,10 +10930,10 @@ __metadata: micromatch: "npm:4.0.5" pidtree: "npm:0.6.0" string-argv: "npm:0.3.2" - yaml: "npm:2.3.3" + yaml: "npm:2.3.4" bin: lint-staged: bin/lint-staged.js - checksum: 5c8806137c8c9c63e1156e16f2a2763586a9eab8f24713b95bbfd099308c83f85af2df622fdc326a9f0e455e657718f61f6d4a81067a5c77243e65e822c8f16c + checksum: d427408be98df7558e918593cb765d5caaa67a5cdca89671fb54280a6c959f4e448db36d4f85e8e0bd9c2c1e996aa133916925cf47c9df573b47308d5e298d84 languageName: node linkType: hard @@ -13152,12 +13191,12 @@ __metadata: languageName: node linkType: hard -"postcss-scss@npm:^4.0.7": - version: 4.0.7 - resolution: "postcss-scss@npm:4.0.7" +"postcss-scss@npm:^4.0.9": + version: 4.0.9 + resolution: "postcss-scss@npm:4.0.9" peerDependencies: - postcss: ^8.4.19 - checksum: 2f86938fef39bd766ada496d8ccac840bf9f2dee0d9c6006dc2903ba0fbdc9f5c2d6ead1f3e7508f8d82eee6ad25df7d77e9196c4c6bec8952ef9a7403f30efc + postcss: ^8.4.29 + checksum: f917ecfd4b9113a6648e966a41f027ff7e14238393914978d44596e227a50f084667dc8818742348dc7d8b20130b30d4259aca1d4db86754a9c141202ae03714 languageName: node linkType: hard @@ -13201,7 +13240,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.2.15, postcss@npm:^8.4.24, postcss@npm:^8.4.25": +"postcss@npm:^8.2.15, postcss@npm:^8.4.24, postcss@npm:^8.4.28": version: 8.4.31 resolution: "postcss@npm:8.4.31" dependencies: @@ -13296,11 +13335,11 @@ __metadata: linkType: hard "prettier@npm:^3.0.0": - version: 3.0.1 - resolution: "prettier@npm:3.0.1" + version: 3.1.0 + resolution: "prettier@npm:3.1.0" bin: prettier: bin/prettier.cjs - checksum: 7231768b6e0f0f17cbaa83a4f7cdb100df0229ef1910b0b2cf72ce5ed8ee25ae7ec0d30cde20dcd898a002c6d1fcdb8a6ab0f8f5d8fc1275b7c29ea9e56305f2 + checksum: a45ea70aa97fde162ea4c4aba3dfc7859aa6a732a1db34458d9535dc3c2c16d3bc3fb5689e6cd76aa835562555303b02d9449fd2e15af3b73c8053557e25c5b6 languageName: node linkType: hard @@ -13322,7 +13361,7 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.6.2, pretty-format@npm:^29.7.0": +"pretty-format@npm:^29.0.0, pretty-format@npm:^29.7.0": version: 29.7.0 resolution: "pretty-format@npm:29.7.0" dependencies: @@ -15720,20 +15759,20 @@ __metadata: languageName: node linkType: hard -"stylelint-config-recommended-scss@npm:^13.0.0": - version: 13.0.0 - resolution: "stylelint-config-recommended-scss@npm:13.0.0" +"stylelint-config-recommended-scss@npm:^13.1.0": + version: 13.1.0 + resolution: "stylelint-config-recommended-scss@npm:13.1.0" dependencies: - postcss-scss: "npm:^4.0.7" + postcss-scss: "npm:^4.0.9" stylelint-config-recommended: "npm:^13.0.0" - stylelint-scss: "npm:^5.1.0" + stylelint-scss: "npm:^5.3.0" peerDependencies: postcss: ^8.3.3 stylelint: ^15.10.0 peerDependenciesMeta: postcss: optional: true - checksum: 370152e20e6395800ac89517019f03153b121ce7a7dfa0865442365bf2725935da9df2eb3e8b5ee4e240d1b3a7438ee2cd1932009bdc59da8c2a790066379387 + checksum: e07d0172c7936b4f644138e4129df2f187d297f1f96ce5865ab21ccd1c22caf94220f7caf9d6985e93e515de4c0356f6cb9c924d00df2eee5b3bc237f7e5bb48 languageName: node linkType: hard @@ -15747,10 +15786,10 @@ __metadata: linkType: hard "stylelint-config-standard-scss@npm:^11.0.0": - version: 11.0.0 - resolution: "stylelint-config-standard-scss@npm:11.0.0" + version: 11.1.0 + resolution: "stylelint-config-standard-scss@npm:11.1.0" dependencies: - stylelint-config-recommended-scss: "npm:^13.0.0" + stylelint-config-recommended-scss: "npm:^13.1.0" stylelint-config-standard: "npm:^34.0.0" peerDependencies: postcss: ^8.3.3 @@ -15758,7 +15797,7 @@ __metadata: peerDependenciesMeta: postcss: optional: true - checksum: 9b0766ec11f1e6f690c1e22d74e7f7103f64569bdca966c26ff43f81f55f13797fdb1503338f973672c001daf50b13682361dd4105d22497841437c148f86be5 + checksum: 22d00e75c1eacce9883fd48c3d67b1107b0e39d7d86e9f73deaa332b11c39a9678c947ae2c34cd5159a452ec9a857694ed58b5a851087480d3c9a66dab629415 languageName: node linkType: hard @@ -15773,37 +15812,38 @@ __metadata: languageName: node linkType: hard -"stylelint-scss@npm:^5.1.0": - version: 5.1.0 - resolution: "stylelint-scss@npm:5.1.0" +"stylelint-scss@npm:^5.3.0": + version: 5.3.1 + resolution: "stylelint-scss@npm:5.3.1" dependencies: + known-css-properties: "npm:^0.29.0" postcss-media-query-parser: "npm:^0.2.3" postcss-resolve-nested-selector: "npm:^0.1.1" postcss-selector-parser: "npm:^6.0.13" postcss-value-parser: "npm:^4.2.0" peerDependencies: stylelint: ^14.5.1 || ^15.0.0 - checksum: af176340227e77942429d2032cd345ebc8e40e4ff17a2ce69b6000252da178f21d1a97311a258a81c76c0610a96650c1e2ecdfa0d598a6fc41e31d6a7cd03847 + checksum: 5dfed5f9ac9812cd2ac6ef0272c720dee0326aaaee2998315a23bdcd71b8f04427f29cad634793eea2b45984182e20f03e90d43501e8e4d55bc956f80e2de477 languageName: node linkType: hard "stylelint@npm:^15.10.1": - version: 15.10.2 - resolution: "stylelint@npm:15.10.2" + version: 15.11.0 + resolution: "stylelint@npm:15.11.0" dependencies: - "@csstools/css-parser-algorithms": "npm:^2.3.0" - "@csstools/css-tokenizer": "npm:^2.1.1" - "@csstools/media-query-list-parser": "npm:^2.1.2" + "@csstools/css-parser-algorithms": "npm:^2.3.1" + "@csstools/css-tokenizer": "npm:^2.2.0" + "@csstools/media-query-list-parser": "npm:^2.1.4" "@csstools/selector-specificity": "npm:^3.0.0" balanced-match: "npm:^2.0.0" colord: "npm:^2.9.3" cosmiconfig: "npm:^8.2.0" - css-functions-list: "npm:^3.2.0" + css-functions-list: "npm:^3.2.1" css-tree: "npm:^2.3.1" debug: "npm:^4.3.4" - fast-glob: "npm:^3.3.0" + fast-glob: "npm:^3.3.1" fastest-levenshtein: "npm:^1.0.16" - file-entry-cache: "npm:^6.0.1" + file-entry-cache: "npm:^7.0.0" global-modules: "npm:^2.0.0" globby: "npm:^11.1.0" globjoin: "npm:^0.1.4" @@ -15812,13 +15852,13 @@ __metadata: import-lazy: "npm:^4.0.0" imurmurhash: "npm:^0.1.4" is-plain-object: "npm:^5.0.0" - known-css-properties: "npm:^0.27.0" + known-css-properties: "npm:^0.29.0" mathml-tag-names: "npm:^2.1.3" meow: "npm:^10.1.5" micromatch: "npm:^4.0.5" normalize-path: "npm:^3.0.0" picocolors: "npm:^1.0.0" - postcss: "npm:^8.4.25" + postcss: "npm:^8.4.28" postcss-resolve-nested-selector: "npm:^0.1.1" postcss-safe-parser: "npm:^6.0.0" postcss-selector-parser: "npm:^6.0.13" @@ -15833,7 +15873,7 @@ __metadata: write-file-atomic: "npm:^5.0.1" bin: stylelint: bin/stylelint.mjs - checksum: 8378ee868b09322d2b7e07b03461c524736778a391b2ce6d4ad46c636e55a90ed98723f253db10d9a762cfefec60200d0b9c5cd7798b2f373efd2d986768ebc7 + checksum: 2d88b7293e308b7e418c14ba4130777b1a28b214304957f03b41a6dc8e00005266caf47479f718a6ec5e572cb52e903ca34aabf3febbe3a3ae32fff6b018d9fd languageName: node linkType: hard @@ -17724,10 +17764,10 @@ __metadata: languageName: node linkType: hard -"yaml@npm:2.3.3": - version: 2.3.3 - resolution: "yaml@npm:2.3.3" - checksum: a0c56bf682159b0567e9cbbddf23efc2f6806f6450716d9be6ec5eb1af1b941e95c8d3dc9c47da20d1b6883a9d6c61e31cf98bb4b77ebca4396bf772657f2f00 +"yaml@npm:2.3.4": + version: 2.3.4 + resolution: "yaml@npm:2.3.4" + checksum: cf03b68f8fef5e8516b0f0b54edaf2459f1648317fc6210391cf606d247e678b449382f4bd01f77392538429e306c7cba8ff46ff6b37cac4de9a76aff33bd9e1 languageName: node linkType: hard From a36b59be8ad7656b7ceab9751c9ec5b3563e3a30 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 13 Nov 2023 09:32:36 -0500 Subject: [PATCH 015/255] Spec coverage for `api/v1/trends` controllers (#27837) --- .../api/v1/trends/links_controller_spec.rb | 38 +++++++++++++++-- .../api/v1/trends/statuses_controller_spec.rb | 38 +++++++++++++++-- .../api/v1/trends/tags_controller_spec.rb | 41 +++++++++++++++---- 3 files changed, 101 insertions(+), 16 deletions(-) diff --git a/spec/controllers/api/v1/trends/links_controller_spec.rb b/spec/controllers/api/v1/trends/links_controller_spec.rb index 71a7e2e47..12d4198aa 100644 --- a/spec/controllers/api/v1/trends/links_controller_spec.rb +++ b/spec/controllers/api/v1/trends/links_controller_spec.rb @@ -2,14 +2,44 @@ require 'rails_helper' -describe Api::V1::Trends::LinksController do +RSpec.describe Api::V1::Trends::LinksController do render_views describe 'GET #index' do - it 'returns http success' do - get :index + around do |example| + previous = Setting.trends + example.run + Setting.trends = previous + end - expect(response).to have_http_status(200) + context 'when trends are disabled' do + before { Setting.trends = false } + + it 'returns http success' do + get :index + + expect(response).to have_http_status(200) + end + end + + context 'when trends are enabled' do + before { Setting.trends = true } + + it 'returns http success' do + prepare_trends + stub_const('Api::V1::Trends::LinksController::DEFAULT_LINKS_LIMIT', 2) + get :index + + expect(response).to have_http_status(200) + expect(response.headers).to include('Link') + end + + def prepare_trends + Fabricate.times(3, :preview_card, trendable: true, language: 'en').each do |link| + 2.times { |i| Trends.links.add(link, i) } + end + Trends::Links.new(threshold: 1).refresh + end end end end diff --git a/spec/controllers/api/v1/trends/statuses_controller_spec.rb b/spec/controllers/api/v1/trends/statuses_controller_spec.rb index e9892bb14..69fdb270d 100644 --- a/spec/controllers/api/v1/trends/statuses_controller_spec.rb +++ b/spec/controllers/api/v1/trends/statuses_controller_spec.rb @@ -2,14 +2,44 @@ require 'rails_helper' -describe Api::V1::Trends::StatusesController do +RSpec.describe Api::V1::Trends::StatusesController do render_views describe 'GET #index' do - it 'returns http success' do - get :index + around do |example| + previous = Setting.trends + example.run + Setting.trends = previous + end - expect(response).to have_http_status(200) + context 'when trends are disabled' do + before { Setting.trends = false } + + it 'returns http success' do + get :index + + expect(response).to have_http_status(200) + end + end + + context 'when trends are enabled' do + before { Setting.trends = true } + + it 'returns http success' do + prepare_trends + stub_const('Api::BaseController::DEFAULT_STATUSES_LIMIT', 2) + get :index + + expect(response).to have_http_status(200) + expect(response.headers).to include('Link') + end + + def prepare_trends + Fabricate.times(3, :status, trendable: true, language: 'en').each do |status| + 2.times { |i| Trends.statuses.add(status, i) } + end + Trends::Statuses.new(threshold: 1, decay_threshold: -1).refresh + end end end end diff --git a/spec/controllers/api/v1/trends/tags_controller_spec.rb b/spec/controllers/api/v1/trends/tags_controller_spec.rb index 84370d841..9311392cd 100644 --- a/spec/controllers/api/v1/trends/tags_controller_spec.rb +++ b/spec/controllers/api/v1/trends/tags_controller_spec.rb @@ -6,16 +6,41 @@ RSpec.describe Api::V1::Trends::TagsController do render_views describe 'GET #index' do - before do - Fabricate.times(10, :tag).each do |tag| - 10.times { |i| Trends.tags.add(tag, i) } - end - - get :index + around do |example| + previous = Setting.trends + example.run + Setting.trends = previous end - it 'returns http success' do - expect(response).to have_http_status(200) + context 'when trends are disabled' do + before { Setting.trends = false } + + it 'returns http success' do + get :index + + expect(response).to have_http_status(200) + expect(response.headers).to_not include('Link') + end + end + + context 'when trends are enabled' do + before { Setting.trends = true } + + it 'returns http success' do + prepare_trends + stub_const('Api::V1::Trends::TagsController::DEFAULT_TAGS_LIMIT', 2) + get :index + + expect(response).to have_http_status(200) + expect(response.headers).to include('Link') + end + + def prepare_trends + Fabricate.times(3, :tag, trendable: true).each do |tag| + 2.times { |i| Trends.tags.add(tag, i) } + end + Trends::Tags.new(threshold: 1).refresh + end end end end From 7e3c10dec676b0a560493071c5950c7e5df759b2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko <eugen@zeonfederated.com> Date: Mon, 13 Nov 2023 15:39:45 +0100 Subject: [PATCH 016/255] Add icons for private and disabled boost in web UI (#27817) Co-authored-by: Claire <claire.github-309c@sitedethib.com> --- .../mastodon/components/status_action_bar.jsx | 12 ++++++++++-- .../features/status/components/action_bar.jsx | 12 ++++++++++-- app/javascript/svg-icons/repeat_disabled.svg | 5 +++++ app/javascript/svg-icons/repeat_private.svg | 5 +++++ config/webpack/rules/material_icons.js | 2 +- 5 files changed, 31 insertions(+), 5 deletions(-) create mode 100755 app/javascript/svg-icons/repeat_disabled.svg create mode 100755 app/javascript/svg-icons/repeat_private.svg diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index 240174739..25eab91fe 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -19,6 +19,8 @@ import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/s import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg'; import { ReactComponent as VisibilityIcon } from '@material-symbols/svg-600/outlined/visibility.svg'; +import { ReactComponent as RepeatDisabledIcon } from 'mastodon/../svg-icons/repeat_disabled.svg'; +import { ReactComponent as RepeatPrivateIcon } from 'mastodon/../svg-icons/repeat_private.svg'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; @@ -348,6 +350,7 @@ class StatusActionBar extends ImmutablePureComponent { let replyIcon; let replyIconComponent; let replyTitle; + if (status.get('in_reply_to_id', null) === null) { replyIcon = 'reply'; replyIconComponent = ReplyIcon; @@ -360,15 +363,20 @@ class StatusActionBar extends ImmutablePureComponent { const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private'; - let reblogTitle = ''; + let reblogTitle, reblogIconComponent; + if (status.get('reblogged')) { reblogTitle = intl.formatMessage(messages.cancel_reblog_private); + reblogIconComponent = publicStatus ? RepeatIcon : RepeatPrivateIcon; } else if (publicStatus) { reblogTitle = intl.formatMessage(messages.reblog); + reblogIconComponent = RepeatIcon; } else if (reblogPrivate) { reblogTitle = intl.formatMessage(messages.reblog_private); + reblogIconComponent = RepeatPrivateIcon; } else { reblogTitle = intl.formatMessage(messages.cannot_reblog); + reblogIconComponent = RepeatDisabledIcon; } const filterButton = this.props.onFilter && ( @@ -380,7 +388,7 @@ class StatusActionBar extends ImmutablePureComponent { return ( <div className='status__action-bar'> <IconButton className='status__action-bar__button' title={replyTitle} icon={isReply ? 'reply' : replyIcon} iconComponent={isReply ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} counter={status.get('replies_count')} /> - <IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} /> + <IconButton className={classNames('status__action-bar__button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={reblogIconComponent} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} /> <IconButton className='status__action-bar__button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} /> <IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} /> diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx index eac0bab7e..663bce743 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.jsx +++ b/app/javascript/mastodon/features/status/components/action_bar.jsx @@ -18,6 +18,8 @@ import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlin import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg'; import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg'; +import { ReactComponent as RepeatDisabledIcon } from 'mastodon/../svg-icons/repeat_disabled.svg'; +import { ReactComponent as RepeatPrivateIcon } from 'mastodon/../svg-icons/repeat_private.svg'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; @@ -280,6 +282,7 @@ class ActionBar extends PureComponent { let replyIcon; let replyIconComponent; + if (status.get('in_reply_to_id', null) === null) { replyIcon = 'reply'; replyIconComponent = ReplyIcon; @@ -290,21 +293,26 @@ class ActionBar extends PureComponent { const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private'; - let reblogTitle; + let reblogTitle, reblogIconComponent; + if (status.get('reblogged')) { reblogTitle = intl.formatMessage(messages.cancel_reblog_private); + reblogIconComponent = publicStatus ? RepeatIcon : RepeatPrivateIcon; } else if (publicStatus) { reblogTitle = intl.formatMessage(messages.reblog); + reblogIconComponent = RepeatIcon; } else if (reblogPrivate) { reblogTitle = intl.formatMessage(messages.reblog_private); + reblogIconComponent = RepeatPrivateIcon; } else { reblogTitle = intl.formatMessage(messages.cannot_reblog); + reblogIconComponent = RepeatDisabledIcon; } return ( <div className='detailed-status__action-bar'> <div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} /></div> - <div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} /></div> + <div className='detailed-status__button'><IconButton className={classNames({ reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={reblogIconComponent} onClick={this.handleReblogClick} /></div> <div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} /></div> <div className='detailed-status__button'><IconButton className='bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} /></div> diff --git a/app/javascript/svg-icons/repeat_disabled.svg b/app/javascript/svg-icons/repeat_disabled.svg new file mode 100755 index 000000000..3157f660e --- /dev/null +++ b/app/javascript/svg-icons/repeat_disabled.svg @@ -0,0 +1,5 @@ +<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M19 13V17.8787L17 15.8787V13H19Z"/> +<path d="M2.41421 2.70711L1 4.12132L5 8.12132V11H7V10.1213L13.8787 17H6.85L8.4 15.45L7 14L3 18L7 22L8.4 20.55L6.85 19H15.8787L19.3848 22.5061L20.799 21.0919L2.41421 2.70711Z"/> +<path d="M17.15 7H8.12132L6.12132 5H17.15L15.6 3.45L17 2L21 6L17 10L15.6 8.55L17.15 7Z"/> +</svg> diff --git a/app/javascript/svg-icons/repeat_private.svg b/app/javascript/svg-icons/repeat_private.svg new file mode 100755 index 000000000..a65be532a --- /dev/null +++ b/app/javascript/svg-icons/repeat_private.svg @@ -0,0 +1,5 @@ +<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M8.4 15.45L7 14L3 18L7 22L8.4 20.55L6.85 19H13.5V18C13.5 17.6567 13.5638 17.3171 13.6988 17H6.85L8.4 15.45Z"/> +<path d="M5 5V11H7V7H17.15L15.6 8.55L17 10L21 6L17 2L15.6 3.45L17.15 5H5Z"/> +<path d="M16 22C15.7167 22 15.475 21.9083 15.275 21.725C15.0917 21.525 15 21.2833 15 21V18C15 17.7167 15.0917 17.4833 15.275 17.3C15.475 17.1 15.7167 17 16 17V16C16 15.45 16.1917 14.9833 16.575 14.6C16.975 14.2 17.45 14 18 14C18.55 14 19.0167 14.2 19.4 14.6C19.8 14.9833 20 15.45 20 16V17C20.2833 17 20.5167 17.1 20.7 17.3C20.9 17.4833 21 17.7167 21 18V21C21 21.2833 20.9 21.525 20.7 21.725C20.5167 21.9083 20.2833 22 20 22H16ZM17 17H19V16C19 15.7167 18.9 15.4833 18.7 15.3C18.5167 15.1 18.2833 15 18 15C17.7167 15 17.475 15.1 17.275 15.3C17.0917 15.4833 17 15.7167 17 16V17Z"/> +</svg> diff --git a/config/webpack/rules/material_icons.js b/config/webpack/rules/material_icons.js index 7ac1072b0..048e198ef 100644 --- a/config/webpack/rules/material_icons.js +++ b/config/webpack/rules/material_icons.js @@ -1,6 +1,6 @@ module.exports = { test: /\.svg$/, - include: /node_modules\/@material-symbols/, + include: [/node_modules\/@material-symbols/, /svg-icons/], issuer: /\.[jt]sx?$/, use: [ { From a1b48460e4e22cb552b35776a5cc03961c619d9f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:40:10 +0100 Subject: [PATCH 017/255] Update DefinitelyTyped types (non-major) (#27830) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 178 +++++++++++++++++++++++++-------------------------- 2 files changed, 90 insertions(+), 90 deletions(-) diff --git a/package.json b/package.json index 96bfb1571..6f20b98bc 100644 --- a/package.json +++ b/package.json @@ -176,7 +176,7 @@ "@types/react-dom": "^18.2.4", "@types/react-helmet": "^6.1.6", "@types/react-immutable-proptypes": "^2.1.0", - "@types/react-motion": "^0.0.36", + "@types/react-motion": "^0.0.37", "@types/react-overlays": "^3.1.0", "@types/react-router": "^5.1.20", "@types/react-router-dom": "^5.3.3", diff --git a/yarn.lock b/yarn.lock index 891eb59fe..b05b2bfbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2384,7 +2384,7 @@ __metadata: "@types/react-dom": "npm:^18.2.4" "@types/react-helmet": "npm:^6.1.6" "@types/react-immutable-proptypes": "npm:^2.1.0" - "@types/react-motion": "npm:^0.0.36" + "@types/react-motion": "npm:^0.0.37" "@types/react-overlays": "npm:^3.1.0" "@types/react-router": "npm:^5.1.20" "@types/react-router-dom": "npm:^5.3.3" @@ -3006,15 +3006,15 @@ __metadata: linkType: hard "@types/babel__core@npm:*, @types/babel__core@npm:^7.1.12, @types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.1.7, @types/babel__core@npm:^7.20.1": - version: 7.20.3 - resolution: "@types/babel__core@npm:7.20.3" + version: 7.20.4 + resolution: "@types/babel__core@npm:7.20.4" dependencies: "@babel/parser": "npm:^7.20.7" "@babel/types": "npm:^7.20.7" "@types/babel__generator": "npm:*" "@types/babel__template": "npm:*" "@types/babel__traverse": "npm:*" - checksum: 5b5f9de4df7f995c2f06f3fdad39b58bc30121d1f2daceb97dd423c9b5dcbd5c464959338824e0dbee0c758bf55c4e9fe46fafd13bd29c1834afad04f291c588 + checksum: 2adc7ec49de5f922271ce087cedee000de468a3e13f92b7b6254016bd8357298cb98e6d2b3c9defc69bb6e38e0c134ffe80776a8ce4e9fb167bbffcb4d7613b7 languageName: node linkType: hard @@ -3075,18 +3075,18 @@ __metadata: linkType: hard "@types/emoji-mart@npm:^3.0.9": - version: 3.0.11 - resolution: "@types/emoji-mart@npm:3.0.11" + version: 3.0.12 + resolution: "@types/emoji-mart@npm:3.0.12" dependencies: "@types/react": "npm:*" - checksum: 1080ee6d0286248310b1f29ed7e21f15bdb587dec924dc2f714ab60f9ecc4567dde84fb73e41336d72a3e77afd2546f3025f886474391dd5efe1884a6a8ef034 + checksum: 146abafe3ce9f4954c7f6ed3603bdc5a897b2d6b99dd9da6065ef597a9a6a59fb914e907decbda29b661216ddf3da8bb34a28d50f3d6929efce2b3c42e73b085 languageName: node linkType: hard "@types/escape-html@npm:^1.0.2": - version: 1.0.3 - resolution: "@types/escape-html@npm:1.0.3" - checksum: 980ec83f07f91389ffc9d7043da40db49dc40879a57f743a422bf30aa1d730f33c880baab4b31aacce550f2b195a866ec95d66a14c517ea1416d03e9b462df9d + version: 1.0.4 + resolution: "@types/escape-html@npm:1.0.4" + checksum: 5cdae9d38e97b1ad61180528ef7ca66bf6be96e875cc560c3e064d6ca75ccf2adaf2fa3b7bdd4f7494013e4357a2fb0bb62f2e59ca53097d5c45c7519d0ce9c3 languageName: node linkType: hard @@ -3127,14 +3127,14 @@ __metadata: linkType: hard "@types/express@npm:^4.17.17": - version: 4.17.20 - resolution: "@types/express@npm:4.17.20" + version: 4.17.21 + resolution: "@types/express@npm:4.17.21" dependencies: "@types/body-parser": "npm:*" "@types/express-serve-static-core": "npm:^4.17.33" "@types/qs": "npm:*" "@types/serve-static": "npm:*" - checksum: f73f5f92bd0a0fa4697598be3122c89522caa9e3bcb14c28b5e6d58a8e47f0301027478997153ae9ee4cf3d432576fb3fb0918ea0db521cc1204f8b759828a32 + checksum: 12e562c4571da50c7d239e117e688dc434db1bac8be55613294762f84fd77fbd0658ccd553c7d3ab02408f385bc93980992369dd30e2ecd2c68c358e6af8fabf languageName: node linkType: hard @@ -3165,12 +3165,12 @@ __metadata: linkType: hard "@types/hoist-non-react-statics@npm:^3.3.1": - version: 3.3.4 - resolution: "@types/hoist-non-react-statics@npm:3.3.4" + version: 3.3.5 + resolution: "@types/hoist-non-react-statics@npm:3.3.5" dependencies: "@types/react": "npm:*" hoist-non-react-statics: "npm:^3.3.0" - checksum: 677ddcacf72f2fb79f65599189d4741fa3d815aa5e50c7fd6c3c9be92298aecf05b044e7dc445cf2bb0877652293949a7f0e364e63d9266b242cd9cb9bf53fa7 + checksum: 2a3b64bf3d9817d7830afa60ee314493c475fb09570a64e7737084cd482d2177ebdddf888ce837350bac51741278b077683facc9541f052d4bbe8487b4e3e618 languageName: node linkType: hard @@ -3182,18 +3182,18 @@ __metadata: linkType: hard "@types/http-link-header@npm:^1.0.3": - version: 1.0.4 - resolution: "@types/http-link-header@npm:1.0.4" + version: 1.0.5 + resolution: "@types/http-link-header@npm:1.0.5" dependencies: "@types/node": "npm:*" - checksum: 65035f11a49a2c4ea75a0a8de284a8808264e0a1b03e6be5cd8df8637b283be154f723d2eef091715ad3e98b8d252bc261aea109559e43702dfecae03e26263e + checksum: adeb13381b38c3625478149820772924c154b4a7250dca62c346810a8378f8968fc7f3a9a4f55ec61de5d06083637540f862c8a920f6a710310c9645d19a077d languageName: node linkType: hard "@types/intl@npm:^1.2.0": - version: 1.2.1 - resolution: "@types/intl@npm:1.2.1" - checksum: b1c81eade8a9b7ee33b7642283b7d024c263d34c5efae24a517822bd87b8a01c1a2a8c71ade948346c785abad522858ec389247031b5404307c06ba51da52385 + version: 1.2.2 + resolution: "@types/intl@npm:1.2.2" + checksum: f465c320139c01dfc9ae1382406259fd23f6a455aad31517f61b7fd79bdde493e854d6666c2198ae644d8cf6e147e78831ea810f83a787f65b765bc56834f259 languageName: node linkType: hard @@ -3223,19 +3223,19 @@ __metadata: linkType: hard "@types/jest@npm:^29.5.2": - version: 29.5.7 - resolution: "@types/jest@npm:29.5.7" + version: 29.5.8 + resolution: "@types/jest@npm:29.5.8" dependencies: expect: "npm:^29.0.0" pretty-format: "npm:^29.0.0" - checksum: 231c873f3d1ddac973b8f8f2ad7760677d941d85fb52d1c5dc4a311bafba4c2c1658a1040fd7054a51f4d1841f51c6ca4cabf70675ee4fa9e10fc5b8066e1de1 + checksum: a28e7827ea7e1a2aace6a386868fa6b8402c162d6c71570aed2c29d3745ddc22ceef6899a20643071817905d3c57b670a7992fc8760bff65939351fd4dc481cf languageName: node linkType: hard "@types/js-yaml@npm:^4.0.5": - version: 4.0.8 - resolution: "@types/js-yaml@npm:4.0.8" - checksum: 171a5c54d5b5c86a89300d14a004c49321f1a290fd2f625e2ef682e100ce78715a0eb8eac1ff09114dadaec8ccdb98251ddb5e06f1f3d6aa2ec83930e7a16039 + version: 4.0.9 + resolution: "@types/js-yaml@npm:4.0.9" + checksum: 24de857aa8d61526bbfbbaa383aa538283ad17363fcd5bb5148e2c7f604547db36646440e739d78241ed008702a8920665d1add5618687b6743858fae00da211 languageName: node linkType: hard @@ -3272,9 +3272,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.195": - version: 4.14.200 - resolution: "@types/lodash@npm:4.14.200" - checksum: 7a8dac6dc866f10d1888846d6189d1faeb4f65adb139f0837a005fd1adcde62e60d7e7abb1a2733d13fc57bebb337d74182d8ad3dbd1d211dcd0c310c47e81bc + version: 4.14.201 + resolution: "@types/lodash@npm:4.14.201" + checksum: 14dc43787296c429433d7d034ed47c5ac24b92217056f80a0e6c990449120b9c9c1058918188945fb88353c0c8333c5c36dccc40c51edbd39b05d2169ab2e0ad languageName: node linkType: hard @@ -3330,18 +3330,18 @@ __metadata: linkType: hard "@types/npmlog@npm:^4.1.4": - version: 4.1.5 - resolution: "@types/npmlog@npm:4.1.5" + version: 4.1.6 + resolution: "@types/npmlog@npm:4.1.6" dependencies: "@types/node": "npm:*" - checksum: 84b01941e0bc9c4e1ee145ee1278731e4a1d4236a88c62f94640a741aa323df7a20ff20344432f574184fa2b219ca7f7b549f724684cab4bc8dada7b3a13941c + checksum: 432bfb14b29a383e095e099b2ddff4266051b43bc6c7ea242d10194acde2f1181a1e967bbb543f07979dd77743ead1954abac1128ec78cc2b86a5f7ea841ddcb languageName: node linkType: hard "@types/object-assign@npm:^4.0.30": - version: 4.0.32 - resolution: "@types/object-assign@npm:4.0.32" - checksum: 25a75c2c1f4b20ce95443ab247b153dfb00e4bf08b4716f01efae7063f6e49a8af96f4c752dc3a44d7da381b9730249b3ee97900b6336bf5221f242c9532e8c5 + version: 4.0.33 + resolution: "@types/object-assign@npm:4.0.33" + checksum: 7fbc399aa1140beff35a152e206bfb336dd880721f4a13cc1ea01d964ab376fa4ca2c19059145cbd777c9d3eaf724008faec8cf3becff97353c69560196af086 languageName: node linkType: hard @@ -3353,13 +3353,13 @@ __metadata: linkType: hard "@types/pg@npm:^8.6.6": - version: 8.10.7 - resolution: "@types/pg@npm:8.10.7" + version: 8.10.9 + resolution: "@types/pg@npm:8.10.9" dependencies: "@types/node": "npm:*" pg-protocol: "npm:*" pg-types: "npm:^4.0.1" - checksum: beea456e9f4011d07e318b57d8c96af26379c658ad30d242a3194520d41406ca7bfa19a941405b7db36e401aa07f34cd035bdc5ac3d7681712c47a48df3cd09e + checksum: 6b3bec7230d09da6459636a66dfd6fb538378e466ffff0a0bcd07d67aa4ddce49c73afc7442f53adec92a49dbf9e71d8d847e0075750d7545331735dfd92d22c languageName: node linkType: hard @@ -3371,16 +3371,16 @@ __metadata: linkType: hard "@types/prop-types@npm:*, @types/prop-types@npm:^15.7.5": - version: 15.7.9 - resolution: "@types/prop-types@npm:15.7.9" - checksum: e2a7373b91a8eb30cb4e399ef5b3a14baa7d72eed1667ef5e3cb1e9400edfca9b60c20b845fefdcf7562773829f6ff60ba350b09f6313a8093e70c15b2b88f00 + version: 15.7.10 + resolution: "@types/prop-types@npm:15.7.10" + checksum: 964348d05cdf7399260b3179fbd1462b23d7452dc39fbccb319e54ed6ffafb0a01c0a62c3e6f7c944a635c7a4ad5c99d62c4787c9c4b74e2ec07aebaf6cfedc1 languageName: node linkType: hard "@types/punycode@npm:^2.1.0": - version: 2.1.1 - resolution: "@types/punycode@npm:2.1.1" - checksum: 3e5c3c786790111ac497d7a472c762671c68ec58edce0a88757c503e997eb500af1b8584c948b0a9927394b0f15828faa8f986130eb4ebb0fde0331c2f515630 + version: 2.1.2 + resolution: "@types/punycode@npm:2.1.2" + checksum: 4a748533bde61097f205638b3acc2c3b0e25382d2c35a2e3b60c33c904afbad158ef778ae3e1b3f3c84edd7b04b6d9fa049f2832210c308d3fee77ba7b637cb9 languageName: node linkType: hard @@ -3406,39 +3406,39 @@ __metadata: linkType: hard "@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.4": - version: 18.2.14 - resolution: "@types/react-dom@npm:18.2.14" + version: 18.2.15 + resolution: "@types/react-dom@npm:18.2.15" dependencies: "@types/react": "npm:*" - checksum: 1f79a7708d038cd651bdb21e01a99c594761bc9a40a565abe98958e1d27facfeb6e9824ddf6ae3504e7a56568f0f3da2380fe52ac18477b5864d2d5cf1386a9e + checksum: 70e86f15f69f89b8f179139ab2e8a8aa9765e742789f5dd5a46fec40d4300ada8fe3349cceda42b9964a018982d7ccb7d791b47f781966c992bfd37da909fbd3 languageName: node linkType: hard "@types/react-helmet@npm:^6.1.6": - version: 6.1.8 - resolution: "@types/react-helmet@npm:6.1.8" + version: 6.1.9 + resolution: "@types/react-helmet@npm:6.1.9" dependencies: "@types/react": "npm:*" - checksum: 56efbf05594437fff87466853b813c0672b33fbed1f995b9eb68e1461875cd5276b36c7fbc171134e9b7b897316123ae59b0263742d5a81e28ead133a4962bd2 + checksum: d1823582903d6e70f1f447c7bec9e844b6f85f5de84cbcde5c8bbeecc064db1394c786ed9b9ded30544afe5c91e57c7e8105171df1643998f64c0aeab9f7f2aa languageName: node linkType: hard "@types/react-immutable-proptypes@npm:^2.1.0": - version: 2.1.2 - resolution: "@types/react-immutable-proptypes@npm:2.1.2" + version: 2.1.3 + resolution: "@types/react-immutable-proptypes@npm:2.1.3" dependencies: "@types/prop-types": "npm:*" immutable: "npm:^3.8.2" - checksum: 8a944de2b4b484e9685495dee7b350a88e4fcba47dcecf97c7b4add6ae66b61fc61c18e877a9b8e8d453e7c4714c481166d5531328f92b2d20d45e11389734ee + checksum: 4dab74a43a2dde9bea6299a999dd600ae82f00082fe2b8865b11e5154e658f72fbb117132fa3753dd9a280dd8032a2574d8e7c94de5e268afdadd50d720086da languageName: node linkType: hard -"@types/react-motion@npm:^0.0.36": - version: 0.0.36 - resolution: "@types/react-motion@npm:0.0.36" +"@types/react-motion@npm:^0.0.37": + version: 0.0.37 + resolution: "@types/react-motion@npm:0.0.37" dependencies: "@types/react": "npm:*" - checksum: b039d9b6773a08292253f1343ee7c1c5ad2885499685aef2a0274a84a7bbe4e198b7aafa62b9c269fb37df9e076ae46ee9717fc53f0c26ca182342aaf1653139 + checksum: 387f60636d9bdd2e765ce94db969cf762a62495e32807f88380748a74e9beeb3d8e17c3ec334dab8040244ea62e7954d5f4d4bdbdd0ecc8985eb4a6ce465b61c languageName: node linkType: hard @@ -3482,29 +3482,29 @@ __metadata: linkType: hard "@types/react-sparklines@npm:^1.7.2": - version: 1.7.4 - resolution: "@types/react-sparklines@npm:1.7.4" + version: 1.7.5 + resolution: "@types/react-sparklines@npm:1.7.5" dependencies: "@types/react": "npm:*" - checksum: 1f50232fbd26d2b81508f68dbe1865503b1f9e053aae4ea2d610c771da219af4e6fa86e58fda542e2762f533042f83acab2d977ae2cb1b518ed94ba31aac8504 + checksum: acb0937ebc06019921ec5254fb125356f206038f5e2f244663eb849c692b6f6413f75ce3ee84be91d8c659ae43c8f743dd5c4397cdea65749cd601a495491242 languageName: node linkType: hard "@types/react-swipeable-views@npm:^0.13.1": - version: 0.13.4 - resolution: "@types/react-swipeable-views@npm:0.13.4" + version: 0.13.5 + resolution: "@types/react-swipeable-views@npm:0.13.5" dependencies: "@types/react": "npm:*" - checksum: 673e96a66443b07c5640c94b214fd0780846ba9e983c821f7cc7c8bdc0ab512e65b6a2af7e4aeb0f565ee5a63f30cf2bdf4d9da7a4d9d3dfe2e27d2d8f6c1200 + checksum: d1dcc78d862f37d30a43d79d915fdb388e05dce0b2ac07462ca4f1b00e0eef37cb41d75997f5685dec79bcce1ffee0dfbc744f20d5266dd3090658def5b4e193 languageName: node linkType: hard "@types/react-test-renderer@npm:^18.0.0": - version: 18.0.5 - resolution: "@types/react-test-renderer@npm:18.0.5" + version: 18.0.6 + resolution: "@types/react-test-renderer@npm:18.0.6" dependencies: "@types/react": "npm:*" - checksum: bd98abad08d04081bcf335fa71c450b9f0535ccba2c1395d11254427e1007a228d481d6868879d23b6239c0fede790de77ef6bf31afc735241e3edc63bb0e865 + checksum: f490d4379e8d095f8fa91700ceb37d0fe5a96d7cc0c51e9d7127fc3d2dc4e37a382dd6215b295b300037985cb8938cb5088130102ad14b79e4622e7e520c5a3b languageName: node linkType: hard @@ -3518,11 +3518,11 @@ __metadata: linkType: hard "@types/react-toggle@npm:^4.0.3": - version: 4.0.4 - resolution: "@types/react-toggle@npm:4.0.4" + version: 4.0.5 + resolution: "@types/react-toggle@npm:4.0.5" dependencies: "@types/react": "npm:*" - checksum: 86015101f1ddfd2c31396a8f4fff7b2b442af886ed1301b4470d864b41bec91c46046d3a4e1d97a838c3069138db2f9628f885a7d9f95199bfa27a46d9df33de + checksum: f557b85c96715b145bcc3beb2903f88ee3a6045ef85da0f80561c7cc2ecdc531e2d4ae121ed8ec3a1761264de25b8410653744093f37abf042201587add7ffa6 languageName: node linkType: hard @@ -3536,30 +3536,30 @@ __metadata: linkType: hard "@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7": - version: 18.2.36 - resolution: "@types/react@npm:18.2.36" + version: 18.2.37 + resolution: "@types/react@npm:18.2.37" dependencies: "@types/prop-types": "npm:*" "@types/scheduler": "npm:*" csstype: "npm:^3.0.2" - checksum: 02b593041e9c25aaf519b5e4f87282aff559c0f3db214d7db68fee714d8286c09ab1fced68184fbe814e061019024bb479bbcd38b07985e3e794d98c96c49123 + checksum: 79dd5d23da05bec54e7423ca17096e345eb8fd80a3bf8dd916bb5cdd60677d27c298523aa5b245d090fcc4ec100cfd58c1af4631fbac709d0a9d8be75f9d78a9 languageName: node linkType: hard "@types/redux-immutable@npm:^4.0.3": - version: 4.0.5 - resolution: "@types/redux-immutable@npm:4.0.5" + version: 4.0.6 + resolution: "@types/redux-immutable@npm:4.0.6" dependencies: immutable: "npm:^4.0.0-rc.1" redux: "npm:^4.0.0" - checksum: 1fd808b86506b8d32745159397172fcc9e890766b4330a001c35254d695edeb142d2a17c7ad6592853dfccea1840e632634651bcd0af882f445699d1238813dd + checksum: 19972c307f2bbd31a201b28844224ce06e34917823cf2ded3c303cffcced273a2107c4186cc37af9db4f948204fc48c461e609b9f3d2719963049dedae3ebf82 languageName: node linkType: hard "@types/requestidlecallback@npm:^0.3.5": - version: 0.3.6 - resolution: "@types/requestidlecallback@npm:0.3.6" - checksum: 5a3df7a028fc6894446c14a67c93186f7978cf97d41a0da74a56d4c95ca9580593eb7baaaa385fa54d46f3c93f5789b21548a3708a5a0cc08302aa7e7f037e30 + version: 0.3.7 + resolution: "@types/requestidlecallback@npm:0.3.7" + checksum: aa5d1d981d7ddc98b9212c75c89d2ddb2e521077d6c0c5e285d944a8c6ae8baeec30d4d201aec31716d668d3435f884e80e768e28d929a5b87a55097bc21a5e1 languageName: node linkType: hard @@ -3659,9 +3659,9 @@ __metadata: linkType: hard "@types/uuid@npm:^9.0.0": - version: 9.0.6 - resolution: "@types/uuid@npm:9.0.6" - checksum: 8fb6b3a583a035b8e917192eeadaadadfbfd29315094aafd3478e11f11a986cb118ee0f388b15035fda063d9f1a32fa62e7a791215b762fe1e2c177929ca7146 + version: 9.0.7 + resolution: "@types/uuid@npm:9.0.7" + checksum: b329ebd4f9d1d8e08d4f2cc211be4922d70d1149f73d5772630e4a3acfb5170c6d37b3d7a39a0412f1a56e86e8a844c7f297c798b082f90380608bf766688787 languageName: node linkType: hard @@ -3684,8 +3684,8 @@ __metadata: linkType: hard "@types/webpack@npm:^4.41.33": - version: 4.41.35 - resolution: "@types/webpack@npm:4.41.35" + version: 4.41.36 + resolution: "@types/webpack@npm:4.41.36" dependencies: "@types/node": "npm:*" "@types/tapable": "npm:^1" @@ -3693,7 +3693,7 @@ __metadata: "@types/webpack-sources": "npm:*" anymatch: "npm:^3.0.0" source-map: "npm:^0.6.0" - checksum: ec6b9fda027ff6f7f9efeb4bcfb37607a15fe1e2f2f0883e3500fe474ba0a127ea62783cd19859bbef921cfad22cd680e50bcc2c1963482c6486263886877130 + checksum: 9e9021049b8f7482ec7c45e95d7c1da3604ee04481d7550421ed58f201f66edb8eb6c26b85be94ce3f761874cdbb8b570827becdaf5acdb1897aba9b7f226252 languageName: node linkType: hard @@ -3705,11 +3705,11 @@ __metadata: linkType: hard "@types/yargs@npm:^17.0.24, @types/yargs@npm:^17.0.8": - version: 17.0.29 - resolution: "@types/yargs@npm:17.0.29" + version: 17.0.31 + resolution: "@types/yargs@npm:17.0.31" dependencies: "@types/yargs-parser": "npm:*" - checksum: d8c965c101f7ee3e2f301c02a83dfd5680e4d999d3503c788c13f336868f03ee1498f019552e7d357635a1a36912cbe6751a563e9c339075d30cd131dc361c98 + checksum: 1e04df99bd0ad8ac8b3748b6ac0e99a9a4efe20b9cd8eab69ac9503fe87ab9bec312ad56982e969cdb0e2c0679431434ad571f6934049adb15fa35b22810c867 languageName: node linkType: hard From da5940752055369451e545c664aecdfb3821960b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:40:50 +0100 Subject: [PATCH 018/255] Update eslint (non-major) (#27831) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 337 +++++++++++++++++++++------------------------------ 2 files changed, 140 insertions(+), 199 deletions(-) diff --git a/package.json b/package.json index 6f20b98bc..2230b20ea 100644 --- a/package.json +++ b/package.json @@ -200,7 +200,7 @@ "eslint-plugin-formatjs": "^4.10.1", "eslint-plugin-import": "~2.29.0", "eslint-plugin-jsdoc": "^46.1.0", - "eslint-plugin-jsx-a11y": "~6.7.1", + "eslint-plugin-jsx-a11y": "~6.8.0", "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-promise": "~6.1.1", "eslint-plugin-react": "~7.33.0", diff --git a/yarn.lock b/yarn.lock index b05b2bfbc..e8fe28fb4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1482,7 +1482,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": version: 7.23.2 resolution: "@babel/runtime@npm:7.23.2" dependencies: @@ -1697,14 +1697,14 @@ __metadata: languageName: node linkType: hard -"@es-joy/jsdoccomment@npm:~0.40.1": - version: 0.40.1 - resolution: "@es-joy/jsdoccomment@npm:0.40.1" +"@es-joy/jsdoccomment@npm:~0.41.0": + version: 0.41.0 + resolution: "@es-joy/jsdoccomment@npm:0.41.0" dependencies: - comment-parser: "npm:1.4.0" + comment-parser: "npm:1.4.1" esquery: "npm:^1.5.0" jsdoc-type-pratt-parser: "npm:~4.0.0" - checksum: e66b861c55cf26d22c0facef911d65abbbbf633a9fc47cbf0f0faa4226e495cbce5133f4e69f555cd4c018a13dabb37f8a36d631ba768b9297913154b06a04af + checksum: 1fa27531eba32e4699664da53a0865aeeda1f7e83ac156fe53b7a6b09d2f3816baa94a34845ff019c10289b09572bda5519ec917e3e241088975477fa880f72d languageName: node linkType: hard @@ -1790,16 +1790,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:1.17.2": - version: 1.17.2 - resolution: "@formatjs/ecma402-abstract@npm:1.17.2" - dependencies: - "@formatjs/intl-localematcher": "npm:0.4.2" - tslib: "npm:^2.4.0" - checksum: 7086962b6f6fd517188e9640e8439062e125e7bd60852ae91ceadb259fceaa3f73f7403a77411a7c82b1ae60be4bf4b27f793acc4059214adc91b00682d880fe - languageName: node - linkType: hard - "@formatjs/ecma402-abstract@npm:1.17.4": version: 1.17.4 resolution: "@formatjs/ecma402-abstract@npm:1.17.4" @@ -1819,17 +1809,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-messageformat-parser@npm:2.7.0": - version: 2.7.0 - resolution: "@formatjs/icu-messageformat-parser@npm:2.7.0" - dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.2" - "@formatjs/icu-skeleton-parser": "npm:1.6.2" - tslib: "npm:^2.4.0" - checksum: f671d3dfcfa8ada17d14388f21be4cf1c535cbad8aba9cd6a3132d3120424cb7fb090f67b27e44ffbd0c7d4bba9f20e76b74cfca87f4ab945939e7ea3acb878c - languageName: node - linkType: hard - "@formatjs/icu-messageformat-parser@npm:2.7.2": version: 2.7.2 resolution: "@formatjs/icu-messageformat-parser@npm:2.7.2" @@ -1841,16 +1820,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-skeleton-parser@npm:1.6.2": - version: 1.6.2 - resolution: "@formatjs/icu-skeleton-parser@npm:1.6.2" - dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.2" - tslib: "npm:^2.4.0" - checksum: 2a2a56f49a15e8122b37237d5e09a817e01149ae353e1b5fe8721d1789dbaee85995c897d3aa9e5b400e3ee05b5fd4c0721b3ad49b1d128954dfed873a793153 - languageName: node - linkType: hard - "@formatjs/icu-skeleton-parser@npm:1.6.4": version: 1.6.4 resolution: "@formatjs/icu-skeleton-parser@npm:1.6.4" @@ -1883,15 +1852,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-localematcher@npm:0.4.2": - version: 0.4.2 - resolution: "@formatjs/intl-localematcher@npm:0.4.2" - dependencies: - tslib: "npm:^2.4.0" - checksum: 2521fa48a95a80e3bedc0d444fb2ef67e1215e0bf9e6d16020c4a22af6973849a71c7a29a10cb74fc67b818967e9f8672062760e808e70873132277830e0ec67 - languageName: node - linkType: hard - "@formatjs/intl-localematcher@npm:0.5.1": version: 0.5.1 resolution: "@formatjs/intl-localematcher@npm:0.5.1" @@ -1932,26 +1892,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/ts-transformer@npm:3.13.6": - version: 3.13.6 - resolution: "@formatjs/ts-transformer@npm:3.13.6" - dependencies: - "@formatjs/icu-messageformat-parser": "npm:2.7.0" - "@types/json-stable-stringify": "npm:^1.0.32" - "@types/node": "npm:14 || 16 || 17" - chalk: "npm:^4.0.0" - json-stable-stringify: "npm:^1.0.1" - tslib: "npm:^2.4.0" - typescript: "npm:5" - peerDependencies: - ts-jest: ">=27" - peerDependenciesMeta: - ts-jest: - optional: true - checksum: 76cd99713a974bf63081d9f7b98997dba0fc998205b5bc7cb6249dc8572549408b62a42c394b6d589905368203b37862e0c9248eef5aaa94b8de0b423fa8b508 - languageName: node - linkType: hard - "@formatjs/ts-transformer@npm:3.13.8": version: 3.13.8 resolution: "@formatjs/ts-transformer@npm:3.13.8" @@ -2432,7 +2372,7 @@ __metadata: eslint-plugin-formatjs: "npm:^4.10.1" eslint-plugin-import: "npm:~2.29.0" eslint-plugin-jsdoc: "npm:^46.1.0" - eslint-plugin-jsx-a11y: "npm:~6.7.1" + eslint-plugin-jsx-a11y: "npm:~6.8.0" eslint-plugin-prettier: "npm:^5.0.0" eslint-plugin-promise: "npm:~6.1.1" eslint-plugin-react: "npm:~7.33.0" @@ -3714,14 +3654,14 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^6.0.0": - version: 6.9.1 - resolution: "@typescript-eslint/eslint-plugin@npm:6.9.1" + version: 6.10.0 + resolution: "@typescript-eslint/eslint-plugin@npm:6.10.0" dependencies: "@eslint-community/regexpp": "npm:^4.5.1" - "@typescript-eslint/scope-manager": "npm:6.9.1" - "@typescript-eslint/type-utils": "npm:6.9.1" - "@typescript-eslint/utils": "npm:6.9.1" - "@typescript-eslint/visitor-keys": "npm:6.9.1" + "@typescript-eslint/scope-manager": "npm:6.10.0" + "@typescript-eslint/type-utils": "npm:6.10.0" + "@typescript-eslint/utils": "npm:6.10.0" + "@typescript-eslint/visitor-keys": "npm:6.10.0" debug: "npm:^4.3.4" graphemer: "npm:^1.4.0" ignore: "npm:^5.2.4" @@ -3734,44 +3674,44 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: f2455fe74f8c90d82df97801ee5e17bb3d81b1a59d23eedc7cad95b6eed30180339107bef0460578d5cc587033bb388fd112bae48b6b85f504fe4521f365ac69 + checksum: f50b17cb753afbfc99549d38585eba8558949b977eb4661dd584e73ee946b3dbe944c9e3b12a233fa06b5e1c7d101730ac88a00c7a91b0a7f1e2c37a98e13c7a languageName: node linkType: hard "@typescript-eslint/parser@npm:^6.0.0": - version: 6.9.1 - resolution: "@typescript-eslint/parser@npm:6.9.1" + version: 6.10.0 + resolution: "@typescript-eslint/parser@npm:6.10.0" dependencies: - "@typescript-eslint/scope-manager": "npm:6.9.1" - "@typescript-eslint/types": "npm:6.9.1" - "@typescript-eslint/typescript-estree": "npm:6.9.1" - "@typescript-eslint/visitor-keys": "npm:6.9.1" + "@typescript-eslint/scope-manager": "npm:6.10.0" + "@typescript-eslint/types": "npm:6.10.0" + "@typescript-eslint/typescript-estree": "npm:6.10.0" + "@typescript-eslint/visitor-keys": "npm:6.10.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: a6896655b2005a55e15dd3bb8b8239e1cb1bb0379037f6af2409e910c426cf9cda5490d45cd1857a3ca7fe2727acc8250d8196770147a4dc274e4c700ead9d9c + checksum: fd86c31dfdde03636393a3a9cf16716856bb506923069f34d87af14fac363a33578f47476a15d272e4d7a764de00fd905ee11361cc06b81b302a9fa8ebe4c23c languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.9.1": - version: 6.9.1 - resolution: "@typescript-eslint/scope-manager@npm:6.9.1" +"@typescript-eslint/scope-manager@npm:6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/scope-manager@npm:6.10.0" dependencies: - "@typescript-eslint/types": "npm:6.9.1" - "@typescript-eslint/visitor-keys": "npm:6.9.1" - checksum: 53fa7c3813d22b119e464f9b6d7d23407dfe103ee8ad2dcacf9ad6d656fda20e2bb3346df39e62b0e6b6ce71572ce5838071c5d2cca6daa4e0ce117ff22eafe5 + "@typescript-eslint/types": "npm:6.10.0" + "@typescript-eslint/visitor-keys": "npm:6.10.0" + checksum: a5fbee770d763852a7f426b950d495529139f1629fdcb30136c93f787acd82236db4272f78dff1d05a3a10a6406472ae95ae94ab75cfb618a06d75b8cc536cbf languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.9.1": - version: 6.9.1 - resolution: "@typescript-eslint/type-utils@npm:6.9.1" +"@typescript-eslint/type-utils@npm:6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/type-utils@npm:6.10.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:6.9.1" - "@typescript-eslint/utils": "npm:6.9.1" + "@typescript-eslint/typescript-estree": "npm:6.10.0" + "@typescript-eslint/utils": "npm:6.10.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.0.1" peerDependencies: @@ -3779,23 +3719,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 9373c32c9bce736527e01baabc1dbee4b7f43774ebdcbbe20ee9cf61d1b01e7faab3d5df1ebbe75241308c52eabbc9500dd7826701f95caee4054ca659420304 + checksum: f7c425d4da4d53d78b3d6630216dc1f2809f8dcaed62dc3cf12252102a53103a2aa39a160b310ca1cedebf87b8c339013be0c2360710c7c836b775374730c10e languageName: node linkType: hard -"@typescript-eslint/types@npm:6.9.1": - version: 6.9.1 - resolution: "@typescript-eslint/types@npm:6.9.1" - checksum: 4ba21ba18e256da210a4caedfbc5d4927cf8cb4f2c4d74f8ccc865576f3659b974e79119d3c94db2b68a4cec9cd687e43971d355450b7082d6d1736a5dd6db85 +"@typescript-eslint/types@npm:6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/types@npm:6.10.0" + checksum: 30f47de625405b3729db6d26a0376d98628bd966c70ca01fab1adcef91bba810d27ce643d844e42d1cc77bb2c6277e62efe278a090da63ba748dfe5710c4757b languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.9.1": - version: 6.9.1 - resolution: "@typescript-eslint/typescript-estree@npm:6.9.1" +"@typescript-eslint/typescript-estree@npm:6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/typescript-estree@npm:6.10.0" dependencies: - "@typescript-eslint/types": "npm:6.9.1" - "@typescript-eslint/visitor-keys": "npm:6.9.1" + "@typescript-eslint/types": "npm:6.10.0" + "@typescript-eslint/visitor-keys": "npm:6.10.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -3804,34 +3744,34 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 850b1865a90107879186c3f2969968a2c08fc6fcc56d146483c297cf5be376e33d505ac81533ba8e8103ca4d2edfea7d21b178de9e52217f7ee2922f51a445fa + checksum: ca28ca5a55e2d431c649ad093e4a4302f2b37c430bbeebbe622b05c727fd14dab136aead5a96848499d3ff4d187889733f8871b8dd5205d19bed4a260ad74544 languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.9.1, @typescript-eslint/utils@npm:^6.5.0": - version: 6.9.1 - resolution: "@typescript-eslint/utils@npm:6.9.1" +"@typescript-eslint/utils@npm:6.10.0, @typescript-eslint/utils@npm:^6.5.0": + version: 6.10.0 + resolution: "@typescript-eslint/utils@npm:6.10.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" "@types/json-schema": "npm:^7.0.12" "@types/semver": "npm:^7.5.0" - "@typescript-eslint/scope-manager": "npm:6.9.1" - "@typescript-eslint/types": "npm:6.9.1" - "@typescript-eslint/typescript-estree": "npm:6.9.1" + "@typescript-eslint/scope-manager": "npm:6.10.0" + "@typescript-eslint/types": "npm:6.10.0" + "@typescript-eslint/typescript-estree": "npm:6.10.0" semver: "npm:^7.5.4" peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: 3d329d54c3d155ed29e2b456a602aef76bda1b88dfcf847145849362e4ddefabe5c95de236de750d08d5da9bedcfb2131bdfd784ce4eb87cf82728f0b6662033 + checksum: 809a1d08b154f76ed7a99edddf872369f6ed93987cea19a18cb9f12b8390bddcff9138d9d94955545da54488d59e0001054bec13baf6d858a1761b059480b887 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.9.1": - version: 6.9.1 - resolution: "@typescript-eslint/visitor-keys@npm:6.9.1" +"@typescript-eslint/visitor-keys@npm:6.10.0": + version: 6.10.0 + resolution: "@typescript-eslint/visitor-keys@npm:6.10.0" dependencies: - "@typescript-eslint/types": "npm:6.9.1" + "@typescript-eslint/types": "npm:6.10.0" eslint-visitor-keys: "npm:^3.4.1" - checksum: ac5f375a177add30489e5b63cafa8d82a196b33624bb36418422ebe0d7973b3ba550dc7e0dda36ea75a94cf9b200b4fb5f5fb4d77c027fd801201c1a269d343b + checksum: f9223c148655ce00bb17db8aa92ee964e62c75d15095893e0b4d653c60a4033f456329b06de3eab4b404d8df359904f0dd6e3c8c842885c6d130e28ccd95ce03 languageName: node linkType: hard @@ -4347,7 +4287,7 @@ __metadata: languageName: node linkType: hard -"aria-query@npm:^5.0.0, aria-query@npm:^5.1.3": +"aria-query@npm:^5.0.0, aria-query@npm:^5.3.0": version: 5.3.0 resolution: "aria-query@npm:5.3.0" dependencies: @@ -4565,10 +4505,10 @@ __metadata: languageName: node linkType: hard -"ast-types-flow@npm:^0.0.7": - version: 0.0.7 - resolution: "ast-types-flow@npm:0.0.7" - checksum: f381529f2da535949ba6cceddbdfaa33b4d5105842e147ec63582f560ea9ecc1a08f66457664f3109841d3053641fa8b9fa94ba607f1ea9f6c804fe5dee44a1d +"ast-types-flow@npm:^0.0.8": + version: 0.0.8 + resolution: "ast-types-flow@npm:0.0.8" + checksum: f2a0ba8055353b743c41431974521e5e852a9824870cd6fce2db0e538ac7bf4da406bbd018d109af29ff3f8f0993f6a730c9eddbd0abd031fbcb29ca75c1014e languageName: node linkType: hard @@ -4675,10 +4615,10 @@ __metadata: languageName: node linkType: hard -"axe-core@npm:^4.6.2": - version: 4.7.2 - resolution: "axe-core@npm:4.7.2" - checksum: 8dfc61f038fbd9623ae8a264c8a475d887113a027fb440a2b377b82ffd300e71d1a0bcf042ff13b517a8d548b34c44b4159eff693725c5d7cde240d0aa68feac +"axe-core@npm:=4.7.0": + version: 4.7.0 + resolution: "axe-core@npm:4.7.0" + checksum: 89ac5712b5932ac7d23398b4cb5ba081c394a086e343acc68ba49c83472706e18e0799804e8388c779dcdacc465377deb29f2714241d3fbb389cf3a6b275c9ba languageName: node linkType: hard @@ -4693,7 +4633,7 @@ __metadata: languageName: node linkType: hard -"axobject-query@npm:^3.1.1": +"axobject-query@npm:^3.2.1": version: 3.2.1 resolution: "axobject-query@npm:3.2.1" dependencies: @@ -5807,10 +5747,10 @@ __metadata: languageName: node linkType: hard -"comment-parser@npm:1.4.0": - version: 1.4.0 - resolution: "comment-parser@npm:1.4.0" - checksum: c87ba95d5ff9ae380ed7aab2aa8490303652d535c0cff5b1f16a97be0633d0827d689b5e854b0003fbb6341ce22caf000a03eb1badcdfbb142d7aea8f921c12b +"comment-parser@npm:1.4.1": + version: 1.4.1 + resolution: "comment-parser@npm:1.4.1" + checksum: d6c4be3f5be058f98b24f2d557f745d8fe1cc9eb75bebbdccabd404a0e1ed41563171b16285f593011f8b6a5ec81f564fb1f2121418ac5cbf0f49255bf0840dd languageName: node linkType: hard @@ -6614,13 +6554,14 @@ __metadata: languageName: node linkType: hard -"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4, define-properties@npm:^1.2.0": - version: 1.2.0 - resolution: "define-properties@npm:1.2.0" +"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4, define-properties@npm:^1.2.0, define-properties@npm:^1.2.1": + version: 1.2.1 + resolution: "define-properties@npm:1.2.1" dependencies: + define-data-property: "npm:^1.0.1" has-property-descriptors: "npm:^1.0.0" object-keys: "npm:^1.1.1" - checksum: 34b58cae4651936a3c8c720310ce393a3227f5123640ab5402e7d6e59bb44f8295b789cb5d74e7513682b2e60ff20586d6f52b726d964d617abffa3da76344e0 + checksum: 88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3 languageName: node linkType: hard @@ -7160,7 +7101,7 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.17.2, es-abstract@npm:^1.20.4, es-abstract@npm:^1.21.2, es-abstract@npm:^1.21.3, es-abstract@npm:^1.22.1": +"es-abstract@npm:^1.17.2, es-abstract@npm:^1.20.4, es-abstract@npm:^1.21.2, es-abstract@npm:^1.22.1": version: 1.22.3 resolution: "es-abstract@npm:1.22.3" dependencies: @@ -7231,14 +7172,14 @@ __metadata: languageName: node linkType: hard -"es-iterator-helpers@npm:^1.0.12": - version: 1.0.13 - resolution: "es-iterator-helpers@npm:1.0.13" +"es-iterator-helpers@npm:^1.0.12, es-iterator-helpers@npm:^1.0.15": + version: 1.0.15 + resolution: "es-iterator-helpers@npm:1.0.15" dependencies: asynciterator.prototype: "npm:^1.0.0" call-bind: "npm:^1.0.2" - define-properties: "npm:^1.2.0" - es-abstract: "npm:^1.21.3" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.22.1" es-set-tostringtag: "npm:^2.0.1" function-bind: "npm:^1.1.1" get-intrinsic: "npm:^1.2.1" @@ -7247,9 +7188,9 @@ __metadata: has-proto: "npm:^1.0.1" has-symbols: "npm:^1.0.3" internal-slot: "npm:^1.0.5" - iterator.prototype: "npm:^1.1.0" - safe-array-concat: "npm:^1.0.0" - checksum: e6109017c432376294d5d6849cd0a5f8d9bcf5819eea612026e4401bb362d798c01e7a8984702b87d9d689c07b1146a31a99f17a761ca4e7e6470d9e8db9bea8 + iterator.prototype: "npm:^1.1.2" + safe-array-concat: "npm:^1.0.1" + checksum: b4c83f94bfe624260d5238092de3173989f76f1416b1d02c388aea3b2024174e5f5f0e864057311ac99790b57e836ca3545b6e77256b26066dac944519f5e6d6 languageName: node linkType: hard @@ -7390,11 +7331,11 @@ __metadata: linkType: hard "eslint-plugin-formatjs@npm:^4.10.1": - version: 4.11.0 - resolution: "eslint-plugin-formatjs@npm:4.11.0" + version: 4.11.2 + resolution: "eslint-plugin-formatjs@npm:4.11.2" dependencies: - "@formatjs/icu-messageformat-parser": "npm:2.7.0" - "@formatjs/ts-transformer": "npm:3.13.6" + "@formatjs/icu-messageformat-parser": "npm:2.7.2" + "@formatjs/ts-transformer": "npm:3.13.8" "@types/eslint": "npm:7 || 8" "@types/picomatch": "npm:^2.3.0" "@typescript-eslint/utils": "npm:^6.5.0" @@ -7406,7 +7347,7 @@ __metadata: unicode-emoji-utils: "npm:^1.1.1" peerDependencies: eslint: 7 || 8 - checksum: 4b1afb99d1d46e5e2200669a3918c0238b075c89ac9790f3339d9231f86c093cdd0560b7bfa79e81f99b390b9beab68b3dc8cb8dac57285db2f9b120e7f2667a + checksum: f5a6bffd9c65b9ce765be74d384618e543388720036b070d69d93c00b8c2bfded543141affc7793bf402f2c9177e2bbc395a7d1e8b806a40bfde1744c282a13c languageName: node linkType: hard @@ -7438,12 +7379,12 @@ __metadata: linkType: hard "eslint-plugin-jsdoc@npm:^46.1.0": - version: 46.8.2 - resolution: "eslint-plugin-jsdoc@npm:46.8.2" + version: 46.9.0 + resolution: "eslint-plugin-jsdoc@npm:46.9.0" dependencies: - "@es-joy/jsdoccomment": "npm:~0.40.1" + "@es-joy/jsdoccomment": "npm:~0.41.0" are-docs-informative: "npm:^0.0.2" - comment-parser: "npm:1.4.0" + comment-parser: "npm:1.4.1" debug: "npm:^4.3.4" escape-string-regexp: "npm:^4.0.0" esquery: "npm:^1.5.0" @@ -7452,33 +7393,33 @@ __metadata: spdx-expression-parse: "npm:^3.0.1" peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: ccf38567ddd73d7c57bf144d0fe9c1fe4a54e407353b3577bf036e9919a8ef96e7e385834ee383b64c7c2090b15a0f84a55b9dc5f50539ff399a3f7b91d26b48 + checksum: 4566b0f9bda54b446c813cf5ea93ae6d5866cbc4d448cb957b9ce2563f934d3ed2ed4e665e5a870750860a57137a1714c38599c35c60be16dce0f8e5a75b6ff6 languageName: node linkType: hard -"eslint-plugin-jsx-a11y@npm:~6.7.1": - version: 6.7.1 - resolution: "eslint-plugin-jsx-a11y@npm:6.7.1" +"eslint-plugin-jsx-a11y@npm:~6.8.0": + version: 6.8.0 + resolution: "eslint-plugin-jsx-a11y@npm:6.8.0" dependencies: - "@babel/runtime": "npm:^7.20.7" - aria-query: "npm:^5.1.3" - array-includes: "npm:^3.1.6" - array.prototype.flatmap: "npm:^1.3.1" - ast-types-flow: "npm:^0.0.7" - axe-core: "npm:^4.6.2" - axobject-query: "npm:^3.1.1" + "@babel/runtime": "npm:^7.23.2" + aria-query: "npm:^5.3.0" + array-includes: "npm:^3.1.7" + array.prototype.flatmap: "npm:^1.3.2" + ast-types-flow: "npm:^0.0.8" + axe-core: "npm:=4.7.0" + axobject-query: "npm:^3.2.1" damerau-levenshtein: "npm:^1.0.8" emoji-regex: "npm:^9.2.2" - has: "npm:^1.0.3" - jsx-ast-utils: "npm:^3.3.3" - language-tags: "npm:=1.0.5" + es-iterator-helpers: "npm:^1.0.15" + hasown: "npm:^2.0.0" + jsx-ast-utils: "npm:^3.3.5" + language-tags: "npm:^1.0.9" minimatch: "npm:^3.1.2" - object.entries: "npm:^1.1.6" - object.fromentries: "npm:^2.0.6" - semver: "npm:^6.3.0" + object.entries: "npm:^1.1.7" + object.fromentries: "npm:^2.0.7" peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: 41ad3d0c8036b36cd475685c1ad639157f403b16e8ac23c07f1dbe0226ccf8458f2805cbd5cc8e56856a5d8a356f3276e3139274d819476ccad80c41b9245502 + checksum: 199b883e526e6f9d7c54cb3f094abc54f11a1ec816db5fb6cae3b938eb0e503acc10ccba91ca7451633a9d0b9abc0ea03601844a8aba5fe88c5e8897c9ac8f49 languageName: node linkType: hard @@ -10039,16 +9980,16 @@ __metadata: languageName: node linkType: hard -"iterator.prototype@npm:^1.1.0": - version: 1.1.0 - resolution: "iterator.prototype@npm:1.1.0" +"iterator.prototype@npm:^1.1.2": + version: 1.1.2 + resolution: "iterator.prototype@npm:1.1.2" dependencies: - define-properties: "npm:^1.1.4" - get-intrinsic: "npm:^1.1.3" + define-properties: "npm:^1.2.1" + get-intrinsic: "npm:^1.2.1" has-symbols: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.0" - reflect.getprototypeof: "npm:^1.0.3" - checksum: fd641c4cc8cf85a1f99c772722589393b6b59562c7b73cae6bea26e0814b9bdd095d40818f061b85a4f386ecebee92f9a01ba79a70951d72bd3dd3e01a6c624c + reflect.getprototypeof: "npm:^1.0.4" + set-function-name: "npm:^2.0.1" + checksum: a32151326095e916f306990d909f6bbf23e3221999a18ba686419535dcd1749b10ded505e89334b77dc4c7a58a8508978f0eb16c2c8573e6d412eb7eb894ea79 languageName: node linkType: hard @@ -10807,7 +10748,7 @@ __metadata: languageName: node linkType: hard -"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.3": +"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.5": version: 3.3.5 resolution: "jsx-ast-utils@npm:3.3.5" dependencies: @@ -10870,19 +10811,19 @@ __metadata: languageName: node linkType: hard -"language-subtag-registry@npm:~0.3.2": +"language-subtag-registry@npm:^0.3.20": version: 0.3.22 resolution: "language-subtag-registry@npm:0.3.22" checksum: d1e09971260a7cd3b9fdeb190d33af0b6e99c8697013537d9aaa15f7856d9d83aee128ba8078e219df0a7cf4b8dd18d1a0c188f6543b500d92a2689d2d114b70 languageName: node linkType: hard -"language-tags@npm:=1.0.5": - version: 1.0.5 - resolution: "language-tags@npm:1.0.5" +"language-tags@npm:^1.0.9": + version: 1.0.9 + resolution: "language-tags@npm:1.0.9" dependencies: - language-subtag-registry: "npm:~0.3.2" - checksum: 04215e821af9a8f1bc6c99ab5aa0a316c3fe1912ca3337eb28596316064bddd8edd22f2883d866069ebdf01b2002e504a760a336b2c728b6d30514e86744f76c + language-subtag-registry: "npm:^0.3.20" + checksum: 9ab911213c4bd8bd583c850201c17794e52cb0660d1ab6e32558aadc8324abebf6844e46f92b80a5d600d0fbba7eface2c207bfaf270a1c7fd539e4c3a880bff languageName: node linkType: hard @@ -12133,14 +12074,14 @@ __metadata: languageName: node linkType: hard -"object.entries@npm:^1.1.6": - version: 1.1.6 - resolution: "object.entries@npm:1.1.6" +"object.entries@npm:^1.1.6, object.entries@npm:^1.1.7": + version: 1.1.7 + resolution: "object.entries@npm:1.1.7" dependencies: call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.4" - es-abstract: "npm:^1.20.4" - checksum: 8782c71db3a068ccbae9e0541e6b4ac2c25dc67c63f97b7e6ad3c88271d7820197e7398e37747f96542ed47c27f0b81148cdf14c42df15dc22f64818ae7bb5bf + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + checksum: 3ad1899cc7bf14546bf28f4a9b363ae8690b90948fcfbcac4c808395435d760f26193d9cae95337ce0e3c1e5c1f4fa45f7b46b31b68d389e9e117fce38775d86 languageName: node linkType: hard @@ -14193,17 +14134,17 @@ __metadata: languageName: node linkType: hard -"reflect.getprototypeof@npm:^1.0.3": - version: 1.0.3 - resolution: "reflect.getprototypeof@npm:1.0.3" +"reflect.getprototypeof@npm:^1.0.4": + version: 1.0.4 + resolution: "reflect.getprototypeof@npm:1.0.4" dependencies: call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.4" - es-abstract: "npm:^1.20.4" - get-intrinsic: "npm:^1.1.1" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + get-intrinsic: "npm:^1.2.1" globalthis: "npm:^1.0.3" which-builtin-type: "npm:^1.1.3" - checksum: 6300460adb743c5e710f3d0b9c2f49206a4f2a8cc61640e58565d13df3659747e82a88758666f5d32ed449ac3647cfcf0bbd48b574ceed8cb2ea14f20a719580 + checksum: 02104cdd22658b637efe6b1df73658edab539268347327c8250a72d0cb273dcdf280c284e2d94155d22601d022d16be1a816a8616d679e447cbcbde9860d15cb languageName: node linkType: hard @@ -14921,7 +14862,7 @@ __metadata: languageName: node linkType: hard -"set-function-name@npm:^2.0.0": +"set-function-name@npm:^2.0.0, set-function-name@npm:^2.0.1": version: 2.0.1 resolution: "set-function-name@npm:2.0.1" dependencies: From 0945e25b8f4ac46f6522277a3461044f37c7139b Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 13 Nov 2023 09:53:22 -0500 Subject: [PATCH 019/255] Add `Api::V1::Statuses::BaseController` base controller class (#27794) --- .../api/v1/statuses/base_controller.rb | 16 ++++++++++++++++ .../api/v1/statuses/bookmarks_controller.rb | 15 ++------------- .../favourited_by_accounts_controller.rb | 12 +----------- .../api/v1/statuses/favourites_controller.rb | 15 ++------------- .../api/v1/statuses/histories_controller.rb | 12 +----------- .../api/v1/statuses/mutes_controller.rb | 12 +----------- .../api/v1/statuses/pins_controller.rb | 9 +-------- .../statuses/reblogged_by_accounts_controller.rb | 12 +----------- .../api/v1/statuses/reblogs_controller.rb | 4 ++-- .../api/v1/statuses/sources_controller.rb | 14 +------------- .../api/v1/statuses/translations_controller.rb | 12 +----------- 11 files changed, 29 insertions(+), 104 deletions(-) create mode 100644 app/controllers/api/v1/statuses/base_controller.rb diff --git a/app/controllers/api/v1/statuses/base_controller.rb b/app/controllers/api/v1/statuses/base_controller.rb new file mode 100644 index 000000000..3f56b68bc --- /dev/null +++ b/app/controllers/api/v1/statuses/base_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class Api::V1::Statuses::BaseController < Api::BaseController + include Authorization + + before_action :set_status + + private + + def set_status + @status = Status.find(params[:status_id]) + authorize @status, :show? + rescue Mastodon::NotPermittedError + not_found + end +end diff --git a/app/controllers/api/v1/statuses/bookmarks_controller.rb b/app/controllers/api/v1/statuses/bookmarks_controller.rb index 19963c002..109b12f46 100644 --- a/app/controllers/api/v1/statuses/bookmarks_controller.rb +++ b/app/controllers/api/v1/statuses/bookmarks_controller.rb @@ -1,11 +1,9 @@ # frozen_string_literal: true -class Api::V1::Statuses::BookmarksController < Api::BaseController - include Authorization - +class Api::V1::Statuses::BookmarksController < Api::V1::Statuses::BaseController before_action -> { doorkeeper_authorize! :write, :'write:bookmarks' } before_action :require_user! - before_action :set_status, only: [:create] + skip_before_action :set_status, only: [:destroy] def create current_account.bookmarks.find_or_create_by!(account: current_account, status: @status) @@ -28,13 +26,4 @@ class Api::V1::Statuses::BookmarksController < Api::BaseController rescue Mastodon::NotPermittedError not_found end - - private - - def set_status - @status = Status.find(params[:status_id]) - authorize @status, :show? - rescue Mastodon::NotPermittedError - not_found - end end diff --git a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb index 73eb11e71..3cca246ce 100644 --- a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb +++ b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb @@ -1,10 +1,7 @@ # frozen_string_literal: true -class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController - include Authorization - +class Api::V1::Statuses::FavouritedByAccountsController < Api::V1::Statuses::BaseController before_action -> { authorize_if_got_token! :read, :'read:accounts' } - before_action :set_status after_action :insert_pagination_headers def index @@ -61,13 +58,6 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) end - def set_status - @status = Status.find(params[:status_id]) - authorize @status, :show? - rescue Mastodon::NotPermittedError - not_found - end - def pagination_params(core_params) params.slice(:limit).permit(:limit).merge(core_params) end diff --git a/app/controllers/api/v1/statuses/favourites_controller.rb b/app/controllers/api/v1/statuses/favourites_controller.rb index f3428e3df..dbc75a036 100644 --- a/app/controllers/api/v1/statuses/favourites_controller.rb +++ b/app/controllers/api/v1/statuses/favourites_controller.rb @@ -1,11 +1,9 @@ # frozen_string_literal: true -class Api::V1::Statuses::FavouritesController < Api::BaseController - include Authorization - +class Api::V1::Statuses::FavouritesController < Api::V1::Statuses::BaseController before_action -> { doorkeeper_authorize! :write, :'write:favourites' } before_action :require_user! - before_action :set_status, only: [:create] + skip_before_action :set_status, only: [:destroy] def create FavouriteService.new.call(current_account, @status) @@ -30,13 +28,4 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController rescue Mastodon::NotPermittedError not_found end - - private - - def set_status - @status = Status.find(params[:status_id]) - authorize @status, :show? - rescue Mastodon::NotPermittedError - not_found - end end diff --git a/app/controllers/api/v1/statuses/histories_controller.rb b/app/controllers/api/v1/statuses/histories_controller.rb index 2913472b0..dcb21ef04 100644 --- a/app/controllers/api/v1/statuses/histories_controller.rb +++ b/app/controllers/api/v1/statuses/histories_controller.rb @@ -1,10 +1,7 @@ # frozen_string_literal: true -class Api::V1::Statuses::HistoriesController < Api::BaseController - include Authorization - +class Api::V1::Statuses::HistoriesController < Api::V1::Statuses::BaseController before_action -> { authorize_if_got_token! :read, :'read:statuses' } - before_action :set_status def show cache_if_unauthenticated! @@ -16,11 +13,4 @@ class Api::V1::Statuses::HistoriesController < Api::BaseController def status_edits @status.edits.includes(:account, status: [:account]).to_a.presence || [@status.build_snapshot(at_time: @status.edited_at || @status.created_at)] end - - def set_status - @status = Status.find(params[:status_id]) - authorize @status, :show? - rescue Mastodon::NotPermittedError - not_found - end end diff --git a/app/controllers/api/v1/statuses/mutes_controller.rb b/app/controllers/api/v1/statuses/mutes_controller.rb index 87071a2b9..26b92bb8a 100644 --- a/app/controllers/api/v1/statuses/mutes_controller.rb +++ b/app/controllers/api/v1/statuses/mutes_controller.rb @@ -1,11 +1,8 @@ # frozen_string_literal: true -class Api::V1::Statuses::MutesController < Api::BaseController - include Authorization - +class Api::V1::Statuses::MutesController < Api::V1::Statuses::BaseController before_action -> { doorkeeper_authorize! :write, :'write:mutes' } before_action :require_user! - before_action :set_status before_action :set_conversation def create @@ -24,13 +21,6 @@ class Api::V1::Statuses::MutesController < Api::BaseController private - def set_status - @status = Status.find(params[:status_id]) - authorize @status, :show? - rescue Mastodon::NotPermittedError - not_found - end - def set_conversation @conversation = @status.conversation raise Mastodon::ValidationError if @conversation.nil? diff --git a/app/controllers/api/v1/statuses/pins_controller.rb b/app/controllers/api/v1/statuses/pins_controller.rb index 51b1621b6..7107890af 100644 --- a/app/controllers/api/v1/statuses/pins_controller.rb +++ b/app/controllers/api/v1/statuses/pins_controller.rb @@ -1,11 +1,8 @@ # frozen_string_literal: true -class Api::V1::Statuses::PinsController < Api::BaseController - include Authorization - +class Api::V1::Statuses::PinsController < Api::V1::Statuses::BaseController before_action -> { doorkeeper_authorize! :write, :'write:accounts' } before_action :require_user! - before_action :set_status def create StatusPin.create!(account: current_account, status: @status) @@ -26,10 +23,6 @@ class Api::V1::Statuses::PinsController < Api::BaseController private - def set_status - @status = Status.find(params[:status_id]) - end - def distribute_add_activity! json = ActiveModelSerializers::SerializableResource.new( @status, diff --git a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb index 41672e753..dd3e60846 100644 --- a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb +++ b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb @@ -1,10 +1,7 @@ # frozen_string_literal: true -class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController - include Authorization - +class Api::V1::Statuses::RebloggedByAccountsController < Api::V1::Statuses::BaseController before_action -> { authorize_if_got_token! :read, :'read:accounts' } - before_action :set_status after_action :insert_pagination_headers def index @@ -57,13 +54,6 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) end - def set_status - @status = Status.find(params[:status_id]) - authorize @status, :show? - rescue Mastodon::NotPermittedError - not_found - end - def pagination_params(core_params) params.slice(:limit).permit(:limit).merge(core_params) end diff --git a/app/controllers/api/v1/statuses/reblogs_controller.rb b/app/controllers/api/v1/statuses/reblogs_controller.rb index 3ca623117..971b054c5 100644 --- a/app/controllers/api/v1/statuses/reblogs_controller.rb +++ b/app/controllers/api/v1/statuses/reblogs_controller.rb @@ -1,13 +1,13 @@ # frozen_string_literal: true -class Api::V1::Statuses::ReblogsController < Api::BaseController - include Authorization +class Api::V1::Statuses::ReblogsController < Api::V1::Statuses::BaseController include Redisable include Lockable before_action -> { doorkeeper_authorize! :write, :'write:statuses' } before_action :require_user! before_action :set_reblog, only: [:create] + skip_before_action :set_status override_rate_limit_headers :create, family: :statuses diff --git a/app/controllers/api/v1/statuses/sources_controller.rb b/app/controllers/api/v1/statuses/sources_controller.rb index 434086451..5ceda4c7e 100644 --- a/app/controllers/api/v1/statuses/sources_controller.rb +++ b/app/controllers/api/v1/statuses/sources_controller.rb @@ -1,21 +1,9 @@ # frozen_string_literal: true -class Api::V1::Statuses::SourcesController < Api::BaseController - include Authorization - +class Api::V1::Statuses::SourcesController < Api::V1::Statuses::BaseController before_action -> { doorkeeper_authorize! :read, :'read:statuses' } - before_action :set_status def show render json: @status, serializer: REST::StatusSourceSerializer end - - private - - def set_status - @status = Status.find(params[:status_id]) - authorize @status, :show? - rescue Mastodon::NotPermittedError - not_found - end end diff --git a/app/controllers/api/v1/statuses/translations_controller.rb b/app/controllers/api/v1/statuses/translations_controller.rb index ec5ea5b85..7d406b0a3 100644 --- a/app/controllers/api/v1/statuses/translations_controller.rb +++ b/app/controllers/api/v1/statuses/translations_controller.rb @@ -1,10 +1,7 @@ # frozen_string_literal: true -class Api::V1::Statuses::TranslationsController < Api::BaseController - include Authorization - +class Api::V1::Statuses::TranslationsController < Api::V1::Statuses::BaseController before_action -> { doorkeeper_authorize! :read, :'read:statuses' } - before_action :set_status before_action :set_translation rescue_from TranslationService::NotConfiguredError, with: :not_found @@ -24,13 +21,6 @@ class Api::V1::Statuses::TranslationsController < Api::BaseController private - def set_status - @status = Status.find(params[:status_id]) - authorize @status, :show? - rescue Mastodon::NotPermittedError - not_found - end - def set_translation @translation = TranslateStatusService.new.call(@status, content_locale) end From 49ba5a9f94eb2b595f9bb04e29ba4e7e1d99889a Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 13 Nov 2023 11:01:24 -0500 Subject: [PATCH 020/255] Use `hash_including` to check `AccountFilter` setup in `admin/accounts` controller spec (#27838) --- .../controllers/admin/accounts_controller_spec.rb | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/spec/controllers/admin/accounts_controller_spec.rb b/spec/controllers/admin/accounts_controller_spec.rb index ba03ec85a..3b8fa2f71 100644 --- a/spec/controllers/admin/accounts_controller_spec.rb +++ b/spec/controllers/admin/accounts_controller_spec.rb @@ -20,8 +20,7 @@ RSpec.describe Admin::AccountsController do it 'filters with parameters' do account_filter = instance_double(AccountFilter, results: Account.all) allow(AccountFilter).to receive(:new).and_return(account_filter) - - get :index, params: { + params = { origin: 'local', by_domain: 'domain', status: 'active', @@ -31,17 +30,9 @@ RSpec.describe Admin::AccountsController do ip: '0.0.0.42', } - expect(AccountFilter).to have_received(:new) do |params| - h = params.to_h + get :index, params: params - expect(h[:origin]).to eq 'local' - expect(h[:by_domain]).to eq 'domain' - expect(h[:status]).to eq 'active' - expect(h[:username]).to eq 'username' - expect(h[:display_name]).to eq 'display name' - expect(h[:email]).to eq 'local-part@domain' - expect(h[:ip]).to eq '0.0.0.42' - end + expect(AccountFilter).to have_received(:new).with(hash_including(params)) end it 'paginates accounts' do From bac9e0b55d77257b9b9d8ce602ca79c3885a9d18 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Mon, 13 Nov 2023 17:17:05 +0100 Subject: [PATCH 021/255] Add variable delay before link verification of remote account links (#27774) --- app/services/activitypub/process_account_service.rb | 2 +- app/services/update_account_service.rb | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index 1304ca824..8fc0989a3 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -180,7 +180,7 @@ class ActivityPub::ProcessAccountService < BaseService end def check_links! - VerifyAccountLinksWorker.perform_async(@account.id) + VerifyAccountLinksWorker.perform_in(rand(10.minutes.to_i), @account.id) end def process_duplicate_accounts! diff --git a/app/services/update_account_service.rb b/app/services/update_account_service.rb index a98f4d31e..1bbcfce3e 100644 --- a/app/services/update_account_service.rb +++ b/app/services/update_account_service.rb @@ -30,11 +30,7 @@ class UpdateAccountService < BaseService def check_links(account) return unless account.fields.any?(&:requires_verification?) - if account.local? - VerifyAccountLinksWorker.perform_async(account.id) - else - VerifyAccountLinksWorker.perform_in(rand(10.minutes.to_i), account.id) - end + VerifyAccountLinksWorker.perform_async(account.id) end def process_hashtags(account) From b7807f3d84983ab46c3345d076576ffa8433dab4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 13 Nov 2023 17:47:44 -0500 Subject: [PATCH 022/255] Use `normalizes` to prepare `Webhook#events` value (#27605) --- app/models/webhook.rb | 16 ++++++++-------- spec/models/webhook_spec.rb | 31 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/app/models/webhook.rb b/app/models/webhook.rb index 044097921..304b2b1f1 100644 --- a/app/models/webhook.rb +++ b/app/models/webhook.rb @@ -33,11 +33,11 @@ class Webhook < ApplicationRecord validates :secret, presence: true, length: { minimum: 12 } validates :events, presence: true - validate :validate_events + validate :events_validation_error, if: :invalid_events? validate :validate_permissions validate :validate_template - before_validation :strip_events + normalizes :events, with: ->(events) { events.filter_map { |event| event.strip.presence } } before_validation :generate_secret def rotate_secret! @@ -69,8 +69,12 @@ class Webhook < ApplicationRecord private - def validate_events - errors.add(:events, :invalid) if events.any? { |e| EVENTS.exclude?(e) } + def events_validation_error + errors.add(:events, :invalid) + end + + def invalid_events? + events.blank? || events.difference(EVENTS).any? end def validate_permissions @@ -88,10 +92,6 @@ class Webhook < ApplicationRecord end end - def strip_events - self.events = events.filter_map { |str| str.strip.presence } if events.present? - end - def generate_secret self.secret = SecureRandom.hex(20) if secret.blank? end diff --git a/spec/models/webhook_spec.rb b/spec/models/webhook_spec.rb index 715dd7574..effaf92e9 100644 --- a/spec/models/webhook_spec.rb +++ b/spec/models/webhook_spec.rb @@ -5,6 +5,37 @@ require 'rails_helper' RSpec.describe Webhook do let(:webhook) { Fabricate(:webhook) } + describe 'Validations' do + it 'requires presence of events' do + record = described_class.new(events: nil) + record.valid? + + expect(record).to model_have_error_on_field(:events) + end + + it 'requires non-empty events value' do + record = described_class.new(events: []) + record.valid? + + expect(record).to model_have_error_on_field(:events) + end + + it 'requires valid events value from EVENTS' do + record = described_class.new(events: ['account.invalid']) + record.valid? + + expect(record).to model_have_error_on_field(:events) + end + end + + describe 'Normalizations' do + it 'cleans up events values' do + record = described_class.new(events: ['account.approved', 'account.created ', '']) + + expect(record.events).to eq(%w(account.approved account.created)) + end + end + describe '#rotate_secret!' do it 'changes the secret' do previous_value = webhook.secret From 4aa06cbdbfbd4a4f9508c988c012951024b561e8 Mon Sep 17 00:00:00 2001 From: Brian Holley <brian.holley@hotmail.com> Date: Mon, 13 Nov 2023 16:39:54 -0800 Subject: [PATCH 023/255] Fix "Hide these posts from home" list setting not refreshing when switching lists (#27763) --- app/javascript/mastodon/features/list_timeline/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/list_timeline/index.jsx b/app/javascript/mastodon/features/list_timeline/index.jsx index aadb6ecd5..55579c2fd 100644 --- a/app/javascript/mastodon/features/list_timeline/index.jsx +++ b/app/javascript/mastodon/features/list_timeline/index.jsx @@ -204,7 +204,7 @@ class ListTimeline extends PureComponent { </div> <div className='setting-toggle'> - <Toggle id={`list-${id}-exclusive`} defaultChecked={isExclusive} onChange={this.onExclusiveToggle} /> + <Toggle id={`list-${id}-exclusive`} checked={isExclusive} onChange={this.onExclusiveToggle} /> <label htmlFor={`list-${id}-exclusive`} className='setting-toggle__label'> <FormattedMessage id='lists.exclusive' defaultMessage='Hide these posts from home' /> </label> From 5e2ecc736ddf275e57c91348a7b0a485f9b2462d Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 14 Nov 2023 05:29:33 -0500 Subject: [PATCH 024/255] Remove double `subject` in api/v1/accounts/relationships spec (#27839) --- .../api/v1/accounts/relationships_spec.rb | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/spec/requests/api/v1/accounts/relationships_spec.rb b/spec/requests/api/v1/accounts/relationships_spec.rb index bb78e3b3e..5011352c6 100644 --- a/spec/requests/api/v1/accounts/relationships_spec.rb +++ b/spec/requests/api/v1/accounts/relationships_spec.rb @@ -102,17 +102,25 @@ describe 'GET /api/v1/accounts/relationships' do end end - it 'returns JSON with correct data on cached requests too' do - subject - subject + it 'returns JSON with correct data on previously cached requests' do + # Initial request including multiple accounts in params + get '/api/v1/accounts/relationships', headers: headers, params: { id: [simon.id, lewis.id] } + expect(body_as_json.size).to eq(2) + + # Subsequent request with different id, should override cache from first request + get '/api/v1/accounts/relationships', headers: headers, params: { id: [simon.id] } expect(response).to have_http_status(200) - json = body_as_json - - expect(json).to be_a Enumerable - expect(json.first[:following]).to be true - expect(json.first[:showing_reblogs]).to be true + expect(body_as_json) + .to be_an(Enumerable) + .and have_attributes( + size: 1, + first: hash_including( + following: true, + showing_reblogs: true + ) + ) end it 'returns JSON with correct data after change too' do From 373aa95dddd7119725c4f11d3af402066e2288cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 11:30:39 +0100 Subject: [PATCH 025/255] Update formatjs monorepo (#27849) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 154 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 107 insertions(+), 47 deletions(-) diff --git a/yarn.lock b/yarn.lock index e8fe28fb4..1cb5a42d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1800,6 +1800,16 @@ __metadata: languageName: node linkType: hard +"@formatjs/ecma402-abstract@npm:1.18.0": + version: 1.18.0 + resolution: "@formatjs/ecma402-abstract@npm:1.18.0" + dependencies: + "@formatjs/intl-localematcher": "npm:0.5.2" + tslib: "npm:^2.4.0" + checksum: bbdad0aee8e48baad6bfe6b2c27caf3befe35e658b922ee2f84417a819f0bdc7e849a8c0c782db8b53f5666bf19669d2b10a1104257c08796d198c87766bfc92 + languageName: node + linkType: hard + "@formatjs/fast-memoize@npm:2.2.0": version: 2.2.0 resolution: "@formatjs/fast-memoize@npm:2.2.0" @@ -1820,6 +1830,17 @@ __metadata: languageName: node linkType: hard +"@formatjs/icu-messageformat-parser@npm:2.7.3": + version: 2.7.3 + resolution: "@formatjs/icu-messageformat-parser@npm:2.7.3" + dependencies: + "@formatjs/ecma402-abstract": "npm:1.18.0" + "@formatjs/icu-skeleton-parser": "npm:1.7.0" + tslib: "npm:^2.4.0" + checksum: 2a51038813e5cff7e2df767e1227373d228e907adb7268fc3744b3d82c4fa69d4aa9f6020a62de2c468cf724600e9372ac07ae43a4480ed066fe34e224e80e4a + languageName: node + linkType: hard + "@formatjs/icu-skeleton-parser@npm:1.6.4": version: 1.6.4 resolution: "@formatjs/icu-skeleton-parser@npm:1.6.4" @@ -1830,25 +1851,35 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-displaynames@npm:6.6.3": - version: 6.6.3 - resolution: "@formatjs/intl-displaynames@npm:6.6.3" +"@formatjs/icu-skeleton-parser@npm:1.7.0": + version: 1.7.0 + resolution: "@formatjs/icu-skeleton-parser@npm:1.7.0" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.4" - "@formatjs/intl-localematcher": "npm:0.5.1" + "@formatjs/ecma402-abstract": "npm:1.18.0" tslib: "npm:^2.4.0" - checksum: b0520cb744a51290fbcde80860f39ed9c9df9b81beae98986e1fc089ef635f7699c750631fa42a559f3678d1dd02b14904614e70360477d18e68d3eba6592390 + checksum: 2e4db815247ddb10f7990bbb501c85b854ee951ee45143673eb91b4392b11d0a8312327adb8b624c6a2fdafab12083904630d6d22475503d025f1612da4dcaee languageName: node linkType: hard -"@formatjs/intl-listformat@npm:7.5.2": - version: 7.5.2 - resolution: "@formatjs/intl-listformat@npm:7.5.2" +"@formatjs/intl-displaynames@npm:6.6.4": + version: 6.6.4 + resolution: "@formatjs/intl-displaynames@npm:6.6.4" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.4" - "@formatjs/intl-localematcher": "npm:0.5.1" + "@formatjs/ecma402-abstract": "npm:1.18.0" + "@formatjs/intl-localematcher": "npm:0.5.2" tslib: "npm:^2.4.0" - checksum: 54fa03da4ea45504681d6d87d72d1cac574809ce43f965fa4b845e83be3072d92324c58cec57ad386827087fb1d6ecae438d29576f30176bf52eb212e454bce2 + checksum: 009e443dd0d10776b8573d0181407d4c0d6c7a2ff537a5ea1e36413d1b08db9c21dfef272eabab8efabd01a58b64f663a30e4d584fd761df3fd68a5d23fe444b + languageName: node + linkType: hard + +"@formatjs/intl-listformat@npm:7.5.3": + version: 7.5.3 + resolution: "@formatjs/intl-listformat@npm:7.5.3" + dependencies: + "@formatjs/ecma402-abstract": "npm:1.18.0" + "@formatjs/intl-localematcher": "npm:0.5.2" + tslib: "npm:^2.4.0" + checksum: de741ce84b16fed57016afbfe446ebd57cd23a046859a9353f5d455f8bc9114493bf83b9e18429268c7ce8f77bc54516a9b8190baf09fbb25c9b06cfc80101d4 languageName: node linkType: hard @@ -1861,34 +1892,43 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-pluralrules@npm:^5.2.2": - version: 5.2.9 - resolution: "@formatjs/intl-pluralrules@npm:5.2.9" +"@formatjs/intl-localematcher@npm:0.5.2": + version: 0.5.2 + resolution: "@formatjs/intl-localematcher@npm:0.5.2" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.4" - "@formatjs/intl-localematcher": "npm:0.5.1" tslib: "npm:^2.4.0" - checksum: a6ca5c498ce542facacf8ce8640d4ba068f9119b758547a23614b50611eb385a46abd386ff88fa423211355ec463cf102c2c908b74f6e23a5bc9e2a23873dc29 + checksum: 4b3ae75470e3e53ffa39b2d46e65a2a4c9c4becbc0aac989b0694370e10c6687643660a045512d676509bc29b257fe5726fbb028de12f889be02c2d20b6527e6 languageName: node linkType: hard -"@formatjs/intl@npm:2.9.8": - version: 2.9.8 - resolution: "@formatjs/intl@npm:2.9.8" +"@formatjs/intl-pluralrules@npm:^5.2.2": + version: 5.2.10 + resolution: "@formatjs/intl-pluralrules@npm:5.2.10" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.4" + "@formatjs/ecma402-abstract": "npm:1.18.0" + "@formatjs/intl-localematcher": "npm:0.5.2" + tslib: "npm:^2.4.0" + checksum: 1050416613e80bff2c58546c80c8d52ed97847d13c90535a53d058e44969369b50e1cfdb464e9e9ef4802c934c84ea0e656c3f4e3b4d5ac7496b722c759da4cf + languageName: node + linkType: hard + +"@formatjs/intl@npm:2.9.9": + version: 2.9.9 + resolution: "@formatjs/intl@npm:2.9.9" + dependencies: + "@formatjs/ecma402-abstract": "npm:1.18.0" "@formatjs/fast-memoize": "npm:2.2.0" - "@formatjs/icu-messageformat-parser": "npm:2.7.2" - "@formatjs/intl-displaynames": "npm:6.6.3" - "@formatjs/intl-listformat": "npm:7.5.2" - intl-messageformat: "npm:10.5.7" + "@formatjs/icu-messageformat-parser": "npm:2.7.3" + "@formatjs/intl-displaynames": "npm:6.6.4" + "@formatjs/intl-listformat": "npm:7.5.3" + intl-messageformat: "npm:10.5.8" tslib: "npm:^2.4.0" peerDependencies: typescript: 5 peerDependenciesMeta: typescript: optional: true - checksum: 6341f4bfb56a0e14373395b1232e1eeb8e64588a8c3d4614cd2b06f71d4e65dbd4a79e3a1c07e1b6c20c48e399ac2385977b01a559e1d2bd1a1d226e0eae3058 + checksum: b26904da605ab309535dfbbfbd403a3bb33d51d3c969c548b88fa04755be3aff60b1bddd1c453514a84048c7432271cef507ac66de32dcfa66b3f842a1ddb977 languageName: node linkType: hard @@ -1912,6 +1952,26 @@ __metadata: languageName: node linkType: hard +"@formatjs/ts-transformer@npm:3.13.9": + version: 3.13.9 + resolution: "@formatjs/ts-transformer@npm:3.13.9" + dependencies: + "@formatjs/icu-messageformat-parser": "npm:2.7.3" + "@types/json-stable-stringify": "npm:^1.0.32" + "@types/node": "npm:14 || 16 || 17" + chalk: "npm:^4.0.0" + json-stable-stringify: "npm:^1.0.1" + tslib: "npm:^2.4.0" + typescript: "npm:5" + peerDependencies: + ts-jest: ">=27" + peerDependenciesMeta: + ts-jest: + optional: true + checksum: 4e313b967e45aae79246174c3181d31cc7cd297380d3a880a98fc0be16d76b783868712151e840ea16d22e2fbec0388b1005f688b6d4cb74ee4411b43f6d33f4 + languageName: node + linkType: hard + "@gamestdio/websocket@npm:^0.3.2": version: 0.3.2 resolution: "@gamestdio/websocket@npm:0.3.2" @@ -4675,21 +4735,21 @@ __metadata: linkType: hard "babel-plugin-formatjs@npm:^10.5.1": - version: 10.5.9 - resolution: "babel-plugin-formatjs@npm:10.5.9" + version: 10.5.10 + resolution: "babel-plugin-formatjs@npm:10.5.10" dependencies: "@babel/core": "npm:^7.10.4" "@babel/helper-plugin-utils": "npm:^7.10.4" "@babel/plugin-syntax-jsx": "npm:7" "@babel/traverse": "npm:7" "@babel/types": "npm:^7.12.11" - "@formatjs/icu-messageformat-parser": "npm:2.7.2" - "@formatjs/ts-transformer": "npm:3.13.8" + "@formatjs/icu-messageformat-parser": "npm:2.7.3" + "@formatjs/ts-transformer": "npm:3.13.9" "@types/babel__core": "npm:^7.1.7" "@types/babel__helper-plugin-utils": "npm:^7.10.0" "@types/babel__traverse": "npm:^7.1.7" tslib: "npm:^2.4.0" - checksum: 5e4127cf7b4b9b3306a9d0ab5b029831712d22db5e2117225ce706b55d222d09a7eba1f3720fdad7a99f61843b5cba107296fc11ae00a6f0941217d9322aa02e + checksum: bff65cd2a88a0ae00eabab1d022ffc44c4385b7e529cac42375bb1828c678c7a71a78f644512e5d1dd8cd532d418c16acdbabcef2bf6670e24404f4f164a74ce languageName: node linkType: hard @@ -9243,15 +9303,15 @@ __metadata: languageName: node linkType: hard -"intl-messageformat@npm:10.5.7, intl-messageformat@npm:^10.3.5": - version: 10.5.7 - resolution: "intl-messageformat@npm:10.5.7" +"intl-messageformat@npm:10.5.8, intl-messageformat@npm:^10.3.5": + version: 10.5.8 + resolution: "intl-messageformat@npm:10.5.8" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.4" + "@formatjs/ecma402-abstract": "npm:1.18.0" "@formatjs/fast-memoize": "npm:2.2.0" - "@formatjs/icu-messageformat-parser": "npm:2.7.2" + "@formatjs/icu-messageformat-parser": "npm:2.7.3" tslib: "npm:^2.4.0" - checksum: 7f341b3eb5b3d402167c99ca7fb98720c7ad553bed8a490b2210bd90ea9009a09f9030939307fecb111fce1454f31b4298b4f0a346999af627c86f8164a5c547 + checksum: 1d2854aae8471ec48165ca265760d6c5b1814eca831c88db698eb29b5ed20bee21ca8533090c9d28d9c6f1d844dda210b0bc58a2e036446158fae0845e5eed4f languageName: node linkType: hard @@ -13643,18 +13703,18 @@ __metadata: linkType: hard "react-intl@npm:^6.4.2": - version: 6.5.4 - resolution: "react-intl@npm:6.5.4" + version: 6.5.5 + resolution: "react-intl@npm:6.5.5" dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.4" - "@formatjs/icu-messageformat-parser": "npm:2.7.2" - "@formatjs/intl": "npm:2.9.8" - "@formatjs/intl-displaynames": "npm:6.6.3" - "@formatjs/intl-listformat": "npm:7.5.2" + "@formatjs/ecma402-abstract": "npm:1.18.0" + "@formatjs/icu-messageformat-parser": "npm:2.7.3" + "@formatjs/intl": "npm:2.9.9" + "@formatjs/intl-displaynames": "npm:6.6.4" + "@formatjs/intl-listformat": "npm:7.5.3" "@types/hoist-non-react-statics": "npm:^3.3.1" "@types/react": "npm:16 || 17 || 18" hoist-non-react-statics: "npm:^3.3.2" - intl-messageformat: "npm:10.5.7" + intl-messageformat: "npm:10.5.8" tslib: "npm:^2.4.0" peerDependencies: react: ^16.6.0 || 17 || 18 @@ -13662,7 +13722,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 1117a7f866b103abf88a4087f5fe8b854d9c069c69444c592f8431e7d28c9b90423f7b50e550be0f2f173b7563e943bcc9238e80f6747181f81861275f6e2ce7 + checksum: 9ff6200f195557804b735d618ee593aed7848e84213ac4eb9c57708f55c0d93232e0dd338c990348ba3b1d73dca071502a2051d4a2790838d962c3ccde87fa6c languageName: node linkType: hard From 1f8173ac5aa2dbdab66e6c426b137f4fcc162462 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 14 Nov 2023 05:31:59 -0500 Subject: [PATCH 026/255] Extract private methods in api/v1/instances/domain_blocks (#27844) --- .../api/v1/instances/domain_blocks_controller.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/instances/domain_blocks_controller.rb b/app/controllers/api/v1/instances/domain_blocks_controller.rb index 566764dbf..8fb90305a 100644 --- a/app/controllers/api/v1/instances/domain_blocks_controller.rb +++ b/app/controllers/api/v1/instances/domain_blocks_controller.rb @@ -13,7 +13,7 @@ class Api::V1::Instances::DomainBlocksController < Api::V1::Instances::BaseContr cache_if_unauthenticated! end - render json: @domain_blocks, each_serializer: REST::DomainBlockSerializer, with_comment: (Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?)) + render json: @domain_blocks, each_serializer: REST::DomainBlockSerializer, with_comment: show_rationale_in_response? end private @@ -25,4 +25,16 @@ class Api::V1::Instances::DomainBlocksController < Api::V1::Instances::BaseContr def set_domain_blocks @domain_blocks = DomainBlock.with_user_facing_limitations.by_severity end + + def show_rationale_in_response? + always_show_rationale? || show_rationale_for_user? + end + + def always_show_rationale? + Setting.show_domain_blocks_rationale == 'all' + end + + def show_rationale_for_user? + Setting.show_domain_blocks_rationale == 'users' && user_signed_in? + end end From c1e071f6343a0b5c6383e6a336fd1aaf8dc97100 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 11:53:47 +0100 Subject: [PATCH 027/255] New Crowdin Translations (automated) (#27848) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/af.json | 4 ++++ app/javascript/mastodon/locales/be.json | 6 +++--- app/javascript/mastodon/locales/ca.json | 1 + app/javascript/mastodon/locales/fy.json | 1 + app/javascript/mastodon/locales/lt.json | 9 ++++++++- app/javascript/mastodon/locales/sl.json | 1 + app/javascript/mastodon/locales/sr-Latn.json | 1 + app/javascript/mastodon/locales/sr.json | 1 + config/locales/activerecord.af.yml | 4 ++++ config/locales/af.yml | 17 +++++++++++++++++ config/locales/be.yml | 1 + config/locales/ca.yml | 1 + config/locales/cy.yml | 1 + config/locales/da.yml | 5 +++++ config/locales/de.yml | 1 + config/locales/devise.be.yml | 2 +- config/locales/doorkeeper.af.yml | 1 + config/locales/es-AR.yml | 1 + config/locales/es-MX.yml | 1 + config/locales/es.yml | 1 + config/locales/eu.yml | 1 + config/locales/fa.yml | 1 + config/locales/fo.yml | 1 + config/locales/fr-QC.yml | 1 + config/locales/fr.yml | 1 + config/locales/fy.yml | 1 + config/locales/gl.yml | 1 + config/locales/he.yml | 5 +++-- config/locales/hu.yml | 1 + config/locales/is.yml | 1 + config/locales/it.yml | 1 + config/locales/ko.yml | 1 + config/locales/lt.yml | 1 + config/locales/nl.yml | 1 + config/locales/nn.yml | 1 + config/locales/no.yml | 1 + config/locales/pl.yml | 1 + config/locales/pt-BR.yml | 1 + config/locales/pt-PT.yml | 1 + config/locales/simple_form.be.yml | 2 +- config/locales/sk.yml | 8 ++++++++ config/locales/sl.yml | 1 + config/locales/sq.yml | 1 + config/locales/sr-Latn.yml | 1 + config/locales/sr.yml | 1 + config/locales/sv.yml | 1 + config/locales/th.yml | 1 + config/locales/tr.yml | 1 + config/locales/uk.yml | 1 + config/locales/zh-CN.yml | 1 + config/locales/zh-HK.yml | 1 + config/locales/zh-TW.yml | 1 + 52 files changed, 96 insertions(+), 8 deletions(-) diff --git a/app/javascript/mastodon/locales/af.json b/app/javascript/mastodon/locales/af.json index 7e842b5dd..6f7f355fc 100644 --- a/app/javascript/mastodon/locales/af.json +++ b/app/javascript/mastodon/locales/af.json @@ -14,6 +14,7 @@ "account.badges.group": "Groep", "account.block": "Blokkeer @{name}", "account.block_domain": "Blokkeer domein {domain}", + "account.block_short": "Blokkeer", "account.blocked": "Geblokkeer", "account.browse_more_on_origin_server": "Verken die oorspronklike profiel", "account.cancel_follow_request": "Herroep volgversoek", @@ -45,6 +46,7 @@ "account.posts_with_replies": "Plasings en antwoorde", "account.report": "Rapporteer @{name}", "account.requested": "Wag op goedkeuring. Klik om volgversoek te kanselleer", + "account.requested_follow": "{name} het versoek om jou te volg", "account.share": "Deel @{name} se profiel", "account.show_reblogs": "Wys aangestuurde plasings van @{name}", "account.statuses_counter": "{count, plural, one {{counter} Plaas} other {{counter} Plasings}}", @@ -82,6 +84,7 @@ "column.community": "Plaaslike tydlyn", "column.directory": "Blaai deur profiele", "column.domain_blocks": "Geblokkeerde domeine", + "column.favourites": "Gunstelinge", "column.follow_requests": "Volgversoeke", "column.home": "Tuis", "column.lists": "Lyste", @@ -271,6 +274,7 @@ "privacy.unlisted.short": "Ongelys", "privacy_policy.last_updated": "Laaste bywerking op {date}", "privacy_policy.title": "Privaatheidsbeleid", + "regeneration_indicator.sublabel": "Jou tuis-voer word voorberei!", "reply_indicator.cancel": "Kanselleer", "report.placeholder": "Type or paste additional comments", "report.submit": "Submit report", diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 7c2d652b6..e8a52ee29 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -201,7 +201,7 @@ "disabled_account_banner.text": "Ваш уліковы запіс {disabledAccount} часова адключаны.", "dismissable_banner.community_timeline": "Гэта самыя апошнія допісы ад людзей, уліковыя запісы якіх размяшчаюцца на {domain}.", "dismissable_banner.dismiss": "Адхіліць", - "dismissable_banner.explore_links": "Гэтыя навіны абмяркоўваюцца прама зараз на гэтым і іншых серверах дэцэнтралізаванай сеткі.", + "dismissable_banner.explore_links": "Гэтыя навіны абмяркоўваюцца цяпер на гэтым і іншых серверах дэцэнтралізаванай сеткі.", "dismissable_banner.explore_statuses": "Допісы з гэтага і іншых сервераў дэцэнтралізаванай сеткі, якія набіраюць папулярнасць прама зараз.", "dismissable_banner.explore_tags": "Гэтыя хэштэгі зараз набіраюць папулярнасць сярод людзей на гэтым і іншых серверах дэцэнтралізаванай сеткі", "dismissable_banner.public_timeline": "Гэта апошнія публічныя допісы людзей з усей сеткі, за якімі сочаць карыстальнікі {domain}.", @@ -482,7 +482,7 @@ "onboarding.share.lead": "Дайце людзям ведаць, як яны могуць знайсці вас на Mastodon!", "onboarding.share.message": "Я {username} на #Mastodon! Сачыце за мной на {url}", "onboarding.share.next_steps": "Магчымыя наступныя крокі:", - "onboarding.share.title": "Падзяліцеся сваім профілем", + "onboarding.share.title": "Абагульце свой профіль", "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", "onboarding.start.skip": "Want to skip right ahead?", "onboarding.start.title": "Вы зрабілі гэта!", @@ -493,7 +493,7 @@ "onboarding.steps.setup_profile.body": "Others are more likely to interact with you with a filled out profile.", "onboarding.steps.setup_profile.title": "Customize your profile", "onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!", - "onboarding.steps.share_profile.title": "Share your profile", + "onboarding.steps.share_profile.title": "Абагульць ваш профіль у Mastodon", "onboarding.tips.2fa": "<strong>Ці вы ведаеце?</strong> Вы можаце абараніць свой уліковы запіс, усталяваўшы двухфактарную аўтэнтыфікацыю ў наладах уліковага запісу. Яна працуе з любой праграмай TOTP на ваш выбар, нумар тэлефона не патрэбны!", "onboarding.tips.accounts_from_other_servers": "<strong>Ці вы ведаеце?</strong> Паколькі Mastodon дэцэнтралізаваны, некаторыя профілі, якія вам трапляюцца, будуць размяшчацца на іншых серверах, адрозных ад вашага. І ўсё ж вы можаце бесперашкодна ўзаемадзейнічаць з імі! Іх сервер пазначаны ў другой палове імя карыстальніка!", "onboarding.tips.migration": "<strong>Ці вы ведаеце?</strong> Калі вы адчуваеце, што {domain} не з'яўляецца для вас лепшым выбарам у будучыні, вы можаце перайсці на іншы сервер Mastodon, не губляючы сваіх падпісчыкаў. Вы нават можаце стварыць свой уласны сервер!", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 433b9b47b..99cae584b 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Resultats de la cerca", "emoji_button.symbols": "Símbols", "emoji_button.travel": "Viatges i llocs", + "empty_column.account_hides_collections": "Aquest usuari ha elegit no mostrar aquesta informació", "empty_column.account_suspended": "Compte suspès", "empty_column.account_timeline": "No hi ha tuts aquí!", "empty_column.account_unavailable": "Perfil no disponible", diff --git a/app/javascript/mastodon/locales/fy.json b/app/javascript/mastodon/locales/fy.json index 12365c879..9d3b41606 100644 --- a/app/javascript/mastodon/locales/fy.json +++ b/app/javascript/mastodon/locales/fy.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Sykresultaten", "emoji_button.symbols": "Symboalen", "emoji_button.travel": "Reizgje en lokaasjes", + "empty_column.account_hides_collections": "Dizze brûker hat derfoar keazen dizze ynformaasje net beskikber te meitsjen", "empty_column.account_suspended": "Account beskoattele", "empty_column.account_timeline": "Hjir binne gjin berjochten!", "empty_column.account_unavailable": "Profyl net beskikber", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 75f4a239e..5cdc575de 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -41,6 +41,8 @@ "account.languages": "Keisti prenumeruojamas kalbas", "account.locked_info": "Šios paskyros privatumo būsena nustatyta kaip užrakinta. Savininkas (-ė) rankiniu būdu peržiūri, kas gali sekti.", "account.media": "Medija", + "account.mention": "Paminėti @{name}", + "account.moved_to": "{name} nurodė, kad dabar jų nauja paskyra yra:", "account.mute": "Užtildyti @{name}", "account.muted": "Užtildytas", "account.posts": "Toots", @@ -53,10 +55,15 @@ "account.unfollow": "Nebesekti", "account.unmute_short": "Atitildyti", "account_note.placeholder": "Click to add a note", - "alert.unexpected.title": "Oi!", + "alert.unexpected.message": "Įvyko netikėta klaida.", + "alert.unexpected.title": "Ups!", "announcement.announcement": "Skelbimas", + "attachments_list.unprocessed": "(neapdorotas)", "audio.hide": "Slėpti garsą", "autosuggest_hashtag.per_week": "{count} per savaitę", + "boost_modal.combo": "Gali spausti {combo}, kad praleisti kitą kartą", + "bundle_column_error.copy_stacktrace": "Kopijuoti klaidos ataskaitą", + "bundle_column_error.error.body": "Užklausos puslapio nepavyko atvaizduoti. Tai gali būti dėl mūsų kodo klaidos arba naršyklės suderinamumo problemos.", "bundle_column_error.error.title": "O, ne!", "column.domain_blocks": "Hidden domains", "column.lists": "Sąrašai", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index 63507be79..f16a91d65 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Rezultati iskanja", "emoji_button.symbols": "Simboli", "emoji_button.travel": "Potovanja in kraji", + "empty_column.account_hides_collections": "Ta uporabnik se je odločil, da te informacije ne bo dal na voljo", "empty_column.account_suspended": "Račun je suspendiran", "empty_column.account_timeline": "Tukaj ni objav!", "empty_column.account_unavailable": "Profil ni na voljo", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index f64952f7b..aa948b1f0 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Rezultati pretrage", "emoji_button.symbols": "Simboli", "emoji_button.travel": "Putovanja i mesta", + "empty_column.account_hides_collections": "Ovaj korisnik je odlučio da ove informacije ne učini dostupnim", "empty_column.account_suspended": "Nalog je suspendovan", "empty_column.account_timeline": "Nema objava ovde!", "empty_column.account_unavailable": "Profil je nedostupan", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index ec2c76e8f..9e6716927 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Резултати претраге", "emoji_button.symbols": "Симболи", "emoji_button.travel": "Путовања и места", + "empty_column.account_hides_collections": "Овај корисник је одлучио да ове информације не учини доступним", "empty_column.account_suspended": "Налог је суспендован", "empty_column.account_timeline": "Нема објава овде!", "empty_column.account_unavailable": "Профил је недоступан", diff --git a/config/locales/activerecord.af.yml b/config/locales/activerecord.af.yml index c0810999d..91980644e 100644 --- a/config/locales/activerecord.af.yml +++ b/config/locales/activerecord.af.yml @@ -53,3 +53,7 @@ af: position: elevated: kan nie hoër as jou huidige rol wees nie own_role: kan nie verander word met jou huidige rol nie + webhook: + attributes: + events: + invalid_permissions: geleenthede waartoe jy nie toegang het nie mag nie ingesluit word nie diff --git a/config/locales/af.yml b/config/locales/af.yml index 1dbf99afe..74d349591 100644 --- a/config/locales/af.yml +++ b/config/locales/af.yml @@ -5,7 +5,23 @@ af: contact_unavailable: NVT hosted_on: Mastodon gehuisves op %{domain} title: Aangaande + accounts: + follow: Volg + followers: + one: Volgeling + other: Volgelinge + following: Volg + nothing_here: Daar is niks hier nie! + posts: + one: Plasing + other: Plasings + posts_tab_heading: Plasings admin: + account_actions: + action: Voer aksie uit + title: Voer modereer aksie uit op %{acct} + account_moderation_notes: + create: Los nota accounts: location: local: Plaaslik @@ -102,6 +118,7 @@ af: types: bookmarks: Boekmerke invites: + invalid: Hierdie uitnodiging is nie geldig nie title: Nooi ander login_activities: description_html: Indien jy onbekende aktiwiteite gewaar, oorweeg dit om jou wagwoord te verander en tweefaktorverifikasie te aktiveer. diff --git a/config/locales/be.yml b/config/locales/be.yml index 275ef7a82..96a272012 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -1418,6 +1418,7 @@ be: '86400': 1 дзень expires_in_prompt: Ніколі generate: Стварыць запрашальную спасылку + invalid: Гэта запрашэнне несапраўднае invited_by: 'Вас запрасіў(-ла):' max_uses: few: "%{count} выкарыстанні" diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 2cdf87d8f..03b3ff3c2 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -1358,6 +1358,7 @@ ca: '86400': 1 dia expires_in_prompt: Mai generate: Genera + invalid: Aquesta invitació no és vàlida invited_by: 'Has estat invitat per:' max_uses: one: 1 ús diff --git a/config/locales/cy.yml b/config/locales/cy.yml index 846ce41de..c9d5b8828 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -1468,6 +1468,7 @@ cy: '86400': 1 diwrnod expires_in_prompt: Byth generate: Cynhyrchu dolen wahoddiad + invalid: Nid yw'r gwahoddiad hwn yn ddilys invited_by: 'Cawsoch eich gwahodd gan:' max_uses: few: "%{count} defnydd" diff --git a/config/locales/da.yml b/config/locales/da.yml index c5d639185..13010e1ad 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -1110,6 +1110,7 @@ da: functional: Din konto er fuldt funktionel. pending: Din ansøgning afventer gennemgang af vores medarbejdere. Dette kan tage noget tid. Du modtager en e-mail, hvis din ansøgning godkendes. redirecting_to: Din konto er inaktiv, da den pt. er omdirigerer til %{acct}. + self_destruct: Da %{domain} er under nedlukning, vil kontoadgangen være begrænset. view_strikes: Se tidligere anmeldelser af din konto too_fast: Formularen indsendt for hurtigt, forsøg igen. use_security_key: Brug sikkerhedsnøgle @@ -1367,6 +1368,7 @@ da: '86400': 1 dag expires_in_prompt: Aldrig generate: Generér invitationslink + invalid: Denne invitation er ikke gyldig invited_by: 'Du blev inviteret af:' max_uses: one: 1 benyttelse @@ -1579,6 +1581,9 @@ da: over_daily_limit: Den daglige grænse på %{limit} planlagte indlæg er nået over_total_limit: Grænsen på %{limit} planlagte indlæg er nået too_soon: Den planlagte dato skal være i fremtiden + self_destruct: + lead_html: Desværre lukker <strong>%{domain}</strong> permanent. Har man en konto dér, vil fortsat brug heraf ikke være mulig. Man kan dog stadig anmode om en sikkerhedskopi af sine data. + title: Denne server er under nedlukning sessions: activity: Seneste aktivitet browser: Browser diff --git a/config/locales/de.yml b/config/locales/de.yml index 2ab90611f..81fa4b57f 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1368,6 +1368,7 @@ de: '86400': 1 Tag expires_in_prompt: Nie generate: Einladungslink erstellen + invalid: Diese Einladung ist ungültig invited_by: 'Du wurdest eingeladen von:' max_uses: one: Eine Verwendung diff --git a/config/locales/devise.be.yml b/config/locales/devise.be.yml index 3bf35daed..e5e8aea91 100644 --- a/config/locales/devise.be.yml +++ b/config/locales/devise.be.yml @@ -18,7 +18,7 @@ be: unconfirmed: Вы павінны пацвердзіць свой адрас электроннай пошты, перш чым працягнуць mailer: confirmation_instructions: - action: Пацвердзіце адрас электроннай пошты + action: Пацвердзіць адрас электроннай пошты action_with_app: Пацвердзіць і вярнуцца да %{app} explanation: Вы стварылі ўліковы запіс на %{host} з гэтым адрасам электроннай пошты. Вам спатрэбіцца ўсяго адзін клік, каб пацвердзіць яго. Калі гэта былі не вы, то проста праігнаруйце гэты ліст. explanation_when_pending: Вы падалі заяўку на запрашэнне на %{host} з гэтым адрасам электроннай пошты. Як толькі вы пацвердзіце свой адрас электроннай пошты, мы разгледзім вашу заяўку. Вы можаце ўвайсці, каб змяніць свае дадзеныя або выдаліць свой уліковы запіс, але вы не можаце атрымаць доступ да большасці функцый, пакуль ваш уліковы запіс не будзе зацверджаны. Калі ваша заяўка будзе адхілена, вашы даныя будуць выдалены, таму ад вас не спатрэбіцца ніякіх дадатковых дзеянняў. Калі гэта былі не вы, ігнаруйце гэты ліст diff --git a/config/locales/doorkeeper.af.yml b/config/locales/doorkeeper.af.yml index 504c7f507..9e05f403f 100644 --- a/config/locales/doorkeeper.af.yml +++ b/config/locales/doorkeeper.af.yml @@ -149,6 +149,7 @@ af: write:blocks: blokkeer rekeninge en domeine write:bookmarks: laat ’n boekmerk by plasings write:conversations: doof en wis gesprekke uit + write:favourites: gunsteling plasings write:filters: skep filters write:follows: volg mense write:lists: skep lyste diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml index 127f1262a..9175a1fc1 100644 --- a/config/locales/es-AR.yml +++ b/config/locales/es-AR.yml @@ -1368,6 +1368,7 @@ es-AR: '86400': 1 día expires_in_prompt: Nunca generate: Generar enlace de invitación + invalid: Esta invitación no es válida invited_by: 'Fuiste invitado por:' max_uses: one: 1 uso diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index ad2fb184e..75d329b0a 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -1368,6 +1368,7 @@ es-MX: '86400': 1 día expires_in_prompt: Nunca generate: Generar + invalid: Esta invitación no es válida invited_by: 'Fuiste invitado por:' max_uses: one: 1 uso diff --git a/config/locales/es.yml b/config/locales/es.yml index d071e19a1..34d1c85dc 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1368,6 +1368,7 @@ es: '86400': 1 día expires_in_prompt: Nunca generate: Generar + invalid: Esta invitación no es válida invited_by: 'Fuiste invitado por:' max_uses: one: 1 uso diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 3b7bba6ce..dd7575c57 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -1363,6 +1363,7 @@ eu: '86400': Egun 1 expires_in_prompt: Inoiz ez generate: Sortu + invalid: Gonbidapen hau ez da baliozkoa invited_by: 'Honek gonbidatu zaitu:' max_uses: one: Erabilera 1 diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 8569d2e37..04fb52e75 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -1157,6 +1157,7 @@ fa: '86400': ۱ روز expires_in_prompt: هیچ وقت generate: ساختن + invalid: این دعوتنامه معتبر نیست invited_by: 'دعوتکنندهٔ شما:' max_uses: one: ۱ بار diff --git a/config/locales/fo.yml b/config/locales/fo.yml index 8e98cc864..ffa54f588 100644 --- a/config/locales/fo.yml +++ b/config/locales/fo.yml @@ -1368,6 +1368,7 @@ fo: '86400': 1 dag expires_in_prompt: Ongantíð generate: Ger innbjóðingarleinki + invalid: Henda innbjóðing er ikki gildug invited_by: 'Tú var bjóðað/ur av:' max_uses: one: 1 brúk diff --git a/config/locales/fr-QC.yml b/config/locales/fr-QC.yml index 41b71f569..f7425ea32 100644 --- a/config/locales/fr-QC.yml +++ b/config/locales/fr-QC.yml @@ -1368,6 +1368,7 @@ fr-QC: '86400': 1 jour expires_in_prompt: Jamais generate: Générer un lien d'invitation + invalid: Cette invitation n’est pas valide invited_by: 'Vous avez été invité·e par :' max_uses: one: 1 utilisation diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 79d8b92c2..289afb226 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1368,6 +1368,7 @@ fr: '86400': 1 jour expires_in_prompt: Jamais generate: Générer un lien d'invitation + invalid: Cette invitation n’est pas valide invited_by: 'Vous avez été invité·e par :' max_uses: one: 1 utilisation diff --git a/config/locales/fy.yml b/config/locales/fy.yml index 011899d15..de609a14d 100644 --- a/config/locales/fy.yml +++ b/config/locales/fy.yml @@ -1368,6 +1368,7 @@ fy: '86400': 1 dei expires_in_prompt: Nea generate: Utnûgingskeppeling generearje + invalid: Dizze útnûging is net jildich invited_by: 'Jo binne útnûge troch:' max_uses: one: 1 kear diff --git a/config/locales/gl.yml b/config/locales/gl.yml index f86b4fc20..0075c6592 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -1368,6 +1368,7 @@ gl: '86400': 1 día expires_in_prompt: Nunca generate: Xerar + invalid: Este convite non é válido invited_by: 'Convidoute:' max_uses: one: 1 uso diff --git a/config/locales/he.yml b/config/locales/he.yml index ea2ab8f29..11e5db453 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -113,8 +113,8 @@ he: previous_strikes_description_html: many: לחשבון הזה יש <strong>%{count}</strong> פסילות. one: לחשבון הזה פסילה <strong>אחת</strong>. - other: לחשבון הזה <strong>%{count}</strong> פסילות. - two: לחשבון הזה <strong>%{count}</strong> פסילות. + other: לחשבון הזה יש <strong>%{count}</strong> פסילות. + two: לחשבון הזה יש <strong>שתי</strong> פסילות. promote: להעלות בדרגה protocol: פרטיכל public: פומבי @@ -1418,6 +1418,7 @@ he: '86400': יום אחד expires_in_prompt: לעולם לא generate: יצירת קישור להזמנה + invalid: הזמנה זו אינה תקפה invited_by: הוזמנת ע"י max_uses: many: "%{count} שימושים" diff --git a/config/locales/hu.yml b/config/locales/hu.yml index c01f38a9a..48f9d5b9d 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -1368,6 +1368,7 @@ hu: '86400': 1 nap expires_in_prompt: Soha generate: Generálás + invalid: Ez a meghívó nem érvényes invited_by: 'Téged meghívott:' max_uses: one: 1 használat diff --git a/config/locales/is.yml b/config/locales/is.yml index e0eb95569..390ce0ac0 100644 --- a/config/locales/is.yml +++ b/config/locales/is.yml @@ -1372,6 +1372,7 @@ is: '86400': 1 dagur expires_in_prompt: Aldrei generate: Útbúa boðstengil + invalid: Þetta boð er ekki gilt invited_by: 'Þér var boðið af:' max_uses: one: 1 afnot diff --git a/config/locales/it.yml b/config/locales/it.yml index e62ea620c..f35e9e42b 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -1370,6 +1370,7 @@ it: '86400': 1 giorno expires_in_prompt: Mai generate: Genera + invalid: Questo invito non è valido invited_by: 'Sei stato invitato da:' max_uses: one: un uso diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 72eafc8fb..fb193c75f 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -1345,6 +1345,7 @@ ko: '86400': 1 일 expires_in_prompt: 영원히 generate: 초대 링크 생성하기 + invalid: 이 초대는 올바르지 않습니다 invited_by: '당신을 초대한 사람:' max_uses: other: "%{count}회" diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 2f4d813c9..529eb5a44 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -383,6 +383,7 @@ lt: '86400': 1 dienos expires_in_prompt: Niekada generate: Generuoti + invalid: Šis kvietimas negalioja. invited_by: 'Jus pakvietė:' max_uses: few: "%{count} panaudojimai" diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 2a8a59d76..94a1f29f7 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1368,6 +1368,7 @@ nl: '86400': 1 dag expires_in_prompt: Nooit generate: Uitnodigingslink genereren + invalid: Deze uitnodiging is niet geldig invited_by: 'Jij bent uitgenodigd door:' max_uses: one: 1 keer diff --git a/config/locales/nn.yml b/config/locales/nn.yml index acd6b206e..4925d4463 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -1368,6 +1368,7 @@ nn: '86400': 1 dag expires_in_prompt: Aldri generate: Lag innbydingslenkje + invalid: Denne invitasjonen er ikkje gyldig invited_by: 'Du vart innboden av:' max_uses: one: 1 bruk diff --git a/config/locales/no.yml b/config/locales/no.yml index 75085fa5a..a1058bf9f 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -1368,6 +1368,7 @@ '86400': 1 dag expires_in_prompt: Aldri generate: Generer + invalid: Denne invitasjonen er ikke gyldig invited_by: 'Du ble invitert av:' max_uses: one: 1 bruk diff --git a/config/locales/pl.yml b/config/locales/pl.yml index e02cad039..608599724 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -1418,6 +1418,7 @@ pl: '86400': dobie expires_in_prompt: Nigdy generate: Wygeneruj + invalid: Niepoprawne zaproszenie invited_by: 'Zostałeś(-aś) zaproszony(-a) przez:' max_uses: few: "%{count} użycia" diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index d99c265fe..3eb2950bd 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -1368,6 +1368,7 @@ pt-BR: '86400': 1 dia expires_in_prompt: Nunca generate: Gerar convite + invalid: Este convite não é válido invited_by: 'Você recebeu convite de:' max_uses: one: 1 uso diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index a40ac02f4..ce7479aa8 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -1368,6 +1368,7 @@ pt-PT: '86400': 1 dia expires_in_prompt: Nunca generate: Gerar hiperligação de convite + invalid: Este convite não é válido invited_by: 'Foi convidado por:' max_uses: one: 1 uso diff --git a/config/locales/simple_form.be.yml b/config/locales/simple_form.be.yml index 1ed6c8084..7ad87cdd9 100644 --- a/config/locales/simple_form.be.yml +++ b/config/locales/simple_form.be.yml @@ -53,7 +53,7 @@ be: password: Не менш за 8 сімвалаў phrase: Параўнанне адбудзецца нягледзячы на рэгістр тэксту і папярэджанні аб змесціве допісу scopes: Якімі API праграм будзе дазволена карыстацца. Калі вы абярэце найвышэйшы ўзровень, не трэба абіраць асобныя. - setting_aggregate_reblogs: Не паказваць новыя пашырэнні для допісаў, якія нядаўна пашырылі(уплывае выключна на будучыя пашырэнні) + setting_aggregate_reblogs: Не паказваць новыя пашырэнні для допісаў, якія пашырылі нядаўна (закранае толькі нядаўнія пашырэнні) setting_always_send_emails: Звычайна лісты з апавяшчэннямі не будуць дасылацца, калі вы актыўна карыстаецеся Mastodon setting_default_sensitive: Далікатныя медыя прадвызначана схаваныя. Іх можна адкрыць адзіным клікам setting_display_media_default: Хаваць медыя пазначаныя як далікатныя diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 954ef745d..63779e5bd 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -592,6 +592,8 @@ sk: title: Ohľadom appearance: title: Vzhľad + content_retention: + title: Ponechanie obsahu discovery: follow_recommendations: Odporúčania pre nasledovanie profile_directory: Katalóg profilov @@ -616,6 +618,7 @@ sk: delete: Vymaž nahratý súbor destroyed_msg: Nahratie bolo zo stránky úspešne vymazané! software_updates: + critical_update: Kritické — prosím aktualizuj rýchlo documentation_link: Zisti viac title: Dostupné aktualizácie types: @@ -646,6 +649,10 @@ sk: appeal_approved: Namietnuté appeal_rejected: Námietka zamietnutá system_checks: + elasticsearch_preset: + action: Pozri dokumentáciu + elasticsearch_preset_single_node: + action: Pozri dokumentáciu rules_check: action: Spravuj serverové pravidlá message_html: Neurčil/a si žiadne serverové pravidlá. @@ -925,6 +932,7 @@ sk: '86400': 1 deň expires_in_prompt: Nikdy generate: Vygeneruj + invalid: Táto pozvánka je neplatná invited_by: 'Bol/a si pozvaný/á užívateľom:' max_uses: few: "%{count} využití" diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 77ddfd6e2..b31fe118a 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -1418,6 +1418,7 @@ sl: '86400': 1 dan expires_in_prompt: Nikoli generate: Ustvari + invalid: To povabilo ni veljavno invited_by: 'Povabil/a vas je:' max_uses: few: "%{count} uporabe" diff --git a/config/locales/sq.yml b/config/locales/sq.yml index e4fb811ce..bd01a8089 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -1362,6 +1362,7 @@ sq: '86400': 1 ditë expires_in_prompt: Kurrë generate: Prodho lidhje ftese + invalid: Kjo ftesë s’është e vlefshme invited_by: 'Qetë ftuar nga:' max_uses: one: 1 përdorim diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index cba4354f0..6ccec7fd9 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -1393,6 +1393,7 @@ sr-Latn: '86400': 1 dan expires_in_prompt: Nikad generate: Generiši + invalid: Ova pozivnica nije važeća invited_by: 'Pozvao Vas je:' max_uses: few: "%{count} korišćenja" diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 902f13ad6..407908517 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -1393,6 +1393,7 @@ sr: '86400': 1 дан expires_in_prompt: Никад generate: Генериши + invalid: Ова позивница није важећа invited_by: 'Позвао Вас је:' max_uses: few: "%{count} коришћења" diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 736d839f9..8126455f4 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -1368,6 +1368,7 @@ sv: '86400': 1 dag expires_in_prompt: Aldrig generate: Skapa + invalid: Ogiltig inbjudan invited_by: 'Du blev inbjuden av:' max_uses: one: 1 användning diff --git a/config/locales/th.yml b/config/locales/th.yml index 33d8a898e..661899896 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -1343,6 +1343,7 @@ th: '86400': 1 วัน expires_in_prompt: ไม่เลย generate: สร้างลิงก์เชิญ + invalid: คำเชิญนี้ไม่ถูกต้อง invited_by: 'คุณได้รับเชิญโดย:' max_uses: other: "%{count} การใช้งาน" diff --git a/config/locales/tr.yml b/config/locales/tr.yml index c9adfd913..9d4d95a83 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -1368,6 +1368,7 @@ tr: '86400': 1 gün expires_in_prompt: Asla generate: Davet bağlantısı oluştur + invalid: Bu davet geçerli değil invited_by: 'Davet edildiniz:' max_uses: one: 1 kullanım diff --git a/config/locales/uk.yml b/config/locales/uk.yml index eb947a7d0..2261c647b 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -1418,6 +1418,7 @@ uk: '86400': 1 день expires_in_prompt: Ніколи generate: Згенерувати + invalid: Це запрошення не дійсне invited_by: 'Вас запросив:' max_uses: few: "%{count} використання" diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 7902cea4d..b98193065 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -1343,6 +1343,7 @@ zh-CN: '86400': 1 天后 expires_in_prompt: 永不过期 generate: 生成邀请链接 + invalid: 此邀请无效 invited_by: 你的邀请人是: max_uses: other: "%{count} 次" diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml index 58aeac841..f13cedad6 100644 --- a/config/locales/zh-HK.yml +++ b/config/locales/zh-HK.yml @@ -1343,6 +1343,7 @@ zh-HK: '86400': 1 天後 expires_in_prompt: 永不過期 generate: 生成邀請連結 + invalid: 此邀請無效 invited_by: 你的邀請人是: max_uses: other: "%{count} 次" diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 7bcc13396..3063b7afd 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -1345,6 +1345,7 @@ zh-TW: '86400': 1 天後 expires_in_prompt: 永不過期 generate: 建立邀請連結 + invalid: 此邀請是無效的 invited_by: 您的邀請人是: max_uses: other: "%{count} 則" From 4eb4e8b22c564222d8bc69cca754cbfb9a524611 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:07:13 +0100 Subject: [PATCH 028/255] Update Yarn to v4.0.2 (#27851) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2230b20ea..7c73d17c1 100644 --- a/package.json +++ b/package.json @@ -242,5 +242,5 @@ "*.{js,jsx,ts,tsx}": "eslint --fix", "*.{css,scss}": "stylelint --fix" }, - "packageManager": "yarn@4.0.1" + "packageManager": "yarn@4.0.2" } From d562fb84596f7cf2380e7c1cc465e1d4d478d759 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 14 Nov 2023 09:34:30 -0500 Subject: [PATCH 029/255] Specs for minimal CSP policy in `Api::` controllers (#27845) --- app/controllers/api/base_controller.rb | 21 +-------- .../concerns/api/content_security_policy.rb | 27 ++++++++++++ spec/requests/api/v1/csp_spec.rb | 43 +++++++++++++++++++ 3 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 app/controllers/concerns/api/content_security_policy.rb create mode 100644 spec/requests/api/v1/csp_spec.rb diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index c764b4510..135c57565 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -7,6 +7,7 @@ class Api::BaseController < ApplicationController include RateLimitHeaders include AccessTokenTrackingConcern include ApiCachingConcern + include Api::ContentSecurityPolicy skip_before_action :require_functional!, unless: :limited_federation_mode? @@ -17,26 +18,6 @@ class Api::BaseController < ApplicationController protect_from_forgery with: :null_session - content_security_policy do |p| - # Set every directive that does not have a fallback - p.default_src :none - p.frame_ancestors :none - p.form_action :none - - # Disable every directive with a fallback to cut on response size - p.base_uri false - p.font_src false - p.img_src false - p.style_src false - p.media_src false - p.frame_src false - p.manifest_src false - p.connect_src false - p.script_src false - p.child_src false - p.worker_src false - end - rescue_from ActiveRecord::RecordInvalid, Mastodon::ValidationError do |e| render json: { error: e.to_s }, status: 422 end diff --git a/app/controllers/concerns/api/content_security_policy.rb b/app/controllers/concerns/api/content_security_policy.rb new file mode 100644 index 000000000..8116dca57 --- /dev/null +++ b/app/controllers/concerns/api/content_security_policy.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Api::ContentSecurityPolicy + extend ActiveSupport::Concern + + included do + content_security_policy do |policy| + # Set every directive that does not have a fallback + policy.default_src :none + policy.frame_ancestors :none + policy.form_action :none + + # Disable every directive with a fallback to cut on response size + policy.base_uri false + policy.font_src false + policy.img_src false + policy.style_src false + policy.media_src false + policy.frame_src false + policy.manifest_src false + policy.connect_src false + policy.script_src false + policy.child_src false + policy.worker_src false + end + end +end diff --git a/spec/requests/api/v1/csp_spec.rb b/spec/requests/api/v1/csp_spec.rb new file mode 100644 index 000000000..2db52ac72 --- /dev/null +++ b/spec/requests/api/v1/csp_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'API namespace minimal Content-Security-Policy' do + before { stub_tests_controller } + + after { Rails.application.reload_routes! } + + it 'returns the correct CSP headers' do + get '/api/v1/tests' + + expect(response).to have_http_status(200) + expect(response.headers['Content-Security-Policy']).to eq(minimal_csp_headers) + end + + private + + def stub_tests_controller + stub_const('Api::V1::TestsController', api_tests_controller) + + Rails.application.routes.draw do + get '/api/v1/tests', to: 'api/v1/tests#index' + end + end + + def api_tests_controller + Class.new(Api::BaseController) do + def index + head 200 + end + + private + + def user_signed_in? = false + def current_user = nil + end + end + + def minimal_csp_headers + "default-src 'none'; frame-ancestors 'none'; form-action 'none'" + end +end From b2c5b20ef27edd948eca8d6bd2014b7a5efaec11 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 14 Nov 2023 09:52:59 -0500 Subject: [PATCH 030/255] Fix `RSpec/AnyInstance` cop (#27810) --- .rubocop_todo.yml | 17 ---------- .../activitypub/inboxes_controller_spec.rb | 2 +- .../admin/accounts_controller_spec.rb | 3 +- .../admin/resets_controller_spec.rb | 18 ++++++++--- .../auth/sessions_controller_spec.rb | 6 ++-- .../confirmations_controller_spec.rb | 31 +++++++++---------- .../recovery_codes_controller_spec.rb | 6 ++-- spec/lib/request_spec.rb | 5 ++- spec/lib/status_filter_spec.rb | 6 ++-- spec/models/account_spec.rb | 14 +++++++-- spec/models/setting_spec.rb | 6 ++-- .../process_collection_service_spec.rb | 9 ++++-- .../activitypub/delivery_worker_spec.rb | 3 +- .../web/push_notification_worker_spec.rb | 4 +-- 14 files changed, 70 insertions(+), 60 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index f9d14fd55..167204604 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -41,23 +41,6 @@ Metrics/CyclomaticComplexity: Metrics/PerceivedComplexity: Max: 27 -RSpec/AnyInstance: - Exclude: - - 'spec/controllers/activitypub/inboxes_controller_spec.rb' - - 'spec/controllers/admin/accounts_controller_spec.rb' - - 'spec/controllers/admin/resets_controller_spec.rb' - - 'spec/controllers/auth/sessions_controller_spec.rb' - - 'spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb' - - 'spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb' - - 'spec/lib/request_spec.rb' - - 'spec/lib/status_filter_spec.rb' - - 'spec/models/account_spec.rb' - - 'spec/models/setting_spec.rb' - - 'spec/services/activitypub/process_collection_service_spec.rb' - - 'spec/validators/follow_limit_validator_spec.rb' - - 'spec/workers/activitypub/delivery_worker_spec.rb' - - 'spec/workers/web/push_notification_worker_spec.rb' - # Configuration parameters: CountAsOne. RSpec/ExampleLength: Max: 22 diff --git a/spec/controllers/activitypub/inboxes_controller_spec.rb b/spec/controllers/activitypub/inboxes_controller_spec.rb index 030a30326..feca543cb 100644 --- a/spec/controllers/activitypub/inboxes_controller_spec.rb +++ b/spec/controllers/activitypub/inboxes_controller_spec.rb @@ -58,7 +58,7 @@ RSpec.describe ActivityPub::InboxesController do before do allow(ActivityPub::FollowersSynchronizationWorker).to receive(:perform_async).and_return(nil) - allow_any_instance_of(Account).to receive(:local_followers_hash).and_return('somehash') + allow(remote_account).to receive(:local_followers_hash).and_return('somehash') request.headers['Collection-Synchronization'] = synchronization_header post :create, body: '{}' diff --git a/spec/controllers/admin/accounts_controller_spec.rb b/spec/controllers/admin/accounts_controller_spec.rb index 3b8fa2f71..307e81950 100644 --- a/spec/controllers/admin/accounts_controller_spec.rb +++ b/spec/controllers/admin/accounts_controller_spec.rb @@ -227,7 +227,8 @@ RSpec.describe Admin::AccountsController do let(:account) { Fabricate(:account, domain: 'example.com') } before do - allow_any_instance_of(ResolveAccountService).to receive(:call) + service = instance_double(ResolveAccountService, call: nil) + allow(ResolveAccountService).to receive(:new).and_return(service) end context 'when user is admin' do diff --git a/spec/controllers/admin/resets_controller_spec.rb b/spec/controllers/admin/resets_controller_spec.rb index 16adb8a12..14826973c 100644 --- a/spec/controllers/admin/resets_controller_spec.rb +++ b/spec/controllers/admin/resets_controller_spec.rb @@ -13,12 +13,20 @@ describe Admin::ResetsController do describe 'POST #create' do it 'redirects to admin accounts page' do - expect_any_instance_of(User).to receive(:send_reset_password_instructions) do |value| - expect(value.account_id).to eq account.id - end - - post :create, params: { account_id: account.id } + expect do + post :create, params: { account_id: account.id } + end.to change(Devise.mailer.deliveries, :size).by(2) + expect(Devise.mailer.deliveries).to have_attributes( + first: have_attributes( + to: include(account.user.email), + subject: I18n.t('devise.mailer.password_change.subject') + ), + last: have_attributes( + to: include(account.user.email), + subject: I18n.t('devise.mailer.reset_password_instructions.subject') + ) + ) expect(response).to redirect_to(admin_account_path(account.id)) end end diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb index 049190e2e..f341d75b7 100644 --- a/spec/controllers/auth/sessions_controller_spec.rb +++ b/spec/controllers/auth/sessions_controller_spec.rb @@ -126,7 +126,7 @@ RSpec.describe Auth::SessionsController do let!(:previous_login) { Fabricate(:login_activity, user: user, ip: previous_ip) } before do - allow_any_instance_of(ActionDispatch::Request).to receive(:remote_ip).and_return(current_ip) + allow(controller.request).to receive(:remote_ip).and_return(current_ip) user.update(current_sign_in_at: 1.month.ago) post :create, params: { user: { email: user.email, password: user.password } } end @@ -279,7 +279,9 @@ RSpec.describe Auth::SessionsController do context 'when the server has an decryption error' do before do - allow_any_instance_of(User).to receive(:validate_and_consume_otp!).and_raise(OpenSSL::Cipher::CipherError) + allow(user).to receive(:validate_and_consume_otp!).with(user.current_otp).and_raise(OpenSSL::Cipher::CipherError) + allow(User).to receive(:find_by).with(id: user.id).and_return(user) + post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } end diff --git a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb index 37381fe1f..a5a35e91d 100644 --- a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb +++ b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb @@ -61,6 +61,7 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do it 'renders page with success' do prepare_user_otp_generation prepare_user_otp_consumption + allow(controller).to receive(:current_user).and_return(user) expect do post :create, @@ -75,30 +76,28 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do end def prepare_user_otp_generation - expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value| - expect(value).to eq user - otp_backup_codes - end + allow(user) + .to receive(:generate_otp_backup_codes!) + .and_return(otp_backup_codes) end def prepare_user_otp_consumption - expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, code, options| - expect(value).to eq user - expect(code).to eq '123456' - expect(options).to eq({ otp_secret: 'thisisasecretforthespecofnewview' }) - true - end + options = { otp_secret: 'thisisasecretforthespecofnewview' } + allow(user) + .to receive(:validate_and_consume_otp!) + .with('123456', options) + .and_return(true) end end describe 'when creation fails' do subject do - expect_any_instance_of(User).to receive(:validate_and_consume_otp!) do |value, code, options| - expect(value).to eq user - expect(code).to eq '123456' - expect(options).to eq({ otp_secret: 'thisisasecretforthespecofnewview' }) - false - end + options = { otp_secret: 'thisisasecretforthespecofnewview' } + allow(user) + .to receive(:validate_and_consume_otp!) + .with('123456', options) + .and_return(false) + allow(controller).to receive(:current_user).and_return(user) expect do post :create, diff --git a/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb index 630cec428..28a40e138 100644 --- a/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb +++ b/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb @@ -9,10 +9,8 @@ describe Settings::TwoFactorAuthentication::RecoveryCodesController do it 'updates the codes and shows them on a view when signed in' do user = Fabricate(:user) otp_backup_codes = user.generate_otp_backup_codes! - expect_any_instance_of(User).to receive(:generate_otp_backup_codes!) do |value| - expect(value).to eq user - otp_backup_codes - end + allow(user).to receive(:generate_otp_backup_codes!).and_return(otp_backup_codes) + allow(controller).to receive(:current_user).and_return(user) sign_in user, scope: :user post :create, session: { challenge_passed_at: Time.now.utc } diff --git a/spec/lib/request_spec.rb b/spec/lib/request_spec.rb index f0861376b..c7620cf9b 100644 --- a/spec/lib/request_spec.rb +++ b/spec/lib/request_spec.rb @@ -64,8 +64,11 @@ describe Request do end it 'closes underlying connection' do - expect_any_instance_of(HTTP::Client).to receive(:close) + allow(subject.send(:http_client)).to receive(:close) + expect { |block| subject.perform(&block) }.to yield_control + + expect(subject.send(:http_client)).to have_received(:close) end it 'returns response which implements body_with_limit' do diff --git a/spec/lib/status_filter_spec.rb b/spec/lib/status_filter_spec.rb index c994ad419..cf6f3c795 100644 --- a/spec/lib/status_filter_spec.rb +++ b/spec/lib/status_filter_spec.rb @@ -23,7 +23,8 @@ describe StatusFilter do context 'when status policy does not allow show' do it 'filters the status' do - allow_any_instance_of(StatusPolicy).to receive(:show?).and_return(false) + policy = instance_double(StatusPolicy, show?: false) + allow(StatusPolicy).to receive(:new).and_return(policy) expect(filter).to be_filtered end @@ -74,7 +75,8 @@ describe StatusFilter do context 'when status policy does not allow show' do it 'filters the status' do - allow_any_instance_of(StatusPolicy).to receive(:show?).and_return(false) + policy = instance_double(StatusPolicy, show?: false) + allow(StatusPolicy).to receive(:new).and_return(policy) expect(filter).to be_filtered end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index b5d942412..f77ecb055 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -209,9 +209,13 @@ RSpec.describe Account do expect(account.refresh!).to be_nil end - it 'calls not ResolveAccountService#call' do - expect_any_instance_of(ResolveAccountService).to_not receive(:call).with(acct) + it 'does not call ResolveAccountService#call' do + service = instance_double(ResolveAccountService, call: nil) + allow(ResolveAccountService).to receive(:new).and_return(service) + account.refresh! + + expect(service).to_not have_received(:call).with(acct) end end @@ -219,8 +223,12 @@ RSpec.describe Account do let(:domain) { 'example.com' } it 'calls ResolveAccountService#call' do - expect_any_instance_of(ResolveAccountService).to receive(:call).with(acct).once + service = instance_double(ResolveAccountService, call: nil) + allow(ResolveAccountService).to receive(:new).and_return(service) + account.refresh! + + expect(service).to have_received(:call).with(acct).once end end end diff --git a/spec/models/setting_spec.rb b/spec/models/setting_spec.rb index b08136a1c..e98062810 100644 --- a/spec/models/setting_spec.rb +++ b/spec/models/setting_spec.rb @@ -52,7 +52,8 @@ RSpec.describe Setting do before do allow(RailsSettings::Settings).to receive(:object).with(key).and_return(object) allow(described_class).to receive(:default_settings).and_return(default_settings) - allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records) + settings_double = instance_double(Settings::ScopedSettings, thing_scoped: records) + allow(Settings::ScopedSettings).to receive(:new).and_return(settings_double) Rails.cache.delete(cache_key) end @@ -128,7 +129,8 @@ RSpec.describe Setting do describe '.all_as_records' do before do - allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records) + settings_double = instance_double(Settings::ScopedSettings, thing_scoped: records) + allow(Settings::ScopedSettings).to receive(:new).and_return(settings_double) allow(described_class).to receive(:default_settings).and_return(default_settings) end diff --git a/spec/services/activitypub/process_collection_service_spec.rb b/spec/services/activitypub/process_collection_service_spec.rb index ede9f5c04..df526daf3 100644 --- a/spec/services/activitypub/process_collection_service_spec.rb +++ b/spec/services/activitypub/process_collection_service_spec.rb @@ -76,7 +76,8 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do let(:forwarder) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/other_account') } it 'does not process payload if no signature exists' do - allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil) + signature_double = instance_double(ActivityPub::LinkedDataSignature, verify_actor!: nil) + allow(ActivityPub::LinkedDataSignature).to receive(:new).and_return(signature_double) allow(ActivityPub::Activity).to receive(:factory) subject.call(json, forwarder) @@ -87,7 +88,8 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do it 'processes payload with actor if valid signature exists' do payload['signature'] = { 'type' => 'RsaSignature2017' } - allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(actor) + signature_double = instance_double(ActivityPub::LinkedDataSignature, verify_actor!: actor) + allow(ActivityPub::LinkedDataSignature).to receive(:new).and_return(signature_double) allow(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), actor, instance_of(Hash)) subject.call(json, forwarder) @@ -98,7 +100,8 @@ RSpec.describe ActivityPub::ProcessCollectionService, type: :service do it 'does not process payload if invalid signature exists' do payload['signature'] = { 'type' => 'RsaSignature2017' } - allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil) + signature_double = instance_double(ActivityPub::LinkedDataSignature, verify_actor!: nil) + allow(ActivityPub::LinkedDataSignature).to receive(:new).and_return(signature_double) allow(ActivityPub::Activity).to receive(:factory) subject.call(json, forwarder) diff --git a/spec/workers/activitypub/delivery_worker_spec.rb b/spec/workers/activitypub/delivery_worker_spec.rb index d39393d50..efce610ae 100644 --- a/spec/workers/activitypub/delivery_worker_spec.rb +++ b/spec/workers/activitypub/delivery_worker_spec.rb @@ -11,7 +11,8 @@ describe ActivityPub::DeliveryWorker do let(:payload) { 'test' } before do - allow_any_instance_of(Account).to receive(:remote_followers_hash).with('https://example.com/api').and_return('somehash') + allow(sender).to receive(:remote_followers_hash).with('https://example.com/api').and_return('somehash') + allow(Account).to receive(:find).with(sender.id).and_return(sender) end describe 'perform' do diff --git a/spec/workers/web/push_notification_worker_spec.rb b/spec/workers/web/push_notification_worker_spec.rb index 822ef5257..637206a40 100644 --- a/spec/workers/web/push_notification_worker_spec.rb +++ b/spec/workers/web/push_notification_worker_spec.rb @@ -23,8 +23,8 @@ describe Web::PushNotificationWorker do describe 'perform' do before do - allow_any_instance_of(subscription.class).to receive(:contact_email).and_return(contact_email) - allow_any_instance_of(subscription.class).to receive(:vapid_key).and_return(vapid_key) + allow(subscription).to receive_messages(contact_email: contact_email, vapid_key: vapid_key) + allow(Web::PushSubscription).to receive(:find).with(subscription.id).and_return(subscription) allow(Webpush::Encryption).to receive(:encrypt).and_return(payload) allow(JWT).to receive(:encode).and_return('jwt.encoded.payload') From 7e1a77ea51e6dc4aecbf678f8928aa96698fa072 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 14 Nov 2023 09:53:31 -0500 Subject: [PATCH 031/255] Add base class for `api/v1/timelines/*` controllers (#27840) --- .../api/v1/timelines/base_controller.rb | 33 +++++++++++++++++++ .../api/v1/timelines/home_controller.rb | 25 +++----------- .../api/v1/timelines/list_controller.rb | 24 +++----------- .../api/v1/timelines/public_controller.rb | 25 +++----------- .../api/v1/timelines/tag_controller.rb | 25 +++----------- 5 files changed, 52 insertions(+), 80 deletions(-) create mode 100644 app/controllers/api/v1/timelines/base_controller.rb diff --git a/app/controllers/api/v1/timelines/base_controller.rb b/app/controllers/api/v1/timelines/base_controller.rb new file mode 100644 index 000000000..173e173cc --- /dev/null +++ b/app/controllers/api/v1/timelines/base_controller.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +class Api::V1::Timelines::BaseController < Api::BaseController + after_action :insert_pagination_headers, unless: -> { @statuses.empty? } + + private + + def insert_pagination_headers + set_pagination_headers(next_path, prev_path) + end + + def pagination_max_id + @statuses.last.id + end + + def pagination_since_id + @statuses.first.id + end + + def next_path_params + permitted_params.merge(max_id: pagination_max_id) + end + + def prev_path_params + permitted_params.merge(min_id: pagination_since_id) + end + + def permitted_params + params + .slice(*self.class::PERMITTED_PARAMS) + .permit(*self.class::PERMITTED_PARAMS) + end +end diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb index 83b8cb4c6..36fdbea64 100644 --- a/app/controllers/api/v1/timelines/home_controller.rb +++ b/app/controllers/api/v1/timelines/home_controller.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true -class Api::V1::Timelines::HomeController < Api::BaseController +class Api::V1::Timelines::HomeController < Api::V1::Timelines::BaseController before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: [:show] before_action :require_user!, only: [:show] - after_action :insert_pagination_headers, unless: -> { @statuses.empty? } + + PERMITTED_PARAMS = %i(local limit).freeze def show with_read_replica do @@ -40,27 +41,11 @@ class Api::V1::Timelines::HomeController < Api::BaseController HomeFeed.new(current_account) end - def insert_pagination_headers - set_pagination_headers(next_path, prev_path) - end - - def pagination_params(core_params) - params.slice(:local, :limit).permit(:local, :limit).merge(core_params) - end - def next_path - api_v1_timelines_home_url pagination_params(max_id: pagination_max_id) + api_v1_timelines_home_url next_path_params end def prev_path - api_v1_timelines_home_url pagination_params(min_id: pagination_since_id) - end - - def pagination_max_id - @statuses.last.id - end - - def pagination_since_id - @statuses.first.id + api_v1_timelines_home_url prev_path_params end end diff --git a/app/controllers/api/v1/timelines/list_controller.rb b/app/controllers/api/v1/timelines/list_controller.rb index a15eae468..14b884ecd 100644 --- a/app/controllers/api/v1/timelines/list_controller.rb +++ b/app/controllers/api/v1/timelines/list_controller.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true -class Api::V1::Timelines::ListController < Api::BaseController +class Api::V1::Timelines::ListController < Api::V1::Timelines::BaseController before_action -> { doorkeeper_authorize! :read, :'read:lists' } before_action :require_user! before_action :set_list before_action :set_statuses - after_action :insert_pagination_headers, unless: -> { @statuses.empty? } + PERMITTED_PARAMS = %i(limit).freeze def show render json: @statuses, @@ -41,27 +41,11 @@ class Api::V1::Timelines::ListController < Api::BaseController ListFeed.new(@list) end - def insert_pagination_headers - set_pagination_headers(next_path, prev_path) - end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end - def next_path - api_v1_timelines_list_url params[:id], pagination_params(max_id: pagination_max_id) + api_v1_timelines_list_url params[:id], next_path_params end def prev_path - api_v1_timelines_list_url params[:id], pagination_params(min_id: pagination_since_id) - end - - def pagination_max_id - @statuses.last.id - end - - def pagination_since_id - @statuses.first.id + api_v1_timelines_list_url params[:id], prev_path_params end end diff --git a/app/controllers/api/v1/timelines/public_controller.rb b/app/controllers/api/v1/timelines/public_controller.rb index 5bbd92b9e..35af8dc4b 100644 --- a/app/controllers/api/v1/timelines/public_controller.rb +++ b/app/controllers/api/v1/timelines/public_controller.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true -class Api::V1::Timelines::PublicController < Api::BaseController +class Api::V1::Timelines::PublicController < Api::V1::Timelines::BaseController before_action :require_user!, only: [:show], if: :require_auth? - after_action :insert_pagination_headers, unless: -> { @statuses.empty? } + + PERMITTED_PARAMS = %i(local remote limit only_media).freeze def show cache_if_unauthenticated! @@ -42,27 +43,11 @@ class Api::V1::Timelines::PublicController < Api::BaseController ) end - def insert_pagination_headers - set_pagination_headers(next_path, prev_path) - end - - def pagination_params(core_params) - params.slice(:local, :remote, :limit, :only_media).permit(:local, :remote, :limit, :only_media).merge(core_params) - end - def next_path - api_v1_timelines_public_url pagination_params(max_id: pagination_max_id) + api_v1_timelines_public_url next_path_params end def prev_path - api_v1_timelines_public_url pagination_params(min_id: pagination_since_id) - end - - def pagination_max_id - @statuses.last.id - end - - def pagination_since_id - @statuses.first.id + api_v1_timelines_public_url prev_path_params end end diff --git a/app/controllers/api/v1/timelines/tag_controller.rb b/app/controllers/api/v1/timelines/tag_controller.rb index a79d65c12..4ba439dbb 100644 --- a/app/controllers/api/v1/timelines/tag_controller.rb +++ b/app/controllers/api/v1/timelines/tag_controller.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true -class Api::V1::Timelines::TagController < Api::BaseController +class Api::V1::Timelines::TagController < Api::V1::Timelines::BaseController before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: :show, if: :require_auth? before_action :load_tag - after_action :insert_pagination_headers, unless: -> { @statuses.empty? } + + PERMITTED_PARAMS = %i(local limit only_media).freeze def show cache_if_unauthenticated! @@ -51,27 +52,11 @@ class Api::V1::Timelines::TagController < Api::BaseController ) end - def insert_pagination_headers - set_pagination_headers(next_path, prev_path) - end - - def pagination_params(core_params) - params.slice(:local, :limit, :only_media).permit(:local, :limit, :only_media).merge(core_params) - end - def next_path - api_v1_timelines_tag_url params[:id], pagination_params(max_id: pagination_max_id) + api_v1_timelines_tag_url params[:id], next_path_params end def prev_path - api_v1_timelines_tag_url params[:id], pagination_params(min_id: pagination_since_id) - end - - def pagination_max_id - @statuses.last.id - end - - def pagination_since_id - @statuses.first.id + api_v1_timelines_tag_url params[:id], prev_path_params end end From 2b038b4f8951845bee470e18ffb11fab29aacb51 Mon Sep 17 00:00:00 2001 From: ppnplus <54897463+ppnplus@users.noreply.github.com> Date: Tue, 14 Nov 2023 22:33:59 +0700 Subject: [PATCH 032/255] Added Thai diacritics and tone marks in HASHTAG_INVALID_CHARS_RE (#26576) --- app/models/tag.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/tag.rb b/app/models/tag.rb index 8fab98fb5..46e55d74f 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -37,7 +37,7 @@ class Tag < ApplicationRecord HASHTAG_RE = %r{(?<![=/)\w])#(#{HASHTAG_NAME_PAT})}i HASHTAG_NAME_RE = /\A(#{HASHTAG_NAME_PAT})\z/i - HASHTAG_INVALID_CHARS_RE = /[^[:alnum:]#{HASHTAG_SEPARATORS}]/ + HASHTAG_INVALID_CHARS_RE = /[^[:alnum:]\u0E47-\u0E4E#{HASHTAG_SEPARATORS}]/ validates :name, presence: true, format: { with: HASHTAG_NAME_RE } validates :display_name, format: { with: HASHTAG_NAME_RE } From 35b9749b95fc8f61631a8b38f9dad37ec5f36a7a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 17:53:15 +0100 Subject: [PATCH 033/255] Update dependency webpack-bundle-analyzer to v4.10.0 (#27852) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 58 +++++++++++++------------------------------------------ 1 file changed, 13 insertions(+), 45 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1cb5a42d5..addbe638f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6430,6 +6430,13 @@ __metadata: languageName: node linkType: hard +"debounce@npm:^1.2.1": + version: 1.2.1 + resolution: "debounce@npm:1.2.1" + checksum: 6c9320aa0973fc42050814621a7a8a78146c1975799b5b3cc1becf1f77ba9a5aa583987884230da0842a03f385def452fad5d60db97c3d1c8b824e38a8edf500 + languageName: node + linkType: hard + "debug@npm:2.6.9, debug@npm:^2.2.0, debug@npm:^2.3.3": version: 2.6.9 resolution: "debug@npm:2.6.9" @@ -8903,7 +8910,7 @@ __metadata: languageName: node linkType: hard -"html-escaper@npm:^2.0.0": +"html-escaper@npm:^2.0.0, html-escaper@npm:^2.0.2": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" checksum: 208e8a12de1a6569edbb14544f4567e6ce8ecc30b9394fcaa4e7bb1e60c12a7c9a1ed27e31290817157e8626f3a4f29e76c8747030822eb84a6abb15c255f0a0 @@ -11032,20 +11039,6 @@ __metadata: languageName: node linkType: hard -"lodash.escape@npm:^4.0.1": - version: 4.0.1 - resolution: "lodash.escape@npm:4.0.1" - checksum: 90ade409cec05b6869090476952fdfb84d4d87b1ff4a0e03ebd590f980d9a1248d93ba14579f10d80c6429e4d6af13ba137c28db64cae6dadb71442e54a3ad2b - languageName: node - linkType: hard - -"lodash.flatten@npm:^4.4.0": - version: 4.4.0 - resolution: "lodash.flatten@npm:4.4.0" - checksum: 97e8f0d6b61fe4723c02ad0c6e67e51784c4a2c48f56ef283483e556ad01594cf9cec9c773e177bbbdbdb5d19e99b09d2487cb6b6e5dc405c2693e93b125bd3a - languageName: node - linkType: hard - "lodash.get@npm:^4.0": version: 4.4.2 resolution: "lodash.get@npm:4.4.2" @@ -11060,13 +11053,6 @@ __metadata: languageName: node linkType: hard -"lodash.invokemap@npm:^4.6.0": - version: 4.6.0 - resolution: "lodash.invokemap@npm:4.6.0" - checksum: 2bcc5f4b8782a316d55ff139215eb797f576f0f6d3db2755ebba7b35fd6061f8cbe81702a72a30bc6d70073a5dcc461f7570eaddcc9184c2e42ec3023645c6a1 - languageName: node - linkType: hard - "lodash.isarguments@npm:^3.1.0": version: 3.1.0 resolution: "lodash.isarguments@npm:3.1.0" @@ -11109,13 +11095,6 @@ __metadata: languageName: node linkType: hard -"lodash.pullall@npm:^4.2.0": - version: 4.2.0 - resolution: "lodash.pullall@npm:4.2.0" - checksum: b129e8d879258c7db04a7dc1c23dd9e37c52f63a04e105faa8d2ab55e97b5a170d5e15cffbb732a36e7f48c4345c07b6fbddfe50e1f5ec301492b6f64a92040c - languageName: node - linkType: hard - "lodash.sortby@npm:^4.7.0": version: 4.7.0 resolution: "lodash.sortby@npm:4.7.0" @@ -11137,13 +11116,6 @@ __metadata: languageName: node linkType: hard -"lodash.uniqby@npm:^4.7.0": - version: 4.7.0 - resolution: "lodash.uniqby@npm:4.7.0" - checksum: c505c0de20ca759599a2ba38710e8fb95ff2d2028e24d86c901ef2c74be8056518571b9b754bfb75053b2818d30dd02243e4a4621a6940c206bbb3f7626db656 - languageName: node - linkType: hard - "lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.20, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" @@ -17035,29 +17007,25 @@ __metadata: linkType: hard "webpack-bundle-analyzer@npm:^4.8.0": - version: 4.9.1 - resolution: "webpack-bundle-analyzer@npm:4.9.1" + version: 4.10.0 + resolution: "webpack-bundle-analyzer@npm:4.10.0" dependencies: "@discoveryjs/json-ext": "npm:0.5.7" acorn: "npm:^8.0.4" acorn-walk: "npm:^8.0.0" commander: "npm:^7.2.0" + debounce: "npm:^1.2.1" escape-string-regexp: "npm:^4.0.0" gzip-size: "npm:^6.0.0" + html-escaper: "npm:^2.0.2" is-plain-object: "npm:^5.0.0" - lodash.debounce: "npm:^4.0.8" - lodash.escape: "npm:^4.0.1" - lodash.flatten: "npm:^4.4.0" - lodash.invokemap: "npm:^4.6.0" - lodash.pullall: "npm:^4.2.0" - lodash.uniqby: "npm:^4.7.0" opener: "npm:^1.5.2" picocolors: "npm:^1.0.0" sirv: "npm:^2.0.3" ws: "npm:^7.3.1" bin: webpack-bundle-analyzer: lib/bin/analyzer.js - checksum: dd047c306471e6c389d6d4156ff22402e587140310a065a6191ee380f8251063f73a8ec6ac6d977c1cd634dbb717e2522b5d0b6cc9b0e847d4f15737fd9c65c9 + checksum: f812a8d3c0198ce518baf742bff656526f3eae69fb7a64c7f0c9cff202f6fb3380cabf3baaae965b8d6ffbbb6fb802eacb373fca03a596a38b01b84cfb2e8329 languageName: node linkType: hard From 36d7d1781f99c66c85cbbde75015b622124b1c3e Mon Sep 17 00:00:00 2001 From: Nick Schonning <nschonni@gmail.com> Date: Tue, 14 Nov 2023 11:53:38 -0500 Subject: [PATCH 034/255] Add CodeCov for Ruby coverage reports (#23868) --- .github/workflows/test-ruby.yml | 8 +++++++- Gemfile | 1 + Gemfile.lock | 2 ++ spec/spec_helper.rb | 8 ++++++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 07fd25fb1..101de66ac 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -94,7 +94,7 @@ jobs: DB_HOST: localhost DB_USER: postgres DB_PASS: postgres - DISABLE_SIMPLECOV: true + DISABLE_SIMPLECOV: ${{ matrix.ruby-version != '.ruby-version' }} RAILS_ENV: test ALLOW_NOPAM: true PAM_ENABLED: true @@ -137,6 +137,12 @@ jobs: - run: bin/rspec + - name: Upload coverage reports to Codecov + if: matrix.ruby-version == '.ruby-version' + uses: codecov/codecov-action@v3 + with: + files: coverage/lcov/mastodon.lcov + test-e2e: name: End to End testing runs-on: ubuntu-latest diff --git a/Gemfile b/Gemfile index 039e13675..add7b3606 100644 --- a/Gemfile +++ b/Gemfile @@ -139,6 +139,7 @@ group :test do # Coverage formatter for RSpec test if DISABLE_SIMPLECOV is false gem 'simplecov', '~> 0.22', require: false + gem 'simplecov-lcov', '~> 0.8', require: false # Stub web requests for specs gem 'webmock', '~> 3.18' diff --git a/Gemfile.lock b/Gemfile.lock index 84ad19b80..20c958e2e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -725,6 +725,7 @@ GEM simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) + simplecov-lcov (0.8.0) simplecov_json_formatter (0.1.4) smart_properties (1.17.0) sprockets (3.7.2) @@ -936,6 +937,7 @@ DEPENDENCIES simple-navigation (~> 4.4) simple_form (~> 5.2) simplecov (~> 0.22) + simplecov-lcov (~> 0.8) sprockets (~> 3.7.2) sprockets-rails (~> 3.4) stackprof diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7c97d8595..f5dcefc78 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -2,13 +2,21 @@ if ENV['DISABLE_SIMPLECOV'] != 'true' require 'simplecov' + require 'simplecov-lcov' + SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true + SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter SimpleCov.start 'rails' do + enable_coverage :branch + enable_coverage_for_eval + add_filter 'lib/linter' add_group 'Policies', 'app/policies' add_group 'Presenters', 'app/presenters' add_group 'Serializers', 'app/serializers' add_group 'Services', 'app/services' add_group 'Validators', 'app/validators' + + add_group 'Libraries', 'lib' end end From 15b2d7eec59c745b418debf63907d8bd08c4a730 Mon Sep 17 00:00:00 2001 From: Emelia Smith <ThisIsMissEm@users.noreply.github.com> Date: Tue, 14 Nov 2023 18:43:20 +0100 Subject: [PATCH 035/255] Split streaming server from web server (#24702) --- Procfile.dev | 2 +- package.json | 27 ++-------- streaming/index.js | 6 ++- streaming/package.json | 39 +++++++++++++++ yarn.lock | 109 ++++++++++++++++++++++------------------- 5 files changed, 108 insertions(+), 75 deletions(-) create mode 100644 streaming/package.json diff --git a/Procfile.dev b/Procfile.dev index fbb2c2de2..f81333b04 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,4 +1,4 @@ web: env PORT=3000 RAILS_ENV=development bundle exec puma -C config/puma.rb sidekiq: env PORT=3000 RAILS_ENV=development bundle exec sidekiq -stream: env PORT=4000 yarn run start +stream: env PORT=4000 yarn workspace @mastodon/streaming start webpack: bin/webpack-dev-server diff --git a/package.json b/package.json index 7c73d17c1..bcd91e3fc 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,13 @@ { "name": "@mastodon/mastodon", "license": "AGPL-3.0-or-later", + "packageManager": "yarn@4.0.2", "engines": { "node": ">=18" }, "workspaces": [ - "." + ".", + "streaming" ], "scripts": { "build:development": "cross-env RAILS_ENV=development NODE_ENV=development ./bin/webpack", @@ -71,10 +73,8 @@ "css-loader": "^5.2.7", "cssnano": "^6.0.1", "detect-passive-events": "^2.0.3", - "dotenv": "^16.0.3", "emoji-mart": "npm:emoji-mart-lazyload@latest", "escape-html": "^1.0.3", - "express": "^4.18.2", "file-loader": "^6.2.0", "font-awesome": "^4.7.0", "fuzzysort": "^2.0.4", @@ -85,21 +85,15 @@ "immutable": "^4.3.0", "imports-loader": "^1.2.0", "intl-messageformat": "^10.3.5", - "ioredis": "^5.3.2", "js-yaml": "^4.1.0", - "jsdom": "^22.1.0", "lodash": "^4.17.21", "mark-loader": "^0.1.6", "marky": "^1.2.5", "mini-css-extract-plugin": "^1.6.2", "mkdirp": "^3.0.1", - "npmlog": "^7.0.1", "path-complete-extname": "^1.0.0", - "pg": "^8.5.0", - "pg-connection-string": "^2.6.0", "postcss": "^8.4.24", "postcss-loader": "^4.3.0", - "prom-client": "^15.0.0", "prop-types": "^15.8.1", "punycode": "^2.3.0", "react": "^18.2.0", @@ -138,7 +132,6 @@ "tesseract.js": "^2.1.5", "tiny-queue": "^0.2.1", "twitter-text": "3.1.0", - "uuid": "^9.0.0", "webpack": "^4.47.0", "webpack-assets-manifest": "^4.0.6", "webpack-bundle-analyzer": "^4.8.0", @@ -150,8 +143,7 @@ "workbox-routing": "^7.0.0", "workbox-strategies": "^7.0.0", "workbox-webpack-plugin": "^7.0.0", - "workbox-window": "^7.0.0", - "ws": "^8.12.1" + "workbox-window": "^7.0.0" }, "devDependencies": { "@formatjs/cli": "^6.1.1", @@ -160,16 +152,13 @@ "@types/babel__core": "^7.20.1", "@types/emoji-mart": "^3.0.9", "@types/escape-html": "^1.0.2", - "@types/express": "^4.17.17", "@types/hoist-non-react-statics": "^3.3.1", "@types/http-link-header": "^1.0.3", "@types/intl": "^1.2.0", "@types/jest": "^29.5.2", "@types/js-yaml": "^4.0.5", "@types/lodash": "^4.14.195", - "@types/npmlog": "^4.1.4", "@types/object-assign": "^4.0.30", - "@types/pg": "^8.6.6", "@types/prop-types": "^15.7.5", "@types/punycode": "^2.1.0", "@types/react": "^18.2.7", @@ -188,7 +177,6 @@ "@types/react-toggle": "^4.0.3", "@types/redux-immutable": "^4.0.3", "@types/requestidlecallback": "^0.3.5", - "@types/uuid": "^9.0.0", "@types/webpack": "^4.41.33", "@types/yargs": "^17.0.24", "@typescript-eslint/eslint-plugin": "^6.0.0", @@ -232,15 +220,10 @@ "optional": true } }, - "optionalDependencies": { - "bufferutil": "^4.0.7", - "utf-8-validate": "^6.0.3" - }, "lint-staged": { "*": "prettier --ignore-unknown --write", "Capfile|Gemfile|*.{rb,ruby,ru,rake}": "bundle exec rubocop --force-exclusion -a", "*.{js,jsx,ts,tsx}": "eslint --fix", "*.{css,scss}": "stylelint --fix" - }, - "packageManager": "yarn@4.0.2" + } } diff --git a/streaming/index.js b/streaming/index.js index b3765531c..e3b63b53a 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -2,6 +2,7 @@ const fs = require('fs'); const http = require('http'); +const path = require('path'); const url = require('url'); const dotenv = require('dotenv'); @@ -17,8 +18,11 @@ const WebSocket = require('ws'); const environment = process.env.NODE_ENV || 'development'; +// Correctly detect and load .env or .env.production file based on environment: +const dotenvFile = environment === 'production' ? '.env.production' : '.env'; + dotenv.config({ - path: environment === 'production' ? '.env.production' : '.env', + path: path.resolve(__dirname, path.join('..', dotenvFile)) }); log.level = process.env.LOG_LEVEL || 'verbose'; diff --git a/streaming/package.json b/streaming/package.json new file mode 100644 index 000000000..d3f214432 --- /dev/null +++ b/streaming/package.json @@ -0,0 +1,39 @@ +{ + "name": "@mastodon/streaming", + "license": "AGPL-3.0-or-later", + "packageManager": "yarn@4.0.1", + "engines": { + "node": ">=18" + }, + "description": "Mastodon's Streaming Server", + "private": true, + "repository": { + "type": "git", + "url": "https://github.com/mastodon/mastodon.git" + }, + "scripts": { + "start": "node ./index.js" + }, + "dependencies": { + "dotenv": "^16.0.3", + "express": "^4.18.2", + "ioredis": "^5.3.2", + "jsdom": "^22.1.0", + "npmlog": "^7.0.1", + "pg": "^8.5.0", + "pg-connection-string": "^2.6.0", + "prom-client": "^15.0.0", + "uuid": "^9.0.0", + "ws": "^8.12.1" + }, + "devDependencies": { + "@types/express": "^4.17.17", + "@types/npmlog": "^4.1.4", + "@types/pg": "^8.6.6", + "@types/uuid": "^9.0.0" + }, + "optionalDependencies": { + "bufferutil": "^4.0.7", + "utf-8-validate": "^6.0.3" + } +} diff --git a/yarn.lock b/yarn.lock index addbe638f..c88dd49d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2368,16 +2368,13 @@ __metadata: "@types/babel__core": "npm:^7.20.1" "@types/emoji-mart": "npm:^3.0.9" "@types/escape-html": "npm:^1.0.2" - "@types/express": "npm:^4.17.17" "@types/hoist-non-react-statics": "npm:^3.3.1" "@types/http-link-header": "npm:^1.0.3" "@types/intl": "npm:^1.2.0" "@types/jest": "npm:^29.5.2" "@types/js-yaml": "npm:^4.0.5" "@types/lodash": "npm:^4.14.195" - "@types/npmlog": "npm:^4.1.4" "@types/object-assign": "npm:^4.0.30" - "@types/pg": "npm:^8.6.6" "@types/prop-types": "npm:^15.7.5" "@types/punycode": "npm:^2.1.0" "@types/react": "npm:^18.2.7" @@ -2396,7 +2393,6 @@ __metadata: "@types/react-toggle": "npm:^4.0.3" "@types/redux-immutable": "npm:^4.0.3" "@types/requestidlecallback": "npm:^0.3.5" - "@types/uuid": "npm:^9.0.0" "@types/webpack": "npm:^4.41.33" "@types/yargs": "npm:^17.0.24" "@typescript-eslint/eslint-plugin": "npm:^6.0.0" @@ -2412,7 +2408,6 @@ __metadata: babel-plugin-preval: "npm:^5.1.0" babel-plugin-transform-react-remove-prop-types: "npm:^0.4.24" blurhash: "npm:^2.0.5" - bufferutil: "npm:^4.0.7" circular-dependency-plugin: "npm:^5.2.2" classnames: "npm:^2.3.2" cocoon-js-vanilla: "npm:^1.3.0" @@ -2423,7 +2418,6 @@ __metadata: css-loader: "npm:^5.2.7" cssnano: "npm:^6.0.1" detect-passive-events: "npm:^2.0.3" - dotenv: "npm:^16.0.3" emoji-mart: "npm:emoji-mart-lazyload@latest" escape-html: "npm:^1.0.3" eslint: "npm:^8.41.0" @@ -2437,7 +2431,6 @@ __metadata: eslint-plugin-promise: "npm:~6.1.1" eslint-plugin-react: "npm:~7.33.0" eslint-plugin-react-hooks: "npm:^4.6.0" - express: "npm:^4.18.2" file-loader: "npm:^6.2.0" font-awesome: "npm:^4.7.0" fuzzysort: "npm:^2.0.4" @@ -2449,25 +2442,19 @@ __metadata: immutable: "npm:^4.3.0" imports-loader: "npm:^1.2.0" intl-messageformat: "npm:^10.3.5" - ioredis: "npm:^5.3.2" jest: "npm:^29.5.0" jest-environment-jsdom: "npm:^29.5.0" js-yaml: "npm:^4.1.0" - jsdom: "npm:^22.1.0" lint-staged: "npm:^15.0.0" lodash: "npm:^4.17.21" mark-loader: "npm:^0.1.6" marky: "npm:^1.2.5" mini-css-extract-plugin: "npm:^1.6.2" mkdirp: "npm:^3.0.1" - npmlog: "npm:^7.0.1" path-complete-extname: "npm:^1.0.0" - pg: "npm:^8.5.0" - pg-connection-string: "npm:^2.6.0" postcss: "npm:^8.4.24" postcss-loader: "npm:^4.3.0" prettier: "npm:^3.0.0" - prom-client: "npm:^15.0.0" prop-types: "npm:^15.8.1" punycode: "npm:^2.3.0" react: "npm:^18.2.0" @@ -2510,8 +2497,6 @@ __metadata: tiny-queue: "npm:^0.2.1" twitter-text: "npm:3.1.0" typescript: "npm:^5.0.4" - utf-8-validate: "npm:^6.0.3" - uuid: "npm:^9.0.0" webpack: "npm:^4.47.0" webpack-assets-manifest: "npm:^4.0.6" webpack-bundle-analyzer: "npm:^4.8.0" @@ -2525,13 +2510,7 @@ __metadata: workbox-strategies: "npm:^7.0.0" workbox-webpack-plugin: "npm:^7.0.0" workbox-window: "npm:^7.0.0" - ws: "npm:^8.12.1" yargs: "npm:^17.7.2" - dependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true peerDependenciesMeta: react: optional: true @@ -2542,6 +2521,34 @@ __metadata: languageName: unknown linkType: soft +"@mastodon/streaming@workspace:streaming": + version: 0.0.0-use.local + resolution: "@mastodon/streaming@workspace:streaming" + dependencies: + "@types/express": "npm:^4.17.17" + "@types/npmlog": "npm:^4.1.4" + "@types/pg": "npm:^8.6.6" + "@types/uuid": "npm:^9.0.0" + bufferutil: "npm:^4.0.7" + dotenv: "npm:^16.0.3" + express: "npm:^4.18.2" + ioredis: "npm:^5.3.2" + jsdom: "npm:^22.1.0" + npmlog: "npm:^7.0.1" + pg: "npm:^8.5.0" + pg-connection-string: "npm:^2.6.0" + prom-client: "npm:^15.0.0" + utf-8-validate: "npm:^6.0.3" + uuid: "npm:^9.0.0" + ws: "npm:^8.12.1" + dependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + languageName: unknown + linkType: soft + "@material-symbols/svg-600@npm:^0.14.0": version: 0.14.0 resolution: "@material-symbols/svg-600@npm:0.14.0" @@ -3056,21 +3063,21 @@ __metadata: linkType: hard "@types/body-parser@npm:*": - version: 1.19.4 - resolution: "@types/body-parser@npm:1.19.4" + version: 1.19.5 + resolution: "@types/body-parser@npm:1.19.5" dependencies: "@types/connect": "npm:*" "@types/node": "npm:*" - checksum: bec2b8a97861a960ee415f7ab3c2aeb7f4d779fd364d27ddee46057897ea571735f1f854f5ee41682964315d4e3699f62427998b9c21851d773398ef535f0612 + checksum: aebeb200f25e8818d8cf39cd0209026750d77c9b85381cdd8deeb50913e4d18a1ebe4b74ca9b0b4d21952511eeaba5e9fbbf739b52731a2061e206ec60d568df languageName: node linkType: hard "@types/connect@npm:*": - version: 3.4.37 - resolution: "@types/connect@npm:3.4.37" + version: 3.4.38 + resolution: "@types/connect@npm:3.4.38" dependencies: "@types/node": "npm:*" - checksum: 79fd5c32a8bb5c9548369e6da3221b6a820f3a8c5396d50f6f642712b9f4c1c881ef86bdf48994a4a279e81998563410b8843c5a10dde5521d5ef6a8ae944c3b + checksum: 2e1cdba2c410f25649e77856505cd60223250fa12dff7a503e492208dbfdd25f62859918f28aba95315251fd1f5e1ffbfca1e25e73037189ab85dd3f8d0a148c languageName: node linkType: hard @@ -3115,14 +3122,14 @@ __metadata: linkType: hard "@types/express-serve-static-core@npm:^4.17.33": - version: 4.17.39 - resolution: "@types/express-serve-static-core@npm:4.17.39" + version: 4.17.41 + resolution: "@types/express-serve-static-core@npm:4.17.41" dependencies: "@types/node": "npm:*" "@types/qs": "npm:*" "@types/range-parser": "npm:*" "@types/send": "npm:*" - checksum: b23b005fddd2ba3f7142ec9713f06b5582c7712cdf99c3419d3972364903b348a103c3264d9a761d6497140e3b89bd416454684c4bdeff206b4c59b86e96428a + checksum: dc166cbf4475c00a81fbcab120bf7477c527184be11ae149df7f26d9c1082114c68f8d387a2926fe80291b06477c8bbd9231ff4f5775de328e887695aefce269 languageName: node linkType: hard @@ -3175,9 +3182,9 @@ __metadata: linkType: hard "@types/http-errors@npm:*": - version: 2.0.3 - resolution: "@types/http-errors@npm:2.0.3" - checksum: 717ce3e8f49a1facb7130fed934108fa8a51ab02089a1049c782e353e0e08e79bdfaac054c2a94db14ea400302e523276387363aa820eaf0031af8ba5d2941dc + version: 2.0.4 + resolution: "@types/http-errors@npm:2.0.4" + checksum: 494670a57ad4062fee6c575047ad5782506dd35a6b9ed3894cea65830a94367bd84ba302eb3dde331871f6d70ca287bfedb1b2cf658e6132cd2cbd427ab56836 languageName: node linkType: hard @@ -3279,16 +3286,16 @@ __metadata: linkType: hard "@types/mime@npm:*": - version: 3.0.3 - resolution: "@types/mime@npm:3.0.3" - checksum: cef99f8cdc42af9de698027c2a20ba5df12bc9a89dcf5513e70103ebb55e00c5f5c585d02411f4b42fde0e78488342f1b1d3e3546a59a3da42e95fdc616e01eb + version: 3.0.4 + resolution: "@types/mime@npm:3.0.4" + checksum: db478bc0f99e40f7b3e01d356a9bdf7817060808a294978111340317bcd80ca35382855578c5b60fbc84ae449674bd9bb38427b18417e1f8f19e4f72f8b242cd languageName: node linkType: hard "@types/mime@npm:^1": - version: 1.3.4 - resolution: "@types/mime@npm:1.3.4" - checksum: a0a16d26c0e70a1b133e26e7c46b70b3136b7e894396bdb7de1c642f4ac87fdbbba26bf56cf73f001312289d89de4f1c06ab745d9445850df45a5a802564c4d6 + version: 1.3.5 + resolution: "@types/mime@npm:1.3.5" + checksum: c2ee31cd9b993804df33a694d5aa3fa536511a49f2e06eeab0b484fef59b4483777dbb9e42a4198a0809ffbf698081fdbca1e5c2218b82b91603dfab10a10fbc languageName: node linkType: hard @@ -3392,16 +3399,16 @@ __metadata: linkType: hard "@types/qs@npm:*": - version: 6.9.9 - resolution: "@types/qs@npm:6.9.9" - checksum: aede2a4181a49ae8548a1354bac3f8235cb0c5aab066b10875a3e68e88a199e220f4284e7e2bb75a3c18e5d4ff6abe1a6ce0389ef31b63952cc45e0f4d885ba0 + version: 6.9.10 + resolution: "@types/qs@npm:6.9.10" + checksum: 6be12e5f062d1b41eb037d59bf9cb65bc9410cedd5e6da832dfd7c8e2b3f4c91e81c9b90b51811140770e5052c6c4e8361181bd9437ddcd4515dc128b7c00353 languageName: node linkType: hard "@types/range-parser@npm:*": - version: 1.2.6 - resolution: "@types/range-parser@npm:1.2.6" - checksum: 46e7fffc54cdacc8fb0cd576f8f9a6436453f0176205d6ec55434a460c7677e78e688673426d5db5e480501b2943ba08a16ececa3a354c222093551c7217fb8f + version: 1.2.7 + resolution: "@types/range-parser@npm:1.2.7" + checksum: 361bb3e964ec5133fa40644a0b942279ed5df1949f21321d77de79f48b728d39253e5ce0408c9c17e4e0fd95ca7899da36841686393b9f7a1e209916e9381a3c languageName: node linkType: hard @@ -3587,23 +3594,23 @@ __metadata: linkType: hard "@types/send@npm:*": - version: 0.17.3 - resolution: "@types/send@npm:0.17.3" + version: 0.17.4 + resolution: "@types/send@npm:0.17.4" dependencies: "@types/mime": "npm:^1" "@types/node": "npm:*" - checksum: 773a0cb55ea03eefbe9a0e6d42114e0f84968db30954a131aae9ba7e9ab984a4776915447ebdeab4412d7f11750126614b0b75e99413f75810045bdb3196554a + checksum: 7f17fa696cb83be0a104b04b424fdedc7eaba1c9a34b06027239aba513b398a0e2b7279778af521f516a397ced417c96960e5f50fcfce40c4bc4509fb1a5883c languageName: node linkType: hard "@types/serve-static@npm:*": - version: 1.15.4 - resolution: "@types/serve-static@npm:1.15.4" + version: 1.15.5 + resolution: "@types/serve-static@npm:1.15.5" dependencies: "@types/http-errors": "npm:*" "@types/mime": "npm:*" "@types/node": "npm:*" - checksum: 061b38993bf8f2b5033f57147c8ec90e1d1a0d6f734958ceb531ba7cc31192fd272c999cdbc57ede8672787e3aa171ec142dc65a467c04078e43823e7476eb49 + checksum: 811d1a2f7e74a872195e7a013bcd87a2fb1edf07eaedcb9dcfd20c1eb4bc56ad4ea0d52141c13192c91ccda7c8aeb8a530d8a7e60b9c27f5990d7e62e0fecb03 languageName: node linkType: hard From 998f0684994b9be5ccad986b83308039ff395ef6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 18:52:34 +0100 Subject: [PATCH 036/255] Update Yarn to v4.0.2 (#27857) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- streaming/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/streaming/package.json b/streaming/package.json index d3f214432..a474e6226 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/streaming", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.0.1", + "packageManager": "yarn@4.0.2", "engines": { "node": ">=18" }, From 7c72944661c100118555045a87ced7d1fa7cc417 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 15 Nov 2023 04:11:02 -0500 Subject: [PATCH 037/255] Use `Lcov` simplecov formatter on CI and `HTML` elsewhere (#27859) --- spec/spec_helper.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f5dcefc78..0bb4f88cf 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -2,9 +2,14 @@ if ENV['DISABLE_SIMPLECOV'] != 'true' require 'simplecov' - require 'simplecov-lcov' - SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true - SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter + + if ENV['CI'] + require 'simplecov-lcov' + SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true + SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter + else + SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter + end SimpleCov.start 'rails' do enable_coverage :branch enable_coverage_for_eval From b6f29106eab8c5deeb1c22051387292108bbb3c8 Mon Sep 17 00:00:00 2001 From: Renaud Chaput <renchap@gmail.com> Date: Wed, 15 Nov 2023 10:20:24 +0100 Subject: [PATCH 038/255] Improve codecov config (#27860) --- .github/codecov.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/codecov.yml diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 000000000..5532c4961 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,13 @@ +coverage: + status: + project: + default: + # Github status check is not blocking + informational: true + patch: + default: + # Github status check is not blocking + informational: true +comment: + # Only write a comment in PR if there are changes + require_changes: true From 5d75799afaacb5b530d9abdb7464db779d3fcbe0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 Nov 2023 09:21:25 +0000 Subject: [PATCH 039/255] Update dependency axios to v1.6.2 (#27861) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index c88dd49d0..e66f58f8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4690,13 +4690,13 @@ __metadata: linkType: hard "axios@npm:^1.4.0": - version: 1.6.1 - resolution: "axios@npm:1.6.1" + version: 1.6.2 + resolution: "axios@npm:1.6.2" dependencies: follow-redirects: "npm:^1.15.0" form-data: "npm:^4.0.0" proxy-from-env: "npm:^1.1.0" - checksum: ca2c6f56659a7f19e4a99082f549fe151952f6fd8aa72ed148559ab2d6a32ce37cd5dc72ce6d4d3cd91f0c1e2617c7c95c20077e5e244a79f319a6c0ce41204f + checksum: 9b77e030e85e4f9cbcba7bb52fbff67d6ce906c92d213e0bd932346a50140faf83733bf786f55bd58301bd92f9973885c7b87d6348023e10f7eaf286d0791a1d languageName: node linkType: hard From 922f086253c8bfcead9df895f4624580d5b61a9c Mon Sep 17 00:00:00 2001 From: Jeong Arm <kjwonmail@gmail.com> Date: Wed, 15 Nov 2023 18:29:10 +0900 Subject: [PATCH 040/255] Fix open status on media modal (#27867) --- .../mastodon/features/picture_in_picture/components/footer.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx index a4ea989fb..9b26e2d75 100644 --- a/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx +++ b/app/javascript/mastodon/features/picture_in_picture/components/footer.jsx @@ -166,7 +166,7 @@ class Footer extends ImmutablePureComponent { onClose(); } - history.push(`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`); + this.props.history.push(`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`); }; render () { From d8074128f9f5f84bd9d5adc416ef67ae922f0289 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:41:24 +0100 Subject: [PATCH 041/255] New Crowdin Translations (automated) (#27866) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/cs.json | 1 + app/javascript/mastodon/locales/eu.json | 2 +- app/javascript/mastodon/locales/it.json | 2 +- app/javascript/mastodon/locales/lt.json | 60 +++++++++++--- app/javascript/mastodon/locales/zh-TW.json | 36 ++++----- config/locales/activerecord.lt.yml | 45 +++++++++++ config/locales/be.yml | 6 +- config/locales/cs.yml | 7 ++ config/locales/devise.zh-TW.yml | 10 +-- config/locales/doorkeeper.zh-TW.yml | 2 +- config/locales/pl.yml | 4 +- config/locales/simple_form.zh-TW.yml | 50 ++++++------ config/locales/vi.yml | 1 + config/locales/zh-TW.yml | 92 +++++++++++----------- 14 files changed, 207 insertions(+), 111 deletions(-) diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index 33c7c31d9..aaf50d67c 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Výsledky hledání", "emoji_button.symbols": "Symboly", "emoji_button.travel": "Cestování a místa", + "empty_column.account_hides_collections": "Tento uživatel se rozhodl nezveřejňovat tuto informaci", "empty_column.account_suspended": "Účet je pozastaven", "empty_column.account_timeline": "Nejsou tu žádné příspěvky!", "empty_column.account_unavailable": "Profil není dostupný", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index 7f109ea08..419589aba 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -389,7 +389,7 @@ "lists.replies_policy.title": "Erakutsi erantzunak:", "lists.search": "Bilatu jarraitzen dituzun pertsonen artean", "lists.subheading": "Zure zerrendak", - "load_pending": "{count, plural, one {eleentuberri #} other {# elementu berri}}", + "load_pending": "{count, plural, one {elementu berri #} other {# elementu berri}}", "loading_indicator.label": "Kargatzen...", "media_gallery.toggle_visible": "Txandakatu ikusgaitasuna", "moved_to_account_banner.text": "Zure {disabledAccount} kontua desgaituta dago une honetan, {movedToAccount} kontura aldatu zinelako.", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 4a2f41ce6..8ad791bfe 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -252,7 +252,7 @@ "explore.search_results": "Risultati della ricerca", "explore.suggested_follows": "Persone", "explore.title": "Esplora", - "explore.trending_links": "Novità", + "explore.trending_links": "Notizie", "explore.trending_statuses": "Post", "explore.trending_tags": "Hashtag", "filter_modal.added.context_mismatch_explanation": "La categoria di questo filtro non si applica al contesto in cui hai acceduto a questo post. Se desideri che il post sia filtrato anche in questo contesto, dovrai modificare il filtro.", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 5cdc575de..5675799e7 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -1,7 +1,7 @@ { "about.blocks": "Prižiūrimi serveriai", "about.contact": "Kontaktuoti:", - "about.disclaimer": "Mastodon – nemokama atvirojo šaltinio programa ir Mastodon gGmbH prekės ženklas.", + "about.disclaimer": "Mastodon – nemokama atvirojo kodo programa ir Mastodon gGmbH prekės ženklas.", "about.domain_blocks.no_reason_available": "Priežastis nežinoma", "about.domain_blocks.preamble": "Mastodon paprastai leidžia peržiūrėti turinį ir bendrauti su naudotojais iš bet kurio kito fediverse esančio serverio. Šios yra išimtys, kurios buvo padarytos šiame konkrečiame serveryje.", "about.domain_blocks.silenced.explanation": "Paprastai nematysi profilių ir turinio iš šio serverio, nebent jį aiškiai ieškosi arba pasirinksi jį sekdamas (-a).", @@ -33,28 +33,46 @@ "account.followers.empty": "Šio naudotojo dar niekas neseka.", "account.followers_counter": "{count, plural, one {{counter} sekėjas (-a)} few {{counter} sekėjai} many {{counter} sekėjo} other {{counter} sekėjų}}", "account.following": "Seka", - "account.follows.empty": "Šis naudotojas (-a) dar nieko neseka.", + "account.follows.empty": "Šis (-i) naudotojas (-a) dar nieko neseka.", "account.follows_you": "Seka tave", "account.go_to_profile": "Eiti į profilį", "account.in_memoriam": "Atminimui.", "account.joined_short": "Prisijungė", "account.languages": "Keisti prenumeruojamas kalbas", + "account.link_verified_on": "Šios nuorodos nuosavybė buvo patikrinta {date}", "account.locked_info": "Šios paskyros privatumo būsena nustatyta kaip užrakinta. Savininkas (-ė) rankiniu būdu peržiūri, kas gali sekti.", "account.media": "Medija", "account.mention": "Paminėti @{name}", "account.moved_to": "{name} nurodė, kad dabar jų nauja paskyra yra:", "account.mute": "Užtildyti @{name}", + "account.mute_notifications_short": "Nutildyti pranešimus", + "account.mute_short": "Nutildyti", "account.muted": "Užtildytas", - "account.posts": "Toots", - "account.posts_with_replies": "Toots and replies", - "account.report": "Pranešti apie @{name}", - "account.requested": "Awaiting approval", + "account.no_bio": "Nėra pateikto aprašymo.", + "account.open_original_page": "Atidaryti originalinį tinklalapį", + "account.posts": "Įrašai", + "account.posts_with_replies": "Įrašai ir atsakymai", + "account.report": "Pranešti @{name}", + "account.requested": "Laukiama patvirtinimo. Spausk, kad atšaukti sekimo užklausą.", + "account.requested_follow": "{name} paprašė tave sekti", + "account.share": "Bendrinti @{name} profilį", "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock_domain": "Unhide {domain}", "account.unblock_short": "Atblokuoti", "account.unfollow": "Nebesekti", + "account.unmute": "Atitildyti @{name}", + "account.unmute_notifications_short": "Atitildyti pranešimus", "account.unmute_short": "Atitildyti", - "account_note.placeholder": "Click to add a note", + "account_note.placeholder": "Spausk norėdamas (-a) pridėti pastabą", + "admin.dashboard.retention.average": "Vidurkis", + "admin.dashboard.retention.cohort": "Registravimo mėnuo", + "admin.dashboard.retention.cohort_size": "Nauji naudotojai", + "admin.impact_report.instance_accounts": "Paskyrų profiliai, kuriuos tai ištrintų", + "admin.impact_report.instance_followers": "Sekėjai, kuriuos prarastų mūsų naudotojai", + "admin.impact_report.instance_follows": "Sekėjai, kuriuos prarastų jų naudotojai", + "admin.impact_report.title": "Poveikio apibendrinimas", + "alert.rate_limited.message": "Pabandyk vėliau po {retry_time, time, medium}.", + "alert.rate_limited.title": "Spartos ribojimas", "alert.unexpected.message": "Įvyko netikėta klaida.", "alert.unexpected.title": "Ups!", "announcement.announcement": "Skelbimas", @@ -65,6 +83,14 @@ "bundle_column_error.copy_stacktrace": "Kopijuoti klaidos ataskaitą", "bundle_column_error.error.body": "Užklausos puslapio nepavyko atvaizduoti. Tai gali būti dėl mūsų kodo klaidos arba naršyklės suderinamumo problemos.", "bundle_column_error.error.title": "O, ne!", + "bundle_column_error.network.body": "Bandant užkrauti šį puslapį įvyko klaida. Tai galėjo atsitikti dėl laikinos tavo interneto ryšio arba šio serverio problemos.", + "bundle_column_error.network.title": "Tinklo klaida", + "bundle_column_error.retry": "Bandyti dar kartą", + "bundle_column_error.return": "Grįžti į pradžią", + "bundle_column_error.routing.body": "Prašyto puslapio nepavyko rasti. Ar esi tikras (-a), kad adreso juostoje nurodytas URL adresas yra teisingas?", + "bundle_column_error.routing.title": "404", + "bundle_modal_error.close": "Uždaryti", + "closed_registrations_modal.find_another_server": "Rasti kitą serverį", "column.domain_blocks": "Hidden domains", "column.lists": "Sąrašai", "column.mutes": "Užtildyti vartotojai", @@ -81,18 +107,32 @@ "compose.published.body": "Įrašas paskelbtas.", "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.", - "compose_form.placeholder": "What is on your mind?", + "compose_form.placeholder": "Kas tavo mintyse?", + "compose_form.poll.add_option": "Pridėti pasirinkimą", + "compose_form.poll.duration": "Apklausos trukmė", + "compose_form.poll.option_placeholder": "Pasirinkimas {number}", + "compose_form.poll.remove_option": "Pašalinti šį pasirinkimą", + "compose_form.poll.switch_to_multiple": "Keisti apklausą, kad būtų galima pasirinkti kelis pasirinkimus", "compose_form.publish_form": "Publish", "compose_form.sensitive.hide": "{count, plural, one {Žymėti mediją kaip jautrią} few {Žymėti medijas kaip jautrias} many {Žymėti medijos kaip jautrios} other {Žymėti medijų kaip jautrių}}", "compose_form.sensitive.marked": "{count, plural, one {Medija pažymėta kaip jautri} few {Medijos pažymėtos kaip jautrios} many {Medijos pažymėta kaip jautrios} other {Medijų pažymėtos kaip jautrios}}", "compose_form.sensitive.unmarked": "{count, plural, one {Medija nepažymėta kaip jautri} few {Medijos nepažymėtos kaip jautrios} many {Medijos nepažymėta kaip jautri} other {Medijų nepažymėta kaip jautrios}}", "compose_form.spoiler.marked": "Text is hidden behind warning", - "compose_form.spoiler.unmarked": "Text is not hidden", + "compose_form.spoiler.unmarked": "Pridėti turinio įspėjimą", + "compose_form.spoiler_placeholder": "Rašyk savo įspėjimą čia", + "confirmation_modal.cancel": "Atšaukti", + "confirmations.block.block_and_report": "Blokuoti ir pranešti", + "confirmations.block.confirm": "Blokuoti", + "confirmations.block.message": "Ar tikrai nori užblokuoti {name}?", "confirmations.delete.confirm": "Ištrinti", "confirmations.delete.message": "Are you sure you want to delete this status?", "confirmations.discard_edit_media.confirm": "Atmesti", "confirmations.discard_edit_media.message": "Turi neišsaugotų medijos aprašymo ar peržiūros pakeitimų, vis tiek juos atmesti?", "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.logout.confirm": "Atsijungti", + "confirmations.logout.message": "Ar tikrai nori atsijungti?", + "confirmations.mute.confirm": "Nutildyti", + "confirmations.mute.explanation": "Tai paslėps jų įrašus ir įrašus, kuriuose jie menėmi, tačiau jie vis tiek galės matyti tavo įrašus ir sekti.", "confirmations.reply.confirm": "Atsakyti", "confirmations.reply.message": "Atsakydamas (-a) dabar perrašysi šiuo metu rašomą žinutę. Ar tikrai nori tęsti?", "confirmations.unfollow.confirm": "Nebesekti", @@ -219,6 +259,8 @@ "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {# days}}", "upload_form.audio_description": "Describe for people with hearing loss", "upload_form.description": "Describe for the visually impaired", + "upload_form.description_missing": "Nėra pridėto aprašymo", + "upload_form.edit": "Redaguoti", "upload_form.video_description": "Describe for people with hearing loss or visual impairment", "upload_modal.edit_media": "Redaguoti mediją", "upload_progress.label": "Uploading…" diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index db4fe4eab..974096d2f 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -12,7 +12,7 @@ "about.powered_by": "由 {mastodon} 提供的去中心化社群媒體", "about.rules": "伺服器規則", "account.account_note_header": "備註", - "account.add_or_remove_from_list": "從列表中新增或移除", + "account.add_or_remove_from_list": "自列表中新增或移除", "account.badges.bot": "機器人", "account.badges.group": "群組", "account.block": "封鎖 @{name}", @@ -26,7 +26,7 @@ "account.domain_blocked": "已封鎖網域", "account.edit_profile": "編輯個人檔案", "account.enable_notifications": "當 @{name} 嘟文時通知我", - "account.endorse": "在個人檔案推薦對方", + "account.endorse": "於個人檔案推薦對方", "account.featured_tags.last_status_at": "上次嘟文於 {date}", "account.featured_tags.last_status_never": "沒有嘟文", "account.featured_tags.title": "{name} 的推薦主題標籤", @@ -65,7 +65,7 @@ "account.unblock": "解除封鎖 @{name}", "account.unblock_domain": "解除封鎖網域 {domain}", "account.unblock_short": "解除封鎖", - "account.unendorse": "取消在個人檔案推薦對方", + "account.unendorse": "取消於個人檔案推薦對方", "account.unfollow": "取消跟隨", "account.unmute": "解除靜音 @{name}", "account.unmute_notifications_short": "取消靜音推播通知", @@ -102,7 +102,7 @@ "bundle_modal_error.message": "載入此元件時發生錯誤。", "bundle_modal_error.retry": "重試", "closed_registrations.other_server_instructions": "因為 Mastodon 是去中心化的,所以您也能於其他伺服器上建立帳號,並仍然與這個伺服器互動。", - "closed_registrations_modal.description": "目前無法在 {domain} 建立新帳號,但也請別忘了,您並不一定需要有 {domain} 伺服器的帳號,也能使用 Mastodon 。", + "closed_registrations_modal.description": "目前無法於 {domain} 建立新帳號,但也請別忘了,您並不一定需要有 {domain} 伺服器的帳號,也能使用 Mastodon 。", "closed_registrations_modal.find_another_server": "尋找另一個伺服器", "closed_registrations_modal.preamble": "Mastodon 是去中心化的,所以無論您於哪個伺服器新增帳號,都可以與此伺服器上的任何人跟隨及互動。您甚至能自行架一個自己的伺服器!", "closed_registrations_modal.title": "註冊 Mastodon", @@ -171,7 +171,7 @@ "confirmations.delete_list.confirm": "刪除", "confirmations.delete_list.message": "您確定要永久刪除此列表嗎?", "confirmations.discard_edit_media.confirm": "捨棄", - "confirmations.discard_edit_media.message": "您在媒體描述或預覽區塊有未儲存的變更。是否要捨棄這些變更?", + "confirmations.discard_edit_media.message": "您於媒體描述或預覽區塊有未儲存的變更。是否要捨棄這些變更?", "confirmations.domain_block.confirm": "封鎖整個網域", "confirmations.domain_block.message": "您真的非常確定要封鎖整個 {domain} 網域嗎?大部分情況下,封鎖或靜音少數特定的帳號就能滿足需求了。您將不能在任何公開的時間軸及通知中看到來自此網域的內容。您來自該網域的跟隨者也將被移除。", "confirmations.edit.confirm": "編輯", @@ -205,7 +205,7 @@ "dismissable_banner.explore_statuses": "這些於此伺服器以及去中心化網路中其他伺服器發出的嘟文正在被此伺服器上的人們熱烈討論著。越多不同人轉嘟及最愛排名更高。", "dismissable_banner.explore_tags": "這些主題標籤正在被此伺服器以及去中心化網路上的人們熱烈討論著。越多不同人所嘟出的主題標籤排名更高。", "dismissable_banner.public_timeline": "這些是來自 {domain} 使用者們跟隨中帳號所發表之最新公開嘟文。", - "embed.instructions": "要在您的網站嵌入此嘟文,請複製以下程式碼。", + "embed.instructions": "若您欲於您的網站嵌入此嘟文,請複製以下程式碼。", "embed.preview": "它將顯示成這樣:", "emoji_button.activity": "活動", "emoji_button.clear": "清除", @@ -218,7 +218,7 @@ "emoji_button.objects": "物件", "emoji_button.people": "人物", "emoji_button.recent": "最常使用", - "emoji_button.search": "搜尋…", + "emoji_button.search": "搜尋...", "emoji_button.search_results": "搜尋結果", "emoji_button.symbols": "符號", "emoji_button.travel": "旅遊與地點", @@ -259,7 +259,7 @@ "filter_modal.added.context_mismatch_title": "不符合情境!", "filter_modal.added.expired_explanation": "此過濾器類別已失效,您需要更新過期日期以套用。", "filter_modal.added.expired_title": "過期的過濾器!", - "filter_modal.added.review_and_configure": "要檢視和進一步設定此過濾器類別,請至 {settings_link}。", + "filter_modal.added.review_and_configure": "要檢視與進一步設定此過濾器類別,請至 {settings_link}。", "filter_modal.added.review_and_configure_title": "過濾器設定", "filter_modal.added.settings_link": "設定頁面", "filter_modal.added.short_explanation": "此嘟文已被新增至以下過濾器類別:{title}。", @@ -362,7 +362,7 @@ "keyboard_shortcuts.search": "將游標移至搜尋框", "keyboard_shortcuts.spoilers": "顯示或隱藏內容警告之嘟文", "keyboard_shortcuts.start": "開啟「開始使用」欄位", - "keyboard_shortcuts.toggle_hidden": "顯示或隱藏在內容警告之後的嘟文", + "keyboard_shortcuts.toggle_hidden": "顯示或隱藏於內容警告之後的嘟文", "keyboard_shortcuts.toggle_sensitivity": "顯示或隱藏媒體", "keyboard_shortcuts.toot": "發個新嘟文", "keyboard_shortcuts.unfocus": "跳離文字撰寫區塊或搜尋框", @@ -376,7 +376,7 @@ "limited_account_hint.title": "此個人檔案已被 {domain} 的管理員隱藏。", "link_preview.author": "由 {name} 提供", "lists.account.add": "新增至列表", - "lists.account.remove": "從列表中移除", + "lists.account.remove": "自列表中移除", "lists.delete": "刪除列表", "lists.edit": "編輯列表", "lists.edit.submit": "變更標題", @@ -469,7 +469,7 @@ "notifications.permission_denied_alert": "由於之前瀏覽器權限被拒絕,無法啟用桌面通知", "notifications.permission_required": "由於尚未授予所需的權限,因此無法使用桌面通知。", "notifications_permission_banner.enable": "啟用桌面通知", - "notifications_permission_banner.how_to_control": "啟用桌面通知以在 Mastodon 沒有開啟的時候接收通知。在已經啟用桌面通知的時候,您可以透過上面的 {icon} 按鈕準確的控制哪些類型的互動會產生桌面通知。", + "notifications_permission_banner.how_to_control": "啟用桌面通知以於 Mastodon 沒有開啟的時候接收通知。啟用桌面通知後,您可以透過上面的 {icon} 按鈕準確的控制哪些類型的互動會產生桌面通知。", "notifications_permission_banner.title": "不要錯過任何東西!", "onboarding.action.back": "返回", "onboarding.actions.back": "返回", @@ -490,7 +490,7 @@ "onboarding.steps.follow_people.title": "客製化您的首頁時間軸", "onboarding.steps.publish_status.body": "向新世界打聲招呼吧。", "onboarding.steps.publish_status.title": "撰寫您第一則嘟文", - "onboarding.steps.setup_profile.body": "若您完整填寫個人檔案,其他人比較願意和您互動。", + "onboarding.steps.setup_profile.body": "若您完整填寫個人檔案,其他人比較願意與您互動。", "onboarding.steps.setup_profile.title": "客製化您的個人檔案", "onboarding.steps.share_profile.body": "讓您的朋友們知道如何於 Mastodon 找到您!", "onboarding.steps.share_profile.title": "分享您的 Mastodon 個人檔案", @@ -614,10 +614,10 @@ "sign_in_banner.create_account": "新增帳號", "sign_in_banner.sign_in": "登入", "sign_in_banner.sso_redirect": "登入或註冊", - "sign_in_banner.text": "登入以跟隨個人檔案和主題標籤,或收藏、分享和回覆嘟文。您也可以使用您的帳號在其他伺服器上進行互動。", + "sign_in_banner.text": "登入以跟隨個人檔案與主題標籤,或收藏、分享及回覆嘟文。您也可以使用您的帳號於其他伺服器進行互動。", "status.admin_account": "開啟 @{name} 的管理介面", "status.admin_domain": "開啟 {domain} 的管理介面", - "status.admin_status": "在管理介面開啟此嘟文", + "status.admin_status": "於管理介面開啟此嘟文", "status.block": "封鎖 @{name}", "status.bookmark": "書籤", "status.cancel_reblog_private": "取消轉嘟", @@ -672,8 +672,8 @@ "status.translated_from_with": "透過 {provider} 翻譯 {lang}", "status.uncached_media_warning": "無法預覽", "status.unmute_conversation": "解除此對話的靜音", - "status.unpin": "從個人檔案頁面取消釘選", - "subscribed_languages.lead": "僅選定語言的嘟文才會出現在您的首頁上,並在變更後列出時間軸。選取「無」以接收所有語言的嘟文。", + "status.unpin": "自個人檔案頁面取消釘選", + "subscribed_languages.lead": "僅選定語言的嘟文才會出現於您的首頁上,並於變更後列出時間軸。選取「無」以接收所有語言的嘟文。", "subscribed_languages.save": "儲存變更", "subscribed_languages.target": "變更 {target} 的訂閱語言", "tabs_bar.home": "首頁", @@ -696,7 +696,7 @@ "upload_area.title": "拖放來上傳", "upload_button.label": "上傳圖片、影片、或者音樂檔案", "upload_error.limit": "已達到檔案上傳限制。", - "upload_error.poll": "不允許在投票中上傳檔案。", + "upload_error.poll": "不允許於投票時上傳檔案。", "upload_form.audio_description": "為聽障人士增加文字說明", "upload_form.description": "為視障人士增加文字說明", "upload_form.description_missing": "沒有任何描述", @@ -706,7 +706,7 @@ "upload_form.video_description": "為聽障或視障人士增加文字說明", "upload_modal.analyzing_picture": "正在分析圖片…", "upload_modal.apply": "套用", - "upload_modal.applying": "正在套用⋯⋯", + "upload_modal.applying": "正在套用...", "upload_modal.choose_image": "選擇圖片", "upload_modal.description_placeholder": "我能吞下玻璃而不傷身體", "upload_modal.detect_text": "從圖片中偵測文字", diff --git a/config/locales/activerecord.lt.yml b/config/locales/activerecord.lt.yml index f54d00471..cb6e21d8e 100644 --- a/config/locales/activerecord.lt.yml +++ b/config/locales/activerecord.lt.yml @@ -1,6 +1,19 @@ --- lt: activerecord: + attributes: + poll: + expires_at: Galutinė data + options: Pasirinkimai + user: + agreement: Paslaugos sutartis + email: El. laiško adresas + locale: Lokali + password: Slaptažodis + user/account: + username: Naudotojo vardas + user/invite_request: + text: Priežastis errors: models: account: @@ -12,3 +25,35 @@ lt: attributes: url: invalid: nėra tinkamas URL adresas. + doorkeeper/application: + attributes: + website: + invalid: nėra tinkamas URL adresas. + import: + attributes: + data: + malformed: yra netaisyklinga. + status: + attributes: + reblog: + taken: įrašas jau egzistuoja. + user: + attributes: + email: + blocked: naudoja neleidžiamą el. laiško paslaugų teikėją. + unreachable: neatrodo, kad egzistuoja. + role_id: + elevated: negali būti didesnis nei tavo dabartinis vaidmuo. + user_role: + attributes: + permissions_as_keys: + dangerous: apima leidimus, kurie nėra saugūs pagrindiniam vaidmeniui. + elevated: negali apimti leidimų, kurių neturi tavo dabartinis vaidmuo. + own_role: negali būti pakeistas tavo dabartinis vaidmuo. + position: + elevated: negali būti didesnis nei tavo dabartinis vaidmuo. + own_role: negali būti pakeistas tavo dabartinis vaidmuo. + webhook: + attributes: + events: + invalid_permissions: negali įtraukti įvykių, į kuriuos neturi teisių. diff --git a/config/locales/be.yml b/config/locales/be.yml index 96a272012..223b4d1df 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -1052,7 +1052,7 @@ be: localization: body: Mastodon перакладаецца добраахвотнікамі. guide_link: https://be.crowdin.com/project/mastodon/be - guide_link_text: Кожны можа зрабіць унёсак. + guide_link_text: Кожны і кожная можа зрабіць унёсак. sensitive_content: Далікатны змест application_mailer: notification_preferences: Змяніць налады эл. пошты @@ -1575,7 +1575,7 @@ be: duration_too_short: гэта занадта хутка expired: Апытанне ўжо скончана invalid_choice: Абраны варыянт апытання не існуе - over_character_limit: не можа быць даўжэй за %{max} сімвалаў кожны + over_character_limit: кожны не можа быць даўжэй за %{max} сімвалаў self_vote: Вы не можаце галасаваць ва ўласных апытаннях too_few_options: павінна быць болей за адзін варыянт too_many_options: колькасць варыянтаў не можа перавышаць %{max} @@ -1764,7 +1764,7 @@ be: public: Публічны public_long: Усе могуць бачыць unlisted: Не ў спісе - unlisted_long: Кожны можа ўбачыць гэты допіс, але ён не паказваецца ў публічных стужках + unlisted_long: Усе могуць пабачыць гэты допіс, але ён не паказваецца ў публічных стужках statuses_cleanup: enabled: Аўтаматычна выдаляць старыя допісы enabled_hint: Аўтаматычна выдаляць вашыя допісы, калі яны дасягаюць вызначанага тэрміну, акрамя наступных выпадкаў diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 15ca09470..a04682a44 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -1074,6 +1074,10 @@ cs: hint_html: Ještě jedna věc! Musíme potvrdit, že jste člověk (to proto, abychom drželi stranou spam!). Vyřešte CAPTCHA níže a klikněte na "Pokračovat". title: Bezpečnostní kontrola confirmations: + awaiting_review_title: Vaše registrace se ověřuje + clicking_this_link: kliknutím na tento odkaz + registration_complete: Vaše registrace na %{domain} je hotová! + welcome_title: Vítám uživatele %{name}! wrong_email_hint: Pokud není e-mail správný, můžete si ho změnit v nastavení účtu. delete_account: Odstranit účet delete_account_html: Chcete-li odstranit svůj účet, <a href="%{path}">pokračujte zde</a>. Budete požádáni o potvrzení. @@ -1770,6 +1774,9 @@ cs: default: "%d. %b %Y, %H:%M" month: "%b %Y" time: "%H:%M" + translation: + errors: + too_many_requests: Na překladatelskou službu bylo zasláno v poslední době příliš mnoho požadavků. two_factor_authentication: add: Přidat disable: Vypnout 2FA diff --git a/config/locales/devise.zh-TW.yml b/config/locales/devise.zh-TW.yml index c01beb796..de977426f 100644 --- a/config/locales/devise.zh-TW.yml +++ b/config/locales/devise.zh-TW.yml @@ -9,7 +9,7 @@ zh-TW: already_authenticated: 您已登入。 inactive: 您的帳號尚未啟用。 invalid: 無效的 %{authentication_keys} 或密碼。 - last_attempt: 在帳號鎖定前,您還有最後一次嘗試機會。 + last_attempt: 帳號鎖定前,您還有最後一次嘗試機會。 locked: 已鎖定您的帳號。 not_found_in_database: 無效的 %{authentication_keys} 或密碼。 pending: 您的帳號仍在審核中。 @@ -20,8 +20,8 @@ zh-TW: confirmation_instructions: action: 驗證電子郵件地址 action_with_app: 確認並返回 %{app} - explanation: 您已經在 %{host} 上以此電子郵件地址建立了一支帳號。您距離啟用它只剩一點之遙了。若這不是您,請忽略此信件。 - explanation_when_pending: 您使用此電子郵件地址申請了 %{host} 的邀請。當您確認電子郵件地址後我們將審核您的申請。您可以在登入後變更詳細資訊或刪除您的帳號,但直到您的帳號被核准之前,您無法操作大部分的功能。若您的申請遭拒絕,您的資料將被移除而不必做後續動作。如果這不是您本人,請忽略此郵件。 + explanation: 您已於 %{host} 上以此電子郵件地址建立了一支帳號。您距離啟用它只剩一點之遙了。若這不是您,請忽略此信件。 + explanation_when_pending: 您使用此電子郵件地址申請了 %{host} 的邀請。當您確認電子郵件地址後我們將審核您的申請。您能於登入後變更詳細資訊或刪除您的帳號,但直到您的帳號被核准之前,您無法操作大部分的功能。若您的申請遭拒絕,您的資料將被移除而不必做後續動作。如果這不是您本人,請忽略此郵件。 extra_html: 同時也請看看<a href="%{terms_path}">伺服器規則</a>與<a href="%{policy_path}">服務條款</a>。 subject: Mastodon:%{instance} 確認說明 title: 驗證電子郵件地址 @@ -37,7 +37,7 @@ zh-TW: title: 密碼已變更 reconfirmation_instructions: explanation: 請確認新的電子郵件地址以變更。 - extra: 若此次變更不是由您起始的,請忽略此信件。Mastodon 帳號的電子郵件地址在您存取上面的連結前不會變更。 + extra: 若此次變更不是由您起始的,請忽略此信件。Mastodon 帳號的電子郵件地址於您存取上面的連結前不會變更。 subject: Mastodon:確認 %{instance} 的電子郵件地址 title: 驗證電子郵件地址 reset_password_instructions: @@ -106,7 +106,7 @@ zh-TW: errors: messages: already_confirmed: 已經確認,請嘗試登入 - confirmation_period_expired: 需要在 %{period} 內完成驗證。請重新申請 + confirmation_period_expired: 您需要於 %{period} 內完成驗證。請重新申請 expired: 已經過期,請重新請求 not_found: 找不到 not_locked: 並未鎖定 diff --git a/config/locales/doorkeeper.zh-TW.yml b/config/locales/doorkeeper.zh-TW.yml index 6073096c3..c0d42ec7b 100644 --- a/config/locales/doorkeeper.zh-TW.yml +++ b/config/locales/doorkeeper.zh-TW.yml @@ -72,7 +72,7 @@ zh-TW: revoke: 您確定嗎? index: authorized_at: 於 %{date} 授權 - description_html: 這些應用程式能透過 API 存取您的帳號。若有您不認得之應用程式,或應用程式行為異常,您可以於此註銷其存取權限。 + description_html: 這些應用程式能透過 API 存取您的帳號。若有您不認得之應用程式,或應用程式行為異常,您能於此註銷其存取權限。 last_used_at: 上次使用時間 %{date} never_used: 從未使用 scopes: 權限 diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 608599724..69b1aa0a9 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -419,8 +419,8 @@ pl: hint: Blokada domen nie zabroni tworzenia wpisów kont w bazie danych, ale pozwoli na automatyczną moderację kont do nich należących. severity: desc_html: "<strong>Wyciszenie</strong> uczyni wpisy użytkowników z tej domeny widoczne tylko dla osób, które go obserwują. <strong>Zawieszenie</strong> spowoduje usunięcie całej zawartości dodanej przez użytkownika. Użyj <strong>Żadne</strong>, jeżeli chcesz jedynie odrzucać zawartość multimedialną." - noop: Nic nie rób - silence: Limit + noop: Żadne + silence: Wycisz suspend: Zawieś title: Nowa blokada domen no_domain_block_selected: Nie zmieniono żadnych bloków domen, gdyż żadna nie została wybrana diff --git a/config/locales/simple_form.zh-TW.yml b/config/locales/simple_form.zh-TW.yml index be21f862f..13b2ad30a 100644 --- a/config/locales/simple_form.zh-TW.yml +++ b/config/locales/simple_form.zh-TW.yml @@ -15,25 +15,25 @@ zh-TW: account_migration: acct: 指定要移動至的帳號的「使用者名稱@網域名稱」 account_warning_preset: - text: 您可使用嘟文語法,例如網址、「#」標籤和提及功能 - title: 可選。不會向收件者顯示 + text: 您可使用嘟文語法,例如網址、「#」標籤與提及功能 + title: 可選的。不會向收件者顯示 admin_account_action: include_statuses: 使用者可看到導致檢舉或警告的嘟文 send_email_notification: 使用者將收到帳號發生之事情的解釋 - text_html: 選用。您能使用嘟文語法。您可 <a href="%{path}">新增警告預設</a> 來節省時間 + text_html: 可選的。您能使用嘟文語法。您可 <a href="%{path}">新增警告預設</a> 來節省時間 type_html: 設定要使用 <strong>%{acct}</strong> 做的事 types: disable: 禁止該使用者使用他們的帳號,但是不刪除或隱藏他們的內容。 none: 使用這個寄送警告給該使用者,而不進行其他動作。 sensitive: 強制標記此使用者所有多媒體附加檔案為敏感內容。 - silence: 禁止該使用者發公開嘟文,從無跟隨他們的帳號中隱藏嘟文和通知。關閉所有對此帳號之檢舉報告。 + silence: 禁止該使用者發公開嘟文,從無跟隨他們的帳號中隱藏嘟文與通知。關閉所有對此帳號之檢舉報告。 suspend: 禁止所有對該帳號任何互動,並且刪除其內容。三十天內可以撤銷此動作。關閉所有對此帳號之檢舉報告。 - warning_preset_id: 選用。您仍可在預設的結尾新增自訂文字 + warning_preset_id: 可選的。您仍可於預設的結尾新增自訂文字 announcement: all_day: 當選取時,僅顯示出時間範圍中的日期部分 - ends_at: 可選的,公告會於該時間點自動取消發布 + ends_at: 可選的。公告會於該時間點自動取消發布 scheduled_at: 空白則立即發布公告 - starts_at: 可選的,讓公告在特定時間範圍內顯示 + starts_at: 可選的。讓公告於特定時間範圍內顯示 text: 您可以使用嘟文語法,但請小心別讓公告太鴨霸而佔據使用者的整個版面。 appeal: text: 您只能對警示提出一次申訴 @@ -44,12 +44,12 @@ zh-TW: context: 此過濾器應套用於以下一項或多項情境 current_password: 因安全因素,請輸入目前帳號的密碼 current_username: 請輸入目前帳號的使用者名稱以確認 - digest: 僅在您長時間未登入且在未登入期間收到私訊時傳送 + digest: 僅於您長時間未登入且於未登入期間收到私訊時傳送 email: 您將收到一封確認電子郵件 header: 支援 PNG、GIF 或 JPG 圖片格式,檔案最大為 %{size},會等比例縮減至 %{dimensions} 像素 inbox_url: 從您想要使用的中繼首頁複製網址 irreversible: 已過濾的嘟文將會不可逆地消失,即便之後移除過濾器也一樣 - locale: 使用者介面、電子郵件和推播通知的語言 + locale: 使用者介面、電子郵件與推播通知的語言 password: 使用至少 8 個字元 phrase: 無論是嘟文的本文或是內容警告都會被過濾 scopes: 允許讓應用程式存取的 API。 若您選擇最高階範圍,則無須選擇個別項目。 @@ -62,12 +62,12 @@ zh-TW: setting_use_blurhash: 彩色漸層圖樣是基於隱藏媒體內容顏色產生,所有細節將變得模糊 setting_use_pending_items: 關閉自動捲動更新,時間軸僅於點擊後更新 username: 您可以使用字幕、數字與底線 - whole_word: 如果關鍵字或詞組僅有字母與數字,則其將只在符合整個單字的時候才會套用 + whole_word: 如果關鍵字或詞組僅有字母與數字,則其將只於符合整個單字時才會套用 domain_allow: - domain: 此網域將能夠攫取本站資料,而自該網域發出的資料也會於本站處理和留存。 + domain: 此網域將能夠攫取本站資料,而自該網域發出的資料也會於本站處理及留存。 email_domain_block: - domain: 這可以是顯示在電子郵件中的網域名稱,或是其使用的 MX 紀錄。其將於註冊時檢查。 - with_dns_records: Mastodon 會嘗試解析所給網域的 DNS 記錄,解析結果一致者將一併封鎖 + domain: 這可以是顯示於電子郵件中的網域名稱,或是其使用的 MX 紀錄。其將於註冊時檢查。 + with_dns_records: Mastodon 會嘗試解析所提供之網域的 DNS 記錄,解析結果一致者將一併封鎖 featured_tag: name: 這些是您最近使用的一些主題標籤: filters: @@ -97,7 +97,7 @@ zh-TW: theme: 未登入之訪客或新使用者所見之佈景主題。 thumbnail: 大約 2:1 圖片會顯示於您伺服器資訊之旁。 timeline_preview: 未登入之訪客能夠瀏覽此伺服器上最新的公開嘟文。 - trendable_by_default: 跳過手動審核熱門內容。仍能在登上熱門趨勢後移除個別內容。 + trendable_by_default: 跳過手動審核熱門內容。仍能於登上熱門趨勢後移除個別內容。 trends: 熱門趨勢將顯示於您伺服器上正在吸引大量注意力的嘟文、主題標籤、或者新聞。 trends_as_landing_page: 顯示熱門趨勢內容給未登入使用者及訪客而不是關於此伺服器之描述。需要啟用熱門趨勢。 form_challenge: @@ -107,9 +107,9 @@ zh-TW: invite_request: text: 這會協助我們審核您的申請 ip_block: - comment: 可選的,但請記得您為何添加這項規則。 + comment: 可選的。但請記得您為何添加這項規則。 expires_in: IP 位址是經常共用或轉手的有限資源,不建議無限期地封鎖特定 IP 位址。 - ip: 請輸入 IPv4 或 IPv6 位址,亦可以用 CIDR 語法以封鎖整個 IP 區段。小心不要將自己給一併封鎖掉囉! + ip: 請輸入 IPv4 或 IPv6 位址,亦可以用 CIDR 語法以封鎖整個 IP 區段。小心不要將自己一併封鎖掉囉! severities: no_access: 封鎖對所有資源存取 sign_up_block: 無法註冊新帳號 @@ -129,11 +129,11 @@ zh-TW: chosen_languages: 當選取時,只有選取語言之嘟文會於公開時間軸中顯示 role: 角色控制使用者有哪些權限 user_role: - color: 在整個使用者介面中用於角色的顏色,十六進位格式的 RGB + color: 於整個使用者介面中用於角色的顏色,十六進位格式的 RGB highlighted: 這會讓角色公開可見 name: 角色的公開名稱,如果角色設定為顯示為徽章 - permissions_as_keys: 有此角色的使用者將有權存取…… - position: 在某些情況下,衝突的解決方式由更高階的角色決定。某些動作只能由優先程度較低的角色執行 + permissions_as_keys: 有此角色的使用者將有權存取... + position: 某些情況下,衝突的解決方式由更高階的角色決定。某些動作只能由優先程度較低的角色執行 webhook: events: 請選擇要傳送的事件 template: 使用變數代換組合您自己的 JSON payload。留白以使用預設 JSON 。 @@ -155,7 +155,7 @@ zh-TW: text: 預設文字 title: 標題 admin_account_action: - include_statuses: 在電子郵件中加入檢舉的嘟文 + include_statuses: 於電子郵件中加入檢舉之嘟文內容 send_email_notification: 透過電子郵件通知使用者 text: 自訂警告 type: 動作 @@ -230,7 +230,7 @@ zh-TW: username_or_email: 使用者名稱或電子郵件地址 whole_word: 整個詞彙 email_domain_block: - with_dns_records: 包括網域的 MX 記錄和 IP 位址 + with_dns_records: 包括網域的 MX 記錄與 IP 位址 featured_tag: name: "「#」主題標籤" filters: @@ -287,7 +287,7 @@ zh-TW: favourite: 當有使用者將您的嘟文加入最愛時,傳送電子郵件通知 follow: 當有使用者跟隨您時,傳送電子郵件通知 follow_request: 當有使用者請求跟隨您時,傳送電子郵件通知 - mention: 當有使用者在嘟文提及您時,傳送電子郵件通知 + mention: 當有使用者於嘟文提及您時,傳送電子郵件通知 pending_account: 有新的帳號需要審核 reblog: 當有使用者轉嘟您的嘟文時,傳送電子郵件通知 report: 新回報已遞交 @@ -304,16 +304,16 @@ zh-TW: indexable: 於搜尋引擎中包含個人檔案頁面 show_application: 顯示您發嘟文之應用程式 tag: - listable: 允許此主題標籤在搜尋及個人檔案目錄中顯示 + listable: 允許此主題標籤於搜尋及個人檔案目錄中顯示 name: 主題標籤 - trendable: 允許此主題標籤在熱門趨勢下顯示 + trendable: 允許此主題標籤於熱門趨勢下顯示 usable: 允許嘟文使用此主題標籤 user: role: 角色 time_zone: 時區 user_role: color: 識別顏色 - highlighted: 在使用者個人檔案上將角色顯示為徽章 + highlighted: 於使用者個人檔案中顯示角色徽章 name: 名稱 permissions_as_keys: 權限 position: 優先權 diff --git a/config/locales/vi.yml b/config/locales/vi.yml index ec8f6c139..9d90d1d51 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -1343,6 +1343,7 @@ vi: '86400': 1 ngày expires_in_prompt: Không giới hạn generate: Tạo lời mời + invalid: Lời mời không hợp lệ invited_by: 'Bạn đã được mời bởi:' max_uses: other: "%{count} lần dùng" diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 3063b7afd..7259afdbe 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -1,10 +1,10 @@ --- zh-TW: about: - about_mastodon_html: Mastodon (長毛象)是一個<em>自由、開放原始碼</em>的社群網站。它是一個分散式的服務,避免您的通訊被單一商業機構壟斷操控。請您選擇一家您信任的 Mastodon 站點,在上面建立帳號,然後您就可以和任一 Mastodon 站點上的使用者互通,享受無縫的<em>社群網路</em>交流。 + about_mastodon_html: Mastodon (長毛象)是一個<em>自由、開放原始碼</em>的社群網站。它是一個分散式的服務,避免您的通訊被單一商業機構壟斷操控。請您選擇一家您信任的 Mastodon 站點,於其建立帳號,您就能與任一 Mastodon 站點上的使用者互通,享受無縫的<em>社群網路</em>交流。 contact_missing: 未設定 contact_unavailable: 未公開 - hosted_on: 在 %{domain} 運作的 Mastodon 站點 + hosted_on: 於 %{domain} 託管之 Mastodon 站點 title: 關於本站 accounts: follow: 跟隨 @@ -13,7 +13,7 @@ zh-TW: following: 正在跟隨 instance_actor_flash: 此帳號是用來代表此伺服器的虛擬執行者,而非個別使用者。它的用途為維繫聯邦宇宙,且不應被停權。 last_active: 上次活躍時間 - link_verified_on: 此連結的所有權已在 %{date} 檢查過 + link_verified_on: 此連結之所有權已於 %{date} 檢查過 nothing_here: 暫時沒有內容可供顯示! pin_errors: following: 您只能推薦您正在跟隨的使用者。 @@ -115,7 +115,7 @@ zh-TW: reject: 拒絕 rejected_msg: 已成功婉拒 %{username} 的新帳號申請 remote_suspension_irreversible: 此帳號之資料已被不可逆地刪除。 - remote_suspension_reversible_hint_html: 這個帳號已於此伺服器被停權,所有資料將會於 %{date} 被刪除。在此之前,遠端伺服器可以完全回復此的帳號。如果您想即時刪除這個帳號的資料,您可以在下面進行操作。 + remote_suspension_reversible_hint_html: 這個帳號已於此伺服器被停權,所有資料將會於 %{date} 被刪除。於此之前,遠端伺服器可以完全回復此的帳號。如果您想即時刪除這個帳號的資料,您能於下面進行操作。 remove_avatar: 取消大頭貼 remove_header: 移除開頭 removed_avatar_msg: 已成功刪除 %{username} 的大頭貼 @@ -149,7 +149,7 @@ zh-TW: suspend: 停權 suspended: 已停權 suspension_irreversible: 已永久刪除此帳號的資料。您可以取消這個帳號的停權狀態,但無法還原已刪除的資料。 - suspension_reversible_hint_html: 這個帳號已被暫停,所有數據將於 %{date} 被刪除。在此之前,您可以完全回復您的帳號。如果您想即時刪除這個帳號的數據,您可以在下面進行操作。 + suspension_reversible_hint_html: 這個帳號已被暫停,所有數據將於 %{date} 被刪除。於此之前,您可以完全回復您的帳號。如果您想即時刪除這個帳號的數據,您能於下面進行操作。 title: 帳號 unblock_email: 解除封鎖電子郵件地址 unblocked_email_msg: 成功解除封鎖 %{username} 的電子郵件地址 @@ -333,7 +333,7 @@ zh-TW: not_permitted: 您無權執行此操作 overwrite: 覆蓋 shortcode: 短代碼 - shortcode_hint: 至少 2 個字元,只能使用字母、數字和下劃線 + shortcode_hint: 至少 2 個字元,只能使用字母、數字與下劃線 title: 自訂表情符號 uncategorized: 未分類 unlist: 不公開 @@ -370,10 +370,10 @@ zh-TW: domain_allows: add_new: 將網域加入聯邦宇宙白名單 created_msg: 網域已成功加入聯邦宇宙白名單 - destroyed_msg: 網域已成功從聯邦宇宙白名單移除 + destroyed_msg: 網域已成功自聯邦宇宙白名單移除 export: 匯出 import: 匯入 - undo: 從聯邦宇宙白名單移除 + undo: 自聯邦宇宙白名單移除 domain_blocks: add_new: 新增網域黑名單 confirm_suspension: @@ -397,7 +397,7 @@ zh-TW: create: 新增封鎖 hint: 站點封鎖動作並不會阻止帳號紀錄被新增至資料庫,但會自動回溯性地對那些帳號套用特定管理設定。 severity: - desc_html: "「<strong>靜音</strong>」令該站點下使用者的嘟文,設定為只對跟隨者顯示,沒有跟隨的人會看不到。「<strong>停權</strong>」會刪除將該站點下使用者的嘟文、媒體檔案和個人檔案。「<strong>無</strong>」則會拒絕接收來自該站點的媒體檔案。" + desc_html: "「<strong>靜音</strong>」令該站點下使用者的嘟文,設定為只對跟隨者顯示,沒有跟隨的人會看不到。「<strong>停權</strong>」會刪除將該站點下使用者的嘟文、媒體檔案與個人檔案。「<strong>無</strong>」則會拒絕接收來自該站點的媒體檔案。" noop: 無 silence: 靜音 suspend: 停權 @@ -451,7 +451,7 @@ zh-TW: title: 匯入網域黑名單 no_file: 尚未選擇檔案 follow_recommendations: - description_html: "<strong>跟隨建議幫助新使用者們快速找到有趣的內容</strong>。當使用者沒有與其他帳號有足夠多的互動以建立個人化跟隨建議時,這些帳號將會被推薦。這些帳號將基於某選定語言之高互動和高本地跟隨者數量帳號而每日重新更新。" + description_html: "<strong>跟隨建議幫助新使用者們快速找到有趣的內容</strong>。當使用者沒有與其他帳號有足夠多的互動以建立個人化跟隨建議時,這些帳號將會被推薦。這些帳號將基於某選定語言之高互動與高本地跟隨者數量帳號而每日重新更新。" language: 對於語言 status: 狀態 suppress: 取消跟隨建議 @@ -461,7 +461,7 @@ zh-TW: instances: availability: description_html: - other: 若在<strong>%{count}天</strong>向某個網域遞送失敗,除非收到某個網域的遞送<em>表單</em>,否則不會繼續嘗試遞送。 + other: 若於 <strong>%{count} 天</strong>向某個網域遞送失敗,除非收到某個網域的遞送<em>表單</em>,否則不會繼續嘗試遞送。 failure_threshold_reached: 錯誤門檻於 %{date}。 failures_recorded: other: 錯誤嘗試於 %{count} 天。 @@ -590,7 +590,7 @@ zh-TW: by_target_domain: 檢舉帳號之網域 cancel: 取消 category: 分類 - category_description_html: 此帳號及/或被檢舉內容之原因會被引用在檢舉帳號通知中 + category_description_html: 此帳號及/或被檢舉內容之原因將被引用於檢舉帳號通知中 comment: none: 無 comment_description_html: 提供更多資訊,%{name} 寫道: @@ -611,7 +611,7 @@ zh-TW: delete: 刪除 placeholder: 記錄已執行的動作,或其他相關的更新... title: 備註 - notes_description_html: 檢視及留下些給其他管理員和未來的自己的備註 + notes_description_html: 檢視及留下些給其他管理員與未來的自己的備註 processed_msg: '檢舉報告 #%{id} 已被成功處理' quick_actions_description_html: 採取一個快速行動,或者下捲以檢視檢舉內容: remote_user_placeholder: 來自 %{instance} 之遠端使用者 @@ -624,7 +624,7 @@ zh-TW: skip_to_actions: 跳過行動 status: 嘟文 statuses: 被檢舉的內容 - statuses_description_html: 侵犯性違規內容會被引用在檢舉帳號通知中 + statuses_description_html: 侵犯性違規內容將被引用於檢舉帳號通知中 summary: action_preambles: delete_html: 您將要 <strong>移除</strong> 某些 <strong>@%{acct}</strong> 之嘟文。此將會: @@ -677,7 +677,7 @@ zh-TW: manage_announcements: 管理公告 manage_announcements_description: 允許使用者管理伺服器上的公告 manage_appeals: 管理解封申訴系統 - manage_appeals_description: 允許使用者審閱針對站務動作的申訴 + manage_appeals_description: 允許使用者審閱針對站務動作之申訴 manage_blocks: 管理封鎖 manage_blocks_description: 允許使用者封鎖電子郵件提供者與 IP 位置 manage_custom_emojis: 管理自訂表情符號 @@ -741,7 +741,7 @@ zh-TW: title: 預設將使用者排除於搜尋引擎索引 discovery: follow_recommendations: 跟隨建議 - preamble: 呈現有趣的內容有助於 Mastodon 上一人不識的新手上路。控制各種不同的分類在您伺服器上如何被探索到。 + preamble: 呈現有趣的內容有助於 Mastodon 上一人不識的新手上路。控制各種不同的分類於您伺服器上如何被探索到。 profile_directory: 個人檔案目錄 public_timelines: 公開時間軸 publish_discovered_servers: 公開已知伺服器列表 @@ -989,11 +989,11 @@ zh-TW: created_msg: 成功建立別名。您可以自舊帳號開始轉移。 deleted_msg: 成功移除別名。您將無法再由舊帳號轉移至目前的帳號。 empty: 您目前沒有任何別名。 - hint_html: 如果想由其他帳號轉移至此帳號,您可以於此處新增別名,稍後系統將容許您將跟隨者由舊帳號轉移至此。此項作業是<strong>無害且可復原的</strong>。 <strong>帳號的遷移程序需要在舊帳號啟動</strong>。 + hint_html: 如果想由其他帳號轉移至此帳號,您能於此處新增別名,稍後系統將容許您將跟隨者由舊帳號轉移至此。此項作業是<strong>無害且可復原的</strong>。 <strong>帳號的遷移程序需要於舊帳號啟動</strong>。 remove: 取消連結別名 appearance: advanced_web_interface: 進階網頁介面 - advanced_web_interface_hint: 進階網頁介面可讓您設定許多不同的欄位來善用螢幕空間,依需要同時查看許多不同的資訊如:首頁、通知、聯邦宇宙時間軸、任意數量的列表和主題標籤。 + advanced_web_interface_hint: 進階網頁介面可讓您設定許多不同的欄位來善用螢幕空間,依需要同時查看許多不同的資訊如:首頁、通知、聯邦宇宙時間軸、任意數量的列表與主題標籤。 animations_and_accessibility: 動畫與無障礙設定 confirmation_dialogs: 確認對話框 discovery: 探索 @@ -1033,13 +1033,13 @@ zh-TW: redirect_to_app_html: 您應被重新導向至 <strong>%{app_name}</strong> 應用程式。如尚未重新導向,請嘗試 %{clicking_this_link} 或手動回到應用程式。 registration_complete: 您於 %{domain} 之註冊申請已完成! welcome_title: 歡迎,%{name}! - wrong_email_hint: 若電子郵件地址不正確,您可以於帳號設定中更改。 + wrong_email_hint: 若電子郵件地址不正確,您能於帳號設定中更改。 delete_account: 刪除帳號 delete_account_html: 如果您欲刪除您的帳號,請<a href="%{path}">點擊這裡繼續</a>。您需要再三確認您的操作。 description: prefix_invited_by_user: "@%{name} 邀請您加入這個 Mastodon 伺服器!" prefix_sign_up: 馬上註冊 Mastodon 帳號吧! - suffix: 有了帳號,就可以從任何 Mastodon 伺服器跟隨任何人、發發廢嘟,並且與任何 Mastodon 伺服器的使用者交流,以及更多! + suffix: 有了帳號,就可以自任何 Mastodon 伺服器跟隨任何人、發發廢嘟,並且與任何 Mastodon 伺服器的使用者交流,以及更多! didnt_get_confirmation: 沒有收到確認連結嗎? dont_have_your_security_key: 找不到您的安全金鑰? forgot_password: 忘記密碼? @@ -1085,7 +1085,7 @@ zh-TW: preamble_html: 請使用您於 <strong>%{domain}</strong> 的帳號密碼登入。若您的帳號託管於其他伺服器,您將無法於此登入。 title: 登入 %{domain} sign_up: - manual_review: "%{domain} 上的註冊由我們的管理員進行人工審核。為協助我們處理您的註冊,請寫一些關於您自己的資訊以及您想要在 %{domain} 上註冊帳號的原因。" + manual_review: "%{domain} 上的註冊由我們的管理員進行人工審核。為協助我們處理您的註冊,請寫一些關於您自己的資訊以及您欲於 %{domain} 上註冊帳號之原因。" preamble: 於此 Mastodon 伺服器擁有帳號的話,您將能跟隨聯邦宇宙網路中任何一份子,無論他們的帳號託管於何處。 title: 讓我們一起設定 %{domain} 吧! status: @@ -1100,7 +1100,7 @@ zh-TW: use_security_key: 使用安全金鑰 challenge: confirm: 繼續 - hint_html: "<strong>温馨小提醒:</strong> 我們在接下來一小時內不會再要求您輸入密碼。" + hint_html: "<strong>温馨小提醒:</strong> 我們於接下來一小時內不會再要求您輸入密碼。" invalid_password: 密碼錯誤 prompt: 輸入密碼以繼續 crypto: @@ -1134,8 +1134,8 @@ zh-TW: warning: before: 在進行下一步驟之前,請詳細閱讀以下説明: caches: 已被其他節點快取的內容可能會殘留其中 - data_removal: 您的嘟文和其他資料將會被永久刪除 - email_change_html: 您可以在不刪除帳號的情況下<a href="%{path}">變更您的電子郵件地址</a> + data_removal: 您的嘟文與其他資料將被永久刪除 + email_change_html: 您能於不刪除帳號的情況下<a href="%{path}">變更您的電子郵件地址</a> email_contact_html: 如果您仍然沒有收到郵件,請寄信至 <a href="mailto:%{email}">%{email}</a> 以獲得協助 email_reconfirmation_html: 如果您沒有收到確認郵件,可以<a href="%{path}">請求再次發送</a> irreversible: 您將無法復原或重新啟用您的帳號 @@ -1176,7 +1176,7 @@ zh-TW: invalid_domain: 並非一個有效網域 edit_profile: basic_information: 基本資訊 - hint_html: "<strong>自訂人們可以於您個人檔案及嘟文內容。</strong>當您完成填寫個人檔案以及設定大頭貼後,其他人們比較願意跟隨您並與您互動。" + hint_html: "<strong>自訂人們能於您個人檔案及嘟文旁所見之內容。</strong>當您完成填寫個人檔案以及設定大頭貼後,其他人們比較願意跟隨您並與您互動。" other: 其他 errors: '400': 您所送出的請求無效或格式不正確。 @@ -1194,13 +1194,13 @@ zh-TW: '503': 此頁面因伺服器暫時發生錯誤而無法提供。 noscript_html: 使用 Mastodon 網頁版應用需要啟用 JavaScript。您也可以選擇適用於您的平台的 <a href="%{apps_path}">Mastodon 應用</a>。 existing_username_validator: - not_found: 無法在本站找到這個名稱的使用者 + not_found: 無法於本伺服器找到此使用者帳號 not_found_multiple: 揣嘸 %{usernames} exports: archive_takeout: date: 日期 download: 下載檔案 - hint_html: 您可以下載包含您的<strong>文章和媒體</strong>的檔案。資料以 ActivityPub 格式儲存,可用於相容的軟體。每次允許存檔的間隔至少 7 天。 + hint_html: 您可以下載包含您的<strong>嘟文與媒體</strong>的檔案。資料以 ActivityPub 格式儲存,可用於相容之軟體。每次允許存檔的間隔至少 7 天。 in_progress: 正在準備您的存檔... request: 下載存檔 size: 大小 @@ -1304,7 +1304,7 @@ zh-TW: following_html: 您將要 <strong>跟隨</strong> 自 <strong>%{filename}</strong> 中之 <strong>%{total_items} 個帳號</strong>。 lists_html: 您將自 <strong>%{filename}</strong> 新增 <strong>%{total_items} 個帳號</strong>至您的<strong>列表</strong>。若不存在列表用以新增帳號,則會建立新列表。 muting_html: 您將要 <strong>靜音</strong> 自 <strong>%{filename}</strong> 中之 <strong>%{total_items} 個帳號</strong>。 - preface: 您能於此匯入您在其他伺服器所匯出的資料檔,包括跟隨中的使用者、封鎖的使用者名單等。 + preface: 您能於此匯入您於其他伺服器所匯出的資料檔,包括跟隨中的使用者、封鎖的使用者名單等。 recent_imports: 最近匯入的 states: finished: 已完成 @@ -1414,12 +1414,12 @@ zh-TW: warning: backreference_required: 新的帳號必須先設定為反向參照到目前帳號 before: 在進行下一步驟之前,請詳細閱讀以下説明: - cooldown: 在轉移帳號後會有一段等待時間,在等待時間內您將無法再次轉移 + cooldown: 轉移帳號後會有一段等待時間,等待時間內您將無法再次轉移 disabled_account: 之後您的目前帳號將完全無法使用。但您可以存取資料匯出與重新啟用。 followers: 此動作將會將目前帳號的所有跟隨者轉移至新帳號 - only_redirect_html: 或者,您也可以<a href="%{path}">僅在您的個人檔案中設定重新導向</a>。 + only_redirect_html: 或者,您也可以<a href="%{path}">僅於您的個人檔案中設定重新導向</a>。 other_data: 其他資料並不會自動轉移 - redirect: 您目前的帳號將於個人檔案頁面新增重新導向公告,並會被排除在搜尋結果之外 + redirect: 您目前的帳號將於個人檔案頁面新增重新導向公告,並會被排除於搜尋結果之外 moderation: title: 站務 move_handler: @@ -1449,8 +1449,8 @@ zh-TW: title: 新的跟隨請求 mention: action: 回覆 - body: "%{name} 在嘟文中提及您:" - subject: "%{name} 在嘟文中提及您" + body: "%{name} 於嘟文中提及您:" + subject: "%{name} 於嘟文中提及您" title: 新的提及 poll: subject: 由 %{name} 發起的投票已結束 @@ -1510,7 +1510,7 @@ zh-TW: privacy: hint_html: "<strong>自訂您希望如何讓您的個人檔案及嘟文被發現。</strong>藉由啟用一系列 Mastodon 功能以幫助您觸及更廣的受眾。煩請花些時間確認您是否欲啟用這些設定。" privacy: 隱私權 - privacy_hint_html: 控制您希望向其他人揭露之內容。人們透過瀏覽其他人的跟隨者與其發嘟之應用程式發現有趣的個人檔案和酷炫的 Mastodon 應用程式,但您能選擇將其隱藏。 + privacy_hint_html: 控制您希望向其他人揭露之內容。人們透過瀏覽其他人的跟隨者與其發嘟之應用程式發現有趣的個人檔案與酷炫的 Mastodon 應用程式,但您能選擇將其隱藏。 reach: 觸及 reach_hint_html: 控制您希望被新使用者探索或跟隨之方式。想讓您的嘟文出現於探索頁面嗎?想讓其他人透過他們的跟隨建議找到您嗎?想自動接受所有新跟隨者嗎?或是想逐一控制跟隨請求嗎? search: 搜尋 @@ -1669,7 +1669,7 @@ zh-TW: private_long: 只有跟隨您的人能看到 public: 公開 public_long: 所有人都能看到 - unlisted: 不在公開時間軸顯示 + unlisted: 不於公開時間軸顯示 unlisted_long: 所有人都能看到,但不會出現在公開時間軸上 statuses_cleanup: enabled: 自動刪除舊嘟文 @@ -1679,7 +1679,7 @@ zh-TW: ignore_favs: 忽略最愛數 ignore_reblogs: 忽略轉嘟數 interaction_exceptions: 基於互動的例外規則 - interaction_exceptions_explanation: 請注意嘟文是無法保證被刪除的,如果在一次處理過後嘟文低於最愛或轉嘟的門檻。 + interaction_exceptions_explanation: 請注意嘟文是無法保證被刪除的,如果於一次處理過後嘟文低於最愛或轉嘟的門檻。 keep_direct: 保留私訊 keep_direct_hint: 不會刪除任何您的私訊 keep_media: 保留包含多媒體附加檔案之嘟文 @@ -1735,7 +1735,7 @@ zh-TW: enabled: 兩階段認證已啟用 enabled_success: 已成功啟用兩階段認證 generate_recovery_codes: 產生備用驗證碼 - lost_recovery_codes: 讓您可以在遺失手機時,使用備用驗證碼登入。若您已遺失備用驗證碼,可於此產生一批新的,舊有的備用驗證碼將會失效。 + lost_recovery_codes: 讓您能於遺失手機時,使用備用驗證碼登入。若您已遺失備用驗證碼,可於此產生一批新的,舊有的備用驗證碼將會失效。 methods: 兩步驟方式 otp: 驗證應用程式 recovery_codes: 備份備用驗證碼 @@ -1745,12 +1745,12 @@ zh-TW: user_mailer: appeal_approved: action: 前往您的帳號 - explanation: 您在 %{appeal_date} 遞交的針對您帳號的 %{strike_date} 警示的申訴已獲批准。您的帳號再次享有良好的信譽。 - subject: 您在 %{date} 提出的申訴已獲批准 + explanation: 您於 %{appeal_date} 遞交的針對您帳號的 %{strike_date} 警示之申訴已獲批准。您的帳號再次享有良好的信譽。 + subject: 您於 %{date} 提出之申訴已獲批准 title: 申訴已批准 appeal_rejected: - explanation: 您在 %{appeal_date} 遞交的針對您帳號的 %{strike_date} 警示的申訴已被駁回。 - subject: 您在 %{date} 提出的申訴已被駁回 + explanation: 您於 %{appeal_date} 遞交的針對您帳號的 %{strike_date} 警示之申訴已被駁回。 + subject: 您於 %{date} 提出之申訴已被駁回 title: 申訴被駁回 backup_ready: explanation: 您要求的 Mastodon 帳號完整備份檔案現已就緒,可供下載! @@ -1772,7 +1772,7 @@ zh-TW: explanation: delete_statuses: 您的某些嘟文被發現已違反一項或多項社群準則,隨後已被 %{instance} 的管理員刪除。 disable: 您無法繼續使用您的帳號,但您的個人頁面及其他資料內容保持不變。您可以要求一份您的資料備份,帳號異動設定,或是刪除帳號。 - mark_statuses_as_sensitive: 您的部份嘟文已被 %{instance} 的管理員標記為敏感內容。這代表了人們必須在顯示預覽前點擊嘟文中的媒體。您可以在將來嘟文時自己將媒體標記為敏感內容。 + mark_statuses_as_sensitive: 您的部份嘟文已被 %{instance} 的管理員標記為敏感內容。這代表了人們必須於顯示預覽前點擊嘟文中的媒體。您能於將來嘟文時自己將媒體標記為敏感內容。 sensitive: 由此刻起,您所有上傳的媒體檔案將被標記為敏感內容,並且隱藏於點擊警告之後。 silence: 您仍然能使用您的帳號,但僅有已跟隨您的人才能見到您於此伺服器之嘟文,您也可能會從各式探索功能中被排除。但其他人仍可手動跟隨您。 suspend: 您將不能使用您的帳號,您的個人檔案頁面及其他資料將不再能被存取。您仍可於約 30 日內資料被完全刪除前要求下載您的資料,但我們仍會保留一部份基本資料,以防止有人規避停權處罰。 @@ -1781,9 +1781,9 @@ zh-TW: subject: delete_statuses: 您於 %{acct} 之嘟文已被移除 disable: 您的帳號 %{acct} 已被凍結 - mark_statuses_as_sensitive: 您在 %{acct} 上的嘟文已被標記為敏感內容 + mark_statuses_as_sensitive: 您於 %{acct} 上的嘟文已被標記為敏感內容 none: 對 %{acct} 的警告 - sensitive: 從現在開始,您在 %{acct} 上的嘟文將會被標記為敏感內容 + sensitive: 從現在開始,您於 %{acct} 上之嘟文將會被標記為敏感內容 silence: 您的帳號 %{acct} 已被限制 suspend: 您的帳號 %{acct} 已被停權 title: @@ -1796,10 +1796,10 @@ zh-TW: suspend: 帳號己被停權 welcome: edit_profile_action: 設定個人檔案 - edit_profile_step: 您可以設定您的個人檔案,包括上傳大頭貼、變更顯示名稱等等。您也可以選擇在新的跟隨者跟隨前,先對他們進行審核。 + edit_profile_step: 您可以設定您的個人檔案,包括上傳大頭貼、變更顯示名稱等等。您也可以選擇於新的跟隨者跟隨前,先對他們進行審核。 explanation: 下面是幾個小幫助,希望它們能幫到您 final_action: 開始嘟嘟 - final_step: '開始嘟嘟吧!即使您現在沒有跟隨者,其他人仍然能在本站時間軸、主題標籤等地方,看到您的公開嘟文。試著用 #introductions 這個主題標籤介紹一下自己吧。' + final_step: '開始嘟嘟吧!即使您現在沒有跟隨者,其他人仍然能於本站時間軸、主題標籤等地方,看到您的公開嘟文。試著用 #introductions 這個主題標籤介紹一下自己吧。' full_handle: 您的完整帳號名稱 full_handle_hint: 您需要將這告訴您的朋友們,這樣他們就能從另一個伺服器向您發送訊息或跟隨您。 subject: 歡迎來到 Mastodon From d67bd44ca1542d665354e733b632c841b6b7d29b Mon Sep 17 00:00:00 2001 From: Eugen Rochko <eugen@zeonfederated.com> Date: Wed, 15 Nov 2023 12:13:53 +0100 Subject: [PATCH 042/255] Add profile setup to onboarding in web UI (#27829) --- .../api/v1/accounts/credentials_controller.rb | 2 + app/javascript/mastodon/actions/accounts.js | 15 ++ app/javascript/mastodon/api_types/accounts.ts | 1 + .../mastodon/components/admin/Retention.jsx | 2 +- .../mastodon/components/loading_indicator.tsx | 26 ++- .../components/progress_indicator.jsx | 29 --- .../features/onboarding/components/step.jsx | 15 +- .../mastodon/features/onboarding/follows.jsx | 105 ++++------ .../mastodon/features/onboarding/index.jsx | 190 ++++++------------ .../mastodon/features/onboarding/profile.jsx | 162 +++++++++++++++ .../mastodon/features/onboarding/share.jsx | 100 ++++----- app/javascript/mastodon/features/ui/index.jsx | 2 +- app/javascript/mastodon/locales/en.json | 13 +- app/javascript/mastodon/models/account.ts | 1 + .../styles/mastodon/components.scss | 164 +++++---------- app/javascript/styles/mastodon/forms.scss | 105 ++++++++-- app/serializers/rest/account_serializer.rb | 6 +- config/routes.rb | 2 +- 18 files changed, 524 insertions(+), 416 deletions(-) delete mode 100644 app/javascript/mastodon/features/onboarding/components/progress_indicator.jsx create mode 100644 app/javascript/mastodon/features/onboarding/profile.jsx diff --git a/app/controllers/api/v1/accounts/credentials_controller.rb b/app/controllers/api/v1/accounts/credentials_controller.rb index 76ba75824..8f31336b9 100644 --- a/app/controllers/api/v1/accounts/credentials_controller.rb +++ b/app/controllers/api/v1/accounts/credentials_controller.rb @@ -16,6 +16,8 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController current_user.update(user_params) if user_params ActivityPub::UpdateDistributionWorker.perform_async(@account.id) render json: @account, serializer: REST::CredentialAccountSerializer + rescue ActiveRecord::RecordInvalid => e + render json: ValidationErrorFormatter.new(e).as_json, status: 422 end private diff --git a/app/javascript/mastodon/actions/accounts.js b/app/javascript/mastodon/actions/accounts.js index e0448f004..9f3bbba03 100644 --- a/app/javascript/mastodon/actions/accounts.js +++ b/app/javascript/mastodon/actions/accounts.js @@ -661,3 +661,18 @@ export function unpinAccountFail(error) { error, }; } + +export const updateAccount = ({ displayName, note, avatar, header, discoverable, indexable }) => (dispatch, getState) => { + const data = new FormData(); + + data.append('display_name', displayName); + data.append('note', note); + if (avatar) data.append('avatar', avatar); + if (header) data.append('header', header); + data.append('discoverable', discoverable); + data.append('indexable', indexable); + + return api(getState).patch('/api/v1/accounts/update_credentials', data).then(response => { + dispatch(importFetchedAccount(response.data)); + }); +}; diff --git a/app/javascript/mastodon/api_types/accounts.ts b/app/javascript/mastodon/api_types/accounts.ts index 985abf946..5bf3e6428 100644 --- a/app/javascript/mastodon/api_types/accounts.ts +++ b/app/javascript/mastodon/api_types/accounts.ts @@ -20,6 +20,7 @@ export interface ApiAccountJSON { bot: boolean; created_at: string; discoverable: boolean; + indexable: boolean; display_name: string; emojis: ApiCustomEmojiJSON[]; fields: ApiAccountFieldJSON[]; diff --git a/app/javascript/mastodon/components/admin/Retention.jsx b/app/javascript/mastodon/components/admin/Retention.jsx index 2f5671068..1e8ef48b7 100644 --- a/app/javascript/mastodon/components/admin/Retention.jsx +++ b/app/javascript/mastodon/components/admin/Retention.jsx @@ -51,7 +51,7 @@ export default class Retention extends PureComponent { let content; if (loading) { - content = <FormattedMessage id='loading_indicator.label' defaultMessage='Loading...' />; + content = <FormattedMessage id='loading_indicator.label' defaultMessage='Loading…' />; } else { content = ( <table className='retention__table'> diff --git a/app/javascript/mastodon/components/loading_indicator.tsx b/app/javascript/mastodon/components/loading_indicator.tsx index 6bc24a0d6..fcdbe80d8 100644 --- a/app/javascript/mastodon/components/loading_indicator.tsx +++ b/app/javascript/mastodon/components/loading_indicator.tsx @@ -1,7 +1,23 @@ +import { useIntl, defineMessages } from 'react-intl'; + import { CircularProgress } from './circular_progress'; -export const LoadingIndicator: React.FC = () => ( - <div className='loading-indicator'> - <CircularProgress size={50} strokeWidth={6} /> - </div> -); +const messages = defineMessages({ + loading: { id: 'loading_indicator.label', defaultMessage: 'Loading…' }, +}); + +export const LoadingIndicator: React.FC = () => { + const intl = useIntl(); + + return ( + <div + className='loading-indicator' + role='progressbar' + aria-busy + aria-live='polite' + aria-label={intl.formatMessage(messages.loading)} + > + <CircularProgress size={50} strokeWidth={6} /> + </div> + ); +}; diff --git a/app/javascript/mastodon/features/onboarding/components/progress_indicator.jsx b/app/javascript/mastodon/features/onboarding/components/progress_indicator.jsx deleted file mode 100644 index 37288a286..000000000 --- a/app/javascript/mastodon/features/onboarding/components/progress_indicator.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import PropTypes from 'prop-types'; -import { Fragment } from 'react'; - -import classNames from 'classnames'; - -import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/done.svg'; - -import { Icon } from 'mastodon/components/icon'; - -const ProgressIndicator = ({ steps, completed }) => ( - <div className='onboarding__progress-indicator'> - {(new Array(steps)).fill().map((_, i) => ( - <Fragment key={i}> - {i > 0 && <div className={classNames('onboarding__progress-indicator__line', { active: completed > i })} />} - - <div className={classNames('onboarding__progress-indicator__step', { active: completed > i })}> - {completed > i && <Icon icon={CheckIcon} />} - </div> - </Fragment> - ))} - </div> -); - -ProgressIndicator.propTypes = { - steps: PropTypes.number.isRequired, - completed: PropTypes.number, -}; - -export default ProgressIndicator; diff --git a/app/javascript/mastodon/features/onboarding/components/step.jsx b/app/javascript/mastodon/features/onboarding/components/step.jsx index 1f42d9d49..1f83f2080 100644 --- a/app/javascript/mastodon/features/onboarding/components/step.jsx +++ b/app/javascript/mastodon/features/onboarding/components/step.jsx @@ -1,11 +1,13 @@ import PropTypes from 'prop-types'; +import { Link } from 'react-router-dom'; + import { ReactComponent as ArrowRightAltIcon } from '@material-symbols/svg-600/outlined/arrow_right_alt.svg'; import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/done.svg'; -import { Icon } from 'mastodon/components/icon'; +import { Icon } from 'mastodon/components/icon'; -const Step = ({ label, description, icon, iconComponent, completed, onClick, href }) => { +export const Step = ({ label, description, icon, iconComponent, completed, onClick, href, to }) => { const content = ( <> <div className='onboarding__steps__item__icon'> @@ -29,6 +31,12 @@ const Step = ({ label, description, icon, iconComponent, completed, onClick, hre {content} </a> ); + } else if (to) { + return ( + <Link to={to} className='onboarding__steps__item'> + {content} + </Link> + ); } return ( @@ -45,7 +53,6 @@ Step.propTypes = { iconComponent: PropTypes.func, completed: PropTypes.bool, href: PropTypes.string, + to: PropTypes.string, onClick: PropTypes.func, }; - -export default Step; diff --git a/app/javascript/mastodon/features/onboarding/follows.jsx b/app/javascript/mastodon/features/onboarding/follows.jsx index e21c7c75b..e23a335c0 100644 --- a/app/javascript/mastodon/features/onboarding/follows.jsx +++ b/app/javascript/mastodon/features/onboarding/follows.jsx @@ -1,79 +1,62 @@ -import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; +import { useEffect } from 'react'; import { FormattedMessage } from 'react-intl'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { connect } from 'react-redux'; +import { Link } from 'react-router-dom'; + +import { useDispatch } from 'react-redux'; + import { fetchSuggestions } from 'mastodon/actions/suggestions'; import { markAsPartial } from 'mastodon/actions/timelines'; -import Column from 'mastodon/components/column'; import { ColumnBackButton } from 'mastodon/components/column_back_button'; import { EmptyAccount } from 'mastodon/components/empty_account'; import Account from 'mastodon/containers/account_container'; +import { useAppSelector } from 'mastodon/store'; -const mapStateToProps = state => ({ - suggestions: state.getIn(['suggestions', 'items']), - isLoading: state.getIn(['suggestions', 'isLoading']), -}); +export const Follows = () => { + const dispatch = useDispatch(); + const isLoading = useAppSelector(state => state.getIn(['suggestions', 'isLoading'])); + const suggestions = useAppSelector(state => state.getIn(['suggestions', 'items'])); -class Follows extends PureComponent { - - static propTypes = { - onBack: PropTypes.func, - dispatch: PropTypes.func.isRequired, - suggestions: ImmutablePropTypes.list, - isLoading: PropTypes.bool, - }; - - componentDidMount () { - const { dispatch } = this.props; + useEffect(() => { dispatch(fetchSuggestions(true)); + + return () => { + dispatch(markAsPartial('home')); + }; + }, [dispatch]); + + let loadedContent; + + if (isLoading) { + loadedContent = (new Array(8)).fill().map((_, i) => <EmptyAccount key={i} />); + } else if (suggestions.isEmpty()) { + loadedContent = <div className='follow-recommendations__empty'><FormattedMessage id='onboarding.follows.empty' defaultMessage='Unfortunately, no results can be shown right now. You can try using search or browsing the explore page to find people to follow, or try again later.' /></div>; + } else { + loadedContent = suggestions.map(suggestion => <Account id={suggestion.get('account')} key={suggestion.get('account')} withBio />); } - componentWillUnmount () { - const { dispatch } = this.props; - dispatch(markAsPartial('home')); - } + return ( + <> + <ColumnBackButton /> - render () { - const { onBack, isLoading, suggestions } = this.props; - - let loadedContent; - - if (isLoading) { - loadedContent = (new Array(8)).fill().map((_, i) => <EmptyAccount key={i} />); - } else if (suggestions.isEmpty()) { - loadedContent = <div className='follow-recommendations__empty'><FormattedMessage id='onboarding.follows.empty' defaultMessage='Unfortunately, no results can be shown right now. You can try using search or browsing the explore page to find people to follow, or try again later.' /></div>; - } else { - loadedContent = suggestions.map(suggestion => <Account id={suggestion.get('account')} key={suggestion.get('account')} withBio />); - } - - return ( - <Column> - <ColumnBackButton onClick={onBack} /> - - <div className='scrollable privacy-policy'> - <div className='column-title'> - <h3><FormattedMessage id='onboarding.follows.title' defaultMessage='Popular on Mastodon' /></h3> - <p><FormattedMessage id='onboarding.follows.lead' defaultMessage='You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!' /></p> - </div> - - <div className='follow-recommendations'> - {loadedContent} - </div> - - <p className='onboarding__lead'><FormattedMessage id='onboarding.tips.accounts_from_other_servers' defaultMessage='<strong>Did you know?</strong> Since Mastodon is decentralized, some profiles you come across will be hosted on servers other than yours. And yet you can interact with them seamlessly! Their server is in the second half of their username!' values={{ strong: chunks => <strong>{chunks}</strong> }} /></p> - - <div className='onboarding__footer'> - <button className='link-button' onClick={onBack}><FormattedMessage id='onboarding.actions.back' defaultMessage='Take me back' /></button> - </div> + <div className='scrollable privacy-policy'> + <div className='column-title'> + <h3><FormattedMessage id='onboarding.follows.title' defaultMessage='Popular on Mastodon' /></h3> + <p><FormattedMessage id='onboarding.follows.lead' defaultMessage='You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!' /></p> </div> - </Column> - ); - } -} + <div className='follow-recommendations'> + {loadedContent} + </div> -export default connect(mapStateToProps)(Follows); + <p className='onboarding__lead'><FormattedMessage id='onboarding.tips.accounts_from_other_servers' defaultMessage='<strong>Did you know?</strong> Since Mastodon is decentralized, some profiles you come across will be hosted on servers other than yours. And yet you can interact with them seamlessly! Their server is in the second half of their username!' values={{ strong: chunks => <strong>{chunks}</strong> }} /></p> + + <div className='onboarding__footer'> + <Link className='link-button' to='/start'><FormattedMessage id='onboarding.actions.back' defaultMessage='Take me back' /></Link> + </div> + </div> + </> + ); +}; diff --git a/app/javascript/mastodon/features/onboarding/index.jsx b/app/javascript/mastodon/features/onboarding/index.jsx index 51d4b71f2..51677fbc7 100644 --- a/app/javascript/mastodon/features/onboarding/index.jsx +++ b/app/javascript/mastodon/features/onboarding/index.jsx @@ -1,152 +1,90 @@ -import PropTypes from 'prop-types'; +import { useCallback } from 'react'; -import { FormattedMessage, injectIntl, defineMessages } from 'react-intl'; +import { FormattedMessage, useIntl, defineMessages } from 'react-intl'; import { Helmet } from 'react-helmet'; -import { Link, withRouter } from 'react-router-dom'; +import { Link, Switch, Route, useHistory } from 'react-router-dom'; + +import { useDispatch } from 'react-redux'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { connect } from 'react-redux'; import { ReactComponent as AccountCircleIcon } from '@material-symbols/svg-600/outlined/account_circle.svg'; import { ReactComponent as ArrowRightAltIcon } from '@material-symbols/svg-600/outlined/arrow_right_alt.svg'; import { ReactComponent as ContentCopyIcon } from '@material-symbols/svg-600/outlined/content_copy.svg'; import { ReactComponent as EditNoteIcon } from '@material-symbols/svg-600/outlined/edit_note.svg'; import { ReactComponent as PersonAddIcon } from '@material-symbols/svg-600/outlined/person_add.svg'; -import { debounce } from 'lodash'; import illustration from 'mastodon/../images/elephant_ui_conversation.svg'; -import { fetchAccount } from 'mastodon/actions/accounts'; import { focusCompose } from 'mastodon/actions/compose'; -import { closeOnboarding } from 'mastodon/actions/onboarding'; import { Icon } from 'mastodon/components/icon'; import Column from 'mastodon/features/ui/components/column'; import { me } from 'mastodon/initial_state'; -import { makeGetAccount } from 'mastodon/selectors'; +import { useAppSelector } from 'mastodon/store'; import { assetHost } from 'mastodon/utils/config'; -import { WithRouterPropTypes } from 'mastodon/utils/react_router'; -import Step from './components/step'; -import Follows from './follows'; -import Share from './share'; +import { Step } from './components/step'; +import { Follows } from './follows'; +import { Profile } from './profile'; +import { Share } from './share'; const messages = defineMessages({ template: { id: 'onboarding.compose.template', defaultMessage: 'Hello #Mastodon!' }, }); -const mapStateToProps = () => { - const getAccount = makeGetAccount(); +const Onboarding = () => { + const account = useAppSelector(state => state.getIn(['accounts', me])); + const dispatch = useDispatch(); + const intl = useIntl(); + const history = useHistory(); - return state => ({ - account: getAccount(state, me), - }); + const handleComposeClick = useCallback(() => { + dispatch(focusCompose(history, intl.formatMessage(messages.template))); + }, [dispatch, intl, history]); + + return ( + <Column> + <Switch> + <Route path='/start' exact> + <div className='scrollable privacy-policy'> + <div className='column-title'> + <img src={illustration} alt='' className='onboarding__illustration' /> + <h3><FormattedMessage id='onboarding.start.title' defaultMessage="You've made it!" /></h3> + <p><FormattedMessage id='onboarding.start.lead' defaultMessage="Your new Mastodon account is ready to go. Here's how you can make the most of it:" /></p> + </div> + + <div className='onboarding__steps'> + <Step to='/start/profile' completed={(!account.get('avatar').endsWith('missing.png')) || (account.get('display_name').length > 0 && account.get('note').length > 0)} icon='address-book-o' iconComponent={AccountCircleIcon} label={<FormattedMessage id='onboarding.steps.setup_profile.title' defaultMessage='Customize your profile' />} description={<FormattedMessage id='onboarding.steps.setup_profile.body' defaultMessage='Others are more likely to interact with you with a filled out profile.' />} /> + <Step to='/start/follows' completed={(account.get('following_count') * 1) >= 1} icon='user-plus' iconComponent={PersonAddIcon} label={<FormattedMessage id='onboarding.steps.follow_people.title' defaultMessage='Find at least {count, plural, one {one person} other {# people}} to follow' values={{ count: 7 }} />} description={<FormattedMessage id='onboarding.steps.follow_people.body' defaultMessage="You curate your own home feed. Let's fill it with interesting people." />} /> + <Step onClick={handleComposeClick} completed={(account.get('statuses_count') * 1) >= 1} icon='pencil-square-o' iconComponent={EditNoteIcon} label={<FormattedMessage id='onboarding.steps.publish_status.title' defaultMessage='Make your first post' />} description={<FormattedMessage id='onboarding.steps.publish_status.body' defaultMessage='Say hello to the world.' values={{ emoji: <img className='emojione' alt='🐘' src={`${assetHost}/emoji/1f418.svg`} /> }} />} /> + <Step to='/start/share' icon='copy' iconComponent={ContentCopyIcon} label={<FormattedMessage id='onboarding.steps.share_profile.title' defaultMessage='Share your profile' />} description={<FormattedMessage id='onboarding.steps.share_profile.body' defaultMessage='Let your friends know how to find you on Mastodon!' />} /> + </div> + + <p className='onboarding__lead'><FormattedMessage id='onboarding.start.skip' defaultMessage="Don't need help getting started?" /></p> + + <div className='onboarding__links'> + <Link to='/explore' className='onboarding__link'> + <FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' /> + <Icon icon={ArrowRightAltIcon} /> + </Link> + + <Link to='/home' className='onboarding__link'> + <FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' /> + <Icon icon={ArrowRightAltIcon} /> + </Link> + </div> + </div> + </Route> + + <Route path='/start/profile' component={Profile} /> + <Route path='/start/follows' component={Follows} /> + <Route path='/start/share' component={Share} /> + </Switch> + + <Helmet> + <meta name='robots' content='noindex' /> + </Helmet> + </Column> + ); }; -class Onboarding extends ImmutablePureComponent { - static propTypes = { - dispatch: PropTypes.func.isRequired, - account: ImmutablePropTypes.record, - ...WithRouterPropTypes, - }; - - state = { - step: null, - profileClicked: false, - shareClicked: false, - }; - - handleClose = () => { - const { dispatch, history } = this.props; - - dispatch(closeOnboarding()); - history.push('/home'); - }; - - handleProfileClick = () => { - this.setState({ profileClicked: true }); - }; - - handleFollowClick = () => { - this.setState({ step: 'follows' }); - }; - - handleComposeClick = () => { - const { dispatch, intl, history } = this.props; - - dispatch(focusCompose(history, intl.formatMessage(messages.template))); - }; - - handleShareClick = () => { - this.setState({ step: 'share', shareClicked: true }); - }; - - handleBackClick = () => { - this.setState({ step: null }); - }; - - handleWindowFocus = debounce(() => { - const { dispatch, account } = this.props; - dispatch(fetchAccount(account.get('id'))); - }, 1000, { trailing: true }); - - componentDidMount () { - window.addEventListener('focus', this.handleWindowFocus, false); - } - - componentWillUnmount () { - window.removeEventListener('focus', this.handleWindowFocus); - } - - render () { - const { account } = this.props; - const { step, shareClicked } = this.state; - - switch(step) { - case 'follows': - return <Follows onBack={this.handleBackClick} />; - case 'share': - return <Share onBack={this.handleBackClick} />; - } - - return ( - <Column> - <div className='scrollable privacy-policy'> - <div className='column-title'> - <img src={illustration} alt='' className='onboarding__illustration' /> - <h3><FormattedMessage id='onboarding.start.title' defaultMessage="You've made it!" /></h3> - <p><FormattedMessage id='onboarding.start.lead' defaultMessage="Your new Mastodon account is ready to go. Here's how you can make the most of it:" /></p> - </div> - - <div className='onboarding__steps'> - <Step onClick={this.handleProfileClick} href='/settings/profile' completed={(!account.get('avatar').endsWith('missing.png')) || (account.get('display_name').length > 0 && account.get('note').length > 0)} icon='address-book-o' iconComponent={AccountCircleIcon} label={<FormattedMessage id='onboarding.steps.setup_profile.title' defaultMessage='Customize your profile' />} description={<FormattedMessage id='onboarding.steps.setup_profile.body' defaultMessage='Others are more likely to interact with you with a filled out profile.' />} /> - <Step onClick={this.handleFollowClick} completed={(account.get('following_count') * 1) >= 7} icon='user-plus' iconComponent={PersonAddIcon} label={<FormattedMessage id='onboarding.steps.follow_people.title' defaultMessage='Find at least {count, plural, one {one person} other {# people}} to follow' values={{ count: 7 }} />} description={<FormattedMessage id='onboarding.steps.follow_people.body' defaultMessage="You curate your own home feed. Let's fill it with interesting people." />} /> - <Step onClick={this.handleComposeClick} completed={(account.get('statuses_count') * 1) >= 1} icon='pencil-square-o' iconComponent={EditNoteIcon} label={<FormattedMessage id='onboarding.steps.publish_status.title' defaultMessage='Make your first post' />} description={<FormattedMessage id='onboarding.steps.publish_status.body' defaultMessage='Say hello to the world.' values={{ emoji: <img className='emojione' alt='🐘' src={`${assetHost}/emoji/1f418.svg`} /> }} />} /> - <Step onClick={this.handleShareClick} completed={shareClicked} icon='copy' iconComponent={ContentCopyIcon} label={<FormattedMessage id='onboarding.steps.share_profile.title' defaultMessage='Share your profile' />} description={<FormattedMessage id='onboarding.steps.share_profile.body' defaultMessage='Let your friends know how to find you on Mastodon!' />} /> - </div> - - <p className='onboarding__lead'><FormattedMessage id='onboarding.start.skip' defaultMessage="Don't need help getting started?" /></p> - - <div className='onboarding__links'> - <Link to='/explore' className='onboarding__link'> - <FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' /> - <Icon icon={ArrowRightAltIcon} /> - </Link> - - <Link to='/home' className='onboarding__link'> - <FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' /> - <Icon icon={ArrowRightAltIcon} /> - </Link> - </div> - </div> - - <Helmet> - <meta name='robots' content='noindex' /> - </Helmet> - </Column> - ); - } - -} - -export default withRouter(connect(mapStateToProps)(injectIntl(Onboarding))); +export default Onboarding; diff --git a/app/javascript/mastodon/features/onboarding/profile.jsx b/app/javascript/mastodon/features/onboarding/profile.jsx new file mode 100644 index 000000000..19ba0bcb9 --- /dev/null +++ b/app/javascript/mastodon/features/onboarding/profile.jsx @@ -0,0 +1,162 @@ +import { useState, useMemo, useCallback, createRef } from 'react'; + +import { useIntl, defineMessages, FormattedMessage } from 'react-intl'; + +import classNames from 'classnames'; +import { useHistory } from 'react-router-dom'; + +import { useDispatch } from 'react-redux'; + + +import { ReactComponent as AddPhotoAlternateIcon } from '@material-symbols/svg-600/outlined/add_photo_alternate.svg'; +import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.svg'; +import Toggle from 'react-toggle'; + +import { updateAccount } from 'mastodon/actions/accounts'; +import { Button } from 'mastodon/components/button'; +import { ColumnBackButton } from 'mastodon/components/column_back_button'; +import { Icon } from 'mastodon/components/icon'; +import { LoadingIndicator } from 'mastodon/components/loading_indicator'; +import { me } from 'mastodon/initial_state'; +import { useAppSelector } from 'mastodon/store'; +import { unescapeHTML } from 'mastodon/utils/html'; + +const messages = defineMessages({ + uploadHeader: { id: 'onboarding.profile.upload_header', defaultMessage: 'Upload profile header' }, + uploadAvatar: { id: 'onboarding.profile.upload_avatar', defaultMessage: 'Upload profile picture' }, +}); + +export const Profile = () => { + const account = useAppSelector(state => state.getIn(['accounts', me])); + const [displayName, setDisplayName] = useState(account.get('display_name')); + const [note, setNote] = useState(unescapeHTML(account.get('note'))); + const [avatar, setAvatar] = useState(null); + const [header, setHeader] = useState(null); + const [discoverable, setDiscoverable] = useState(account.get('discoverable')); + const [indexable, setIndexable] = useState(account.get('indexable')); + const [isSaving, setIsSaving] = useState(false); + const [errors, setErrors] = useState(); + const avatarFileRef = createRef(); + const headerFileRef = createRef(); + const dispatch = useDispatch(); + const intl = useIntl(); + const history = useHistory(); + + const handleDisplayNameChange = useCallback(e => { + setDisplayName(e.target.value); + }, [setDisplayName]); + + const handleNoteChange = useCallback(e => { + setNote(e.target.value); + }, [setNote]); + + const handleDiscoverableChange = useCallback(e => { + setDiscoverable(e.target.checked); + }, [setDiscoverable]); + + const handleIndexableChange = useCallback(e => { + setIndexable(e.target.checked); + }, [setIndexable]); + + const handleAvatarChange = useCallback(e => { + setAvatar(e.target?.files?.[0]); + }, [setAvatar]); + + const handleHeaderChange = useCallback(e => { + setHeader(e.target?.files?.[0]); + }, [setHeader]); + + const avatarPreview = useMemo(() => avatar ? URL.createObjectURL(avatar) : account.get('avatar'), [avatar, account]); + const headerPreview = useMemo(() => header ? URL.createObjectURL(header) : account.get('header'), [header, account]); + + const handleSubmit = useCallback(() => { + setIsSaving(true); + + dispatch(updateAccount({ + displayName, + note, + avatar, + header, + discoverable, + indexable, + })).then(() => history.push('/start/follows')).catch(err => { + setIsSaving(false); + setErrors(err.response.data.details); + }); + }, [dispatch, displayName, note, avatar, header, discoverable, indexable, history]); + + return ( + <> + <ColumnBackButton /> + + <div className='scrollable privacy-policy'> + <div className='column-title'> + <h3><FormattedMessage id='onboarding.profile.title' defaultMessage='Profile setup' /></h3> + <p><FormattedMessage id='onboarding.profile.lead' defaultMessage='You can always complete this later in the settings, where even more customization options are available.' /></p> + </div> + + <div className='simple_form'> + <div className='onboarding__profile'> + <label className={classNames('app-form__header-input', { selected: !!headerPreview, invalid: !!errors?.header })} title={intl.formatMessage(messages.uploadHeader)}> + <input + type='file' + hidden + ref={headerFileRef} + accept='image/*' + onChange={handleHeaderChange} + /> + + {headerPreview && <img src={headerPreview} alt='' />} + + <Icon icon={headerPreview ? EditIcon : AddPhotoAlternateIcon} /> + </label> + + <label className={classNames('app-form__avatar-input', { selected: !!avatarPreview, invalid: !!errors?.avatar })} title={intl.formatMessage(messages.uploadAvatar)}> + <input + type='file' + hidden + ref={avatarFileRef} + accept='image/*' + onChange={handleAvatarChange} + /> + + {avatarPreview && <img src={avatarPreview} alt='' />} + + <Icon icon={avatarPreview ? EditIcon : AddPhotoAlternateIcon} /> + </label> + </div> + + <div className={classNames('input with_block_label', { field_with_errors: !!errors?.display_name })}> + <label htmlFor='display_name'><FormattedMessage id='onboarding.profile.display_name' defaultMessage='Display name' /></label> + <span className='hint'><FormattedMessage id='onboarding.profile.display_name_hint' defaultMessage='Your full name or your fun name…' /></span> + <div className='label_input'> + <input id='display_name' type='text' value={displayName} onChange={handleDisplayNameChange} maxLength={30} /> + </div> + </div> + + <div className={classNames('input with_block_label', { field_with_errors: !!errors?.note })}> + <label htmlFor='note'><FormattedMessage id='onboarding.profile.note' defaultMessage='Bio' /></label> + <span className='hint'><FormattedMessage id='onboarding.profile.note_hint' defaultMessage='You can @mention other people or #hashtags…' /></span> + <div className='label_input'> + <textarea id='note' value={note} onChange={handleNoteChange} maxLength={500} /> + </div> + </div> + </div> + + <label className='report-dialog-modal__toggle'> + <Toggle checked={discoverable} onChange={handleDiscoverableChange} /> + <FormattedMessage id='onboarding.profile.discoverable' defaultMessage='Feature profile and posts in discovery algorithms' /> + </label> + + <label className='report-dialog-modal__toggle'> + <Toggle checked={indexable} onChange={handleIndexableChange} /> + <FormattedMessage id='onboarding.profile.indexable' defaultMessage='Include public posts in search results' /> + </label> + + <div className='onboarding__footer'> + <Button block onClick={handleSubmit} disabled={isSaving}>{isSaving ? <LoadingIndicator /> : <FormattedMessage id='onboarding.profile.save_and_continue' defaultMessage='Save and continue' />}</Button> + </div> + </div> + </> + ); +}; diff --git a/app/javascript/mastodon/features/onboarding/share.jsx b/app/javascript/mastodon/features/onboarding/share.jsx index 334924422..adc0f9cba 100644 --- a/app/javascript/mastodon/features/onboarding/share.jsx +++ b/app/javascript/mastodon/features/onboarding/share.jsx @@ -1,31 +1,25 @@ import PropTypes from 'prop-types'; import { PureComponent } from 'react'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import classNames from 'classnames'; import { Link } from 'react-router-dom'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { connect } from 'react-redux'; import { ReactComponent as ArrowRightAltIcon } from '@material-symbols/svg-600/outlined/arrow_right_alt.svg'; import { ReactComponent as ContentCopyIcon } from '@material-symbols/svg-600/outlined/content_copy.svg'; import SwipeableViews from 'react-swipeable-views'; -import Column from 'mastodon/components/column'; import { ColumnBackButton } from 'mastodon/components/column_back_button'; import { Icon } from 'mastodon/components/icon'; import { me, domain } from 'mastodon/initial_state'; +import { useAppSelector } from 'mastodon/store'; const messages = defineMessages({ shareableMessage: { id: 'onboarding.share.message', defaultMessage: 'I\'m {username} on #Mastodon! Come follow me at {url}' }, }); -const mapStateToProps = state => ({ - account: state.getIn(['accounts', me]), -}); - class CopyPasteText extends PureComponent { static propTypes = { @@ -141,59 +135,47 @@ class TipCarousel extends PureComponent { } -class Share extends PureComponent { +export const Share = () => { + const account = useAppSelector(state => state.getIn(['accounts', me])); + const intl = useIntl(); + const url = (new URL(`/@${account.get('username')}`, document.baseURI)).href; - static propTypes = { - onBack: PropTypes.func, - account: ImmutablePropTypes.record, - intl: PropTypes.object, - }; + return ( + <> + <ColumnBackButton /> - render () { - const { onBack, account, intl } = this.props; - - const url = (new URL(`/@${account.get('username')}`, document.baseURI)).href; - - return ( - <Column> - <ColumnBackButton onClick={onBack} /> - - <div className='scrollable privacy-policy'> - <div className='column-title'> - <h3><FormattedMessage id='onboarding.share.title' defaultMessage='Share your profile' /></h3> - <p><FormattedMessage id='onboarding.share.lead' defaultMessage='Let people know how they can find you on Mastodon!' /></p> - </div> - - <CopyPasteText value={intl.formatMessage(messages.shareableMessage, { username: `@${account.get('username')}@${domain}`, url })} /> - - <TipCarousel> - <div><p className='onboarding__lead'><FormattedMessage id='onboarding.tips.verification' defaultMessage='<strong>Did you know?</strong> You can verify your account by putting a link to your Mastodon profile on your own website and adding the website to your profile. No fees or documents necessary!' values={{ strong: chunks => <strong>{chunks}</strong> }} /></p></div> - <div><p className='onboarding__lead'><FormattedMessage id='onboarding.tips.migration' defaultMessage='<strong>Did you know?</strong> If you feel like {domain} is not a great server choice for you in the future, you can move to another Mastodon server without losing your followers. You can even host your own server!' values={{ domain, strong: chunks => <strong>{chunks}</strong> }} /></p></div> - <div><p className='onboarding__lead'><FormattedMessage id='onboarding.tips.2fa' defaultMessage='<strong>Did you know?</strong> You can secure your account by setting up two-factor authentication in your account settings. It works with any TOTP app of your choice, no phone number necessary!' values={{ strong: chunks => <strong>{chunks}</strong> }} /></p></div> - </TipCarousel> - - <p className='onboarding__lead'><FormattedMessage id='onboarding.share.next_steps' defaultMessage='Possible next steps:' /></p> - - <div className='onboarding__links'> - <Link to='/home' className='onboarding__link'> - <FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' /> - <Icon icon={ArrowRightAltIcon} /> - </Link> - - <Link to='/explore' className='onboarding__link'> - <FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' /> - <Icon icon={ArrowRightAltIcon} /> - </Link> - </div> - - <div className='onboarding__footer'> - <button className='link-button' onClick={onBack}><FormattedMessage id='onboarding.action.back' defaultMessage='Take me back' /></button> - </div> + <div className='scrollable privacy-policy'> + <div className='column-title'> + <h3><FormattedMessage id='onboarding.share.title' defaultMessage='Share your profile' /></h3> + <p><FormattedMessage id='onboarding.share.lead' defaultMessage='Let people know how they can find you on Mastodon!' /></p> </div> - </Column> - ); - } -} + <CopyPasteText value={intl.formatMessage(messages.shareableMessage, { username: `@${account.get('username')}@${domain}`, url })} /> -export default connect(mapStateToProps)(injectIntl(Share)); + <TipCarousel> + <div><p className='onboarding__lead'><FormattedMessage id='onboarding.tips.verification' defaultMessage='<strong>Did you know?</strong> You can verify your account by putting a link to your Mastodon profile on your own website and adding the website to your profile. No fees or documents necessary!' values={{ strong: chunks => <strong>{chunks}</strong> }} /></p></div> + <div><p className='onboarding__lead'><FormattedMessage id='onboarding.tips.migration' defaultMessage='<strong>Did you know?</strong> If you feel like {domain} is not a great server choice for you in the future, you can move to another Mastodon server without losing your followers. You can even host your own server!' values={{ domain, strong: chunks => <strong>{chunks}</strong> }} /></p></div> + <div><p className='onboarding__lead'><FormattedMessage id='onboarding.tips.2fa' defaultMessage='<strong>Did you know?</strong> You can secure your account by setting up two-factor authentication in your account settings. It works with any TOTP app of your choice, no phone number necessary!' values={{ strong: chunks => <strong>{chunks}</strong> }} /></p></div> + </TipCarousel> + + <p className='onboarding__lead'><FormattedMessage id='onboarding.share.next_steps' defaultMessage='Possible next steps:' /></p> + + <div className='onboarding__links'> + <Link to='/home' className='onboarding__link'> + <FormattedMessage id='onboarding.actions.go_to_home' defaultMessage='Take me to my home feed' /> + <Icon icon={ArrowRightAltIcon} /> + </Link> + + <Link to='/explore' className='onboarding__link'> + <FormattedMessage id='onboarding.actions.go_to_explore' defaultMessage='Take me to trending' /> + <Icon icon={ArrowRightAltIcon} /> + </Link> + </div> + + <div className='onboarding__footer'> + <Link className='link-button' to='/start'><FormattedMessage id='onboarding.action.back' defaultMessage='Take me back' /></Link> + </div> + </div> + </> + ); +}; diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index 02c69cbba..d3fee272f 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -210,7 +210,7 @@ class SwitchingColumnsArea extends PureComponent { <WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} /> <WrappedRoute path='/pinned' component={PinnedStatuses} content={children} /> - <WrappedRoute path='/start' exact component={Onboarding} content={children} /> + <WrappedRoute path='/start' component={Onboarding} content={children} /> <WrappedRoute path='/directory' component={Directory} content={children} /> <WrappedRoute path={['/explore', '/search']} component={Explore} content={children} /> <WrappedRoute path={['/publish', '/statuses/new']} component={Compose} content={children} /> diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 9cbaf9305..041446037 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -390,7 +390,7 @@ "lists.search": "Search among people you follow", "lists.subheading": "Your lists", "load_pending": "{count, plural, one {# new item} other {# new items}}", - "loading_indicator.label": "Loading...", + "loading_indicator.label": "Loading…", "media_gallery.toggle_visible": "{number, plural, one {Hide image} other {Hide images}}", "moved_to_account_banner.text": "Your account {disabledAccount} is currently disabled because you moved to {movedToAccount}.", "mute_modal.duration": "Duration", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Unfortunately, no results can be shown right now. You can try using search or browsing the explore page to find people to follow, or try again later.", "onboarding.follows.lead": "Your home feed is the primary way to experience Mastodon. The more people you follow, the more active and interesting it will be. To get you started, here are some suggestions:", "onboarding.follows.title": "Personalize your home feed", + "onboarding.profile.discoverable": "Feature profile and posts in discovery algorithms", + "onboarding.profile.display_name": "Display name", + "onboarding.profile.display_name_hint": "Your full name or your fun name…", + "onboarding.profile.indexable": "Include public posts in search results", + "onboarding.profile.lead": "You can always complete this later in the settings, where even more customization options are available.", + "onboarding.profile.note": "Bio", + "onboarding.profile.note_hint": "You can @mention other people or #hashtags…", + "onboarding.profile.save_and_continue": "Save and continue", + "onboarding.profile.title": "Profile setup", + "onboarding.profile.upload_avatar": "Upload profile picture", + "onboarding.profile.upload_header": "Upload profile header", "onboarding.share.lead": "Let people know how they can find you on Mastodon!", "onboarding.share.message": "I'm {username} on #Mastodon! Come follow me at {url}", "onboarding.share.next_steps": "Possible next steps:", diff --git a/app/javascript/mastodon/models/account.ts b/app/javascript/mastodon/models/account.ts index 00066e284..a04ebe629 100644 --- a/app/javascript/mastodon/models/account.ts +++ b/app/javascript/mastodon/models/account.ts @@ -67,6 +67,7 @@ export const accountDefaultValues: AccountShape = { bot: false, created_at: '', discoverable: false, + indexable: false, display_name: '', display_name_html: '', emojis: List<CustomEmoji>(), diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index c8cfe46a8..9f87352f5 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -2552,7 +2552,7 @@ $ui-header-height: 55px; .column-title { text-align: center; - padding-bottom: 40px; + padding-bottom: 32px; h3 { font-size: 24px; @@ -2743,58 +2743,6 @@ $ui-header-height: 55px; } } -.onboarding__progress-indicator { - display: flex; - align-items: center; - margin-bottom: 30px; - position: sticky; - background: $ui-base-color; - - @media screen and (width >= 600) { - padding: 0 40px; - } - - &__line { - height: 4px; - flex: 1 1 auto; - background: lighten($ui-base-color, 4%); - } - - &__step { - flex: 0 0 auto; - width: 30px; - height: 30px; - background: lighten($ui-base-color, 4%); - border-radius: 50%; - color: $primary-text-color; - display: flex; - align-items: center; - justify-content: center; - - svg { - width: 15px; - height: auto; - } - - &.active { - background: $valid-value-color; - } - } - - &__step.active, - &__line.active { - background: $valid-value-color; - background-image: linear-gradient( - 90deg, - $valid-value-color, - lighten($valid-value-color, 8%), - $valid-value-color - ); - background-size: 200px 100%; - animation: skeleton 1.2s ease-in-out infinite; - } -} - .follow-recommendations { background: darken($ui-base-color, 4%); border-radius: 8px; @@ -2871,6 +2819,28 @@ $ui-header-height: 55px; } } +.onboarding__profile { + position: relative; + margin-bottom: 40px + 20px; + + .app-form__avatar-input { + border: 2px solid $ui-base-color; + position: absolute; + inset-inline-start: -2px; + bottom: -40px; + z-index: 2; + } + + .app-form__header-input { + margin: 0 -20px; + border-radius: 0; + + img { + border-radius: 0; + } + } +} + .compose-form__highlightable { display: flex; flex-direction: column; @@ -3145,6 +3115,7 @@ $ui-header-height: 55px; cursor: pointer; background-color: transparent; border: 0; + border-radius: 10px; padding: 0; user-select: none; -webkit-tap-highlight-color: rgba($base-overlay-background, 0); @@ -3169,81 +3140,41 @@ $ui-header-height: 55px; } .react-toggle-track { - width: 50px; - height: 24px; + width: 32px; + height: 20px; padding: 0; - border-radius: 30px; - background-color: $ui-base-color; - transition: background-color 0.2s ease; + border-radius: 10px; + background-color: #626982; } -.react-toggle:is(:hover, :focus-within):not(.react-toggle--disabled) - .react-toggle-track { - background-color: darken($ui-base-color, 10%); +.react-toggle--focus { + outline: $ui-button-focus-outline; } .react-toggle--checked .react-toggle-track { - background-color: darken($ui-highlight-color, 2%); -} - -.react-toggle--checked:is(:hover, :focus-within):not(.react-toggle--disabled) - .react-toggle-track { background-color: $ui-highlight-color; } -.react-toggle-track-check { - position: absolute; - width: 14px; - height: 10px; - top: 0; - bottom: 0; - margin-top: auto; - margin-bottom: auto; - line-height: 0; - inset-inline-start: 8px; - opacity: 0; - transition: opacity 0.25s ease; -} - -.react-toggle--checked .react-toggle-track-check { - opacity: 1; - transition: opacity 0.25s ease; -} - +.react-toggle-track-check, .react-toggle-track-x { - position: absolute; - width: 10px; - height: 10px; - top: 0; - bottom: 0; - margin-top: auto; - margin-bottom: auto; - line-height: 0; - inset-inline-end: 10px; - opacity: 1; - transition: opacity 0.25s ease; -} - -.react-toggle--checked .react-toggle-track-x { - opacity: 0; + display: none; } .react-toggle-thumb { position: absolute; - top: 1px; - inset-inline-start: 1px; - width: 22px; - height: 22px; - border: 1px solid $ui-base-color; + top: 2px; + inset-inline-start: 2px; + width: 16px; + height: 16px; border-radius: 50%; - background-color: darken($simple-background-color, 2%); + background-color: $primary-text-color; box-sizing: border-box; transition: all 0.25s ease; transition-property: border-color, left; } .react-toggle--checked .react-toggle-thumb { - inset-inline-start: 27px; + inset-inline-start: 32px - 16px - 2px; border-color: $ui-highlight-color; } @@ -4066,6 +3997,17 @@ a.status-card { justify-content: center; } +.button .loading-indicator { + position: static; + transform: none; + + .circular-progress { + color: $primary-text-color; + width: 22px; + height: 22px; + } +} + .circular-progress { color: lighten($ui-base-color, 26%); animation: 1.4s linear 0s infinite normal none running simple-rotate; @@ -5799,12 +5741,14 @@ a.status-card { &__toggle { display: flex; align-items: center; - margin-bottom: 10px; + margin-bottom: 16px; + gap: 8px; & > span { - font-size: 17px; + display: block; + font-size: 14px; font-weight: 500; - margin-inline-start: 10px; + line-height: 20px; } } diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index 0f8eecee0..e72a01936 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -36,7 +36,7 @@ code { } .input { - margin-bottom: 15px; + margin-bottom: 16px; overflow: hidden; &.hidden { @@ -266,12 +266,13 @@ code { font-size: 14px; color: $primary-text-color; display: block; - font-weight: 500; - padding-top: 5px; + font-weight: 600; + line-height: 20px; } .hint { - margin-bottom: 15px; + line-height: 16px; + margin-bottom: 12px; } ul { @@ -427,7 +428,8 @@ code { input[type='datetime-local'], textarea { box-sizing: border-box; - font-size: 16px; + font-size: 14px; + line-height: 20px; color: $primary-text-color; display: block; width: 100%; @@ -435,9 +437,9 @@ code { font-family: inherit; resize: vertical; background: darken($ui-base-color, 10%); - border: 1px solid darken($ui-base-color, 14%); - border-radius: 4px; - padding: 10px; + border: 1px solid darken($ui-base-color, 10%); + border-radius: 8px; + padding: 10px 16px; &::placeholder { color: lighten($darker-text-color, 4%); @@ -451,14 +453,13 @@ code { border-color: $valid-value-color; } - &:hover { - border-color: darken($ui-base-color, 20%); - } - &:active, &:focus { border-color: $highlight-text-color; - background: darken($ui-base-color, 8%); + } + + @media screen and (width <= 600px) { + font-size: 16px; } } @@ -524,12 +525,11 @@ code { border-radius: 4px; background: $ui-button-background-color; color: $ui-button-color; - font-size: 18px; - line-height: inherit; + font-size: 15px; + line-height: 22px; height: auto; - padding: 10px; + padding: 7px 18px; text-decoration: none; - text-transform: uppercase; text-align: center; box-sizing: border-box; cursor: pointer; @@ -1220,3 +1220,74 @@ code { background: $highlight-text-color; } } + +.app-form { + & > * { + margin-bottom: 16px; + } + + &__avatar-input, + &__header-input { + display: block; + border-radius: 8px; + background: var(--dropdown-background-color); + position: relative; + cursor: pointer; + + img { + position: absolute; + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 8px; + z-index: 0; + } + + .icon { + position: absolute; + inset-inline-start: 50%; + top: 50%; + transform: translate(-50%, -50%); + color: $darker-text-color; + z-index: 3; + } + + &.selected .icon { + color: $primary-text-color; + transform: none; + inset-inline-start: auto; + inset-inline-end: 8px; + top: auto; + bottom: 8px; + } + + &.invalid img { + outline: 1px solid $error-value-color; + outline-offset: -1px; + } + + &.invalid::before { + display: block; + content: ''; + width: 100%; + height: 100%; + position: absolute; + background: rgba($error-value-color, 0.25); + z-index: 2; + border-radius: 8px; + } + + &:hover { + background-color: var(--dropdown-border-color); + } + } + + &__avatar-input { + width: 80px; + height: 80px; + } + + &__header-input { + aspect-ratio: 580/193; + } +} diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb index 8c6520b30..5d1292a6b 100644 --- a/app/serializers/rest/account_serializer.rb +++ b/app/serializers/rest/account_serializer.rb @@ -6,7 +6,7 @@ class REST::AccountSerializer < ActiveModel::Serializer # Please update `app/javascript/mastodon/api_types/accounts.ts` when making changes to the attributes - attributes :id, :username, :acct, :display_name, :locked, :bot, :discoverable, :group, :created_at, + attributes :id, :username, :acct, :display_name, :locked, :bot, :discoverable, :indexable, :group, :created_at, :note, :url, :uri, :avatar, :avatar_static, :header, :header_static, :followers_count, :following_count, :statuses_count, :last_status_at, :hide_collections @@ -112,6 +112,10 @@ class REST::AccountSerializer < ActiveModel::Serializer object.suspended? ? false : object.discoverable end + def indexable + object.suspended? ? false : object.indexable + end + def moved_to_account object.suspended? ? nil : AccountDecorator.new(object.moved_to_account) end diff --git a/config/routes.rb b/config/routes.rb index 82431f6ec..150b26cf1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,7 +31,7 @@ Rails.application.routes.draw do /favourites /bookmarks /pinned - /start + /start/(*any) /directory /explore/(*any) /search From fe58ac8d9f1b0c4347fde451f1caedac2ac605bc Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 15 Nov 2023 08:14:51 -0500 Subject: [PATCH 043/255] Improve spec coverage for `api/web/push_subscriptions` controller (#27858) Co-authored-by: Claire <claire.github-309c@sitedethib.com> --- .../api/web/push_subscriptions_controller.rb | 78 ++++++++++++------- .../web/push_subscriptions_controller_spec.rb | 60 ++++++++------ 2 files changed, 86 insertions(+), 52 deletions(-) diff --git a/app/controllers/api/web/push_subscriptions_controller.rb b/app/controllers/api/web/push_subscriptions_controller.rb index 5167928e9..167d16fc4 100644 --- a/app/controllers/api/web/push_subscriptions_controller.rb +++ b/app/controllers/api/web/push_subscriptions_controller.rb @@ -3,37 +3,13 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController before_action :require_user! before_action :set_push_subscription, only: :update + before_action :destroy_previous_subscriptions, only: :create, if: :prior_subscriptions? + after_action :update_session_with_subscription, only: :create def create - active_session = current_session + @push_subscription = ::Web::PushSubscription.create!(web_push_subscription_params) - unless active_session.web_push_subscription.nil? - active_session.web_push_subscription.destroy! - active_session.update!(web_push_subscription: nil) - end - - # Mobile devices do not support regular notifications, so we enable push notifications by default - alerts_enabled = active_session.detection.device.mobile? || active_session.detection.device.tablet? - - data = { - policy: 'all', - alerts: Notification::TYPES.index_with { alerts_enabled }, - } - - data.deep_merge!(data_params) if params[:data] - - push_subscription = ::Web::PushSubscription.create!( - endpoint: subscription_params[:endpoint], - key_p256dh: subscription_params[:keys][:p256dh], - key_auth: subscription_params[:keys][:auth], - data: data, - user_id: active_session.user_id, - access_token_id: active_session.access_token_id - ) - - active_session.update!(web_push_subscription: push_subscription) - - render json: push_subscription, serializer: REST::WebPushSubscriptionSerializer + render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer end def update @@ -43,6 +19,41 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController private + def active_session + @active_session ||= current_session + end + + def destroy_previous_subscriptions + active_session.web_push_subscription.destroy! + active_session.update!(web_push_subscription: nil) + end + + def prior_subscriptions? + active_session.web_push_subscription.present? + end + + def subscription_data + default_subscription_data.tap do |data| + data.deep_merge!(data_params) if params[:data] + end + end + + def default_subscription_data + { + policy: 'all', + alerts: Notification::TYPES.index_with { alerts_enabled }, + } + end + + def alerts_enabled + # Mobile devices do not support regular notifications, so we enable push notifications by default + active_session.detection.device.mobile? || active_session.detection.device.tablet? + end + + def update_session_with_subscription + active_session.update!(web_push_subscription: @push_subscription) + end + def set_push_subscription @push_subscription = ::Web::PushSubscription.find(params[:id]) end @@ -51,6 +62,17 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController @subscription_params ||= params.require(:subscription).permit(:endpoint, keys: [:auth, :p256dh]) end + def web_push_subscription_params + { + access_token_id: active_session.access_token_id, + data: subscription_data, + endpoint: subscription_params[:endpoint], + key_auth: subscription_params[:keys][:auth], + key_p256dh: subscription_params[:keys][:p256dh], + user_id: active_session.user_id, + } + end + def data_params @data_params ||= params.require(:data).permit(:policy, alerts: Notification::TYPES) end diff --git a/spec/controllers/api/web/push_subscriptions_controller_spec.rb b/spec/controllers/api/web/push_subscriptions_controller_spec.rb index 9f027ede9..58677841c 100644 --- a/spec/controllers/api/web/push_subscriptions_controller_spec.rb +++ b/spec/controllers/api/web/push_subscriptions_controller_spec.rb @@ -37,37 +37,49 @@ describe Api::Web::PushSubscriptionsController do } end + before do + sign_in(user) + + stub_request(:post, create_payload[:subscription][:endpoint]).to_return(status: 200) + end + describe 'POST #create' do it 'saves push subscriptions' do - sign_in(user) - - stub_request(:post, create_payload[:subscription][:endpoint]).to_return(status: 200) - post :create, format: :json, params: create_payload + expect(response).to have_http_status(200) + user.reload - push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint]) + expect(created_push_subscription).to have_attributes( + endpoint: eq(create_payload[:subscription][:endpoint]), + key_p256dh: eq(create_payload[:subscription][:keys][:p256dh]), + key_auth: eq(create_payload[:subscription][:keys][:auth]) + ) + expect(user.session_activations.first.web_push_subscription).to eq(created_push_subscription) + end - expect(push_subscription['endpoint']).to eq(create_payload[:subscription][:endpoint]) - expect(push_subscription['key_p256dh']).to eq(create_payload[:subscription][:keys][:p256dh]) - expect(push_subscription['key_auth']).to eq(create_payload[:subscription][:keys][:auth]) + context 'with a user who has a session with a prior subscription' do + let!(:prior_subscription) { Fabricate(:web_push_subscription, session_activation: user.session_activations.last) } + + it 'destroys prior subscription when creating new one' do + post :create, format: :json, params: create_payload + + expect(response).to have_http_status(200) + expect { prior_subscription.reload }.to raise_error(ActiveRecord::RecordNotFound) + end end context 'with initial data' do it 'saves alert settings' do - sign_in(user) - - stub_request(:post, create_payload[:subscription][:endpoint]).to_return(status: 200) - post :create, format: :json, params: create_payload.merge(alerts_payload) - push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint]) + expect(response).to have_http_status(200) - expect(push_subscription.data['policy']).to eq 'all' + expect(created_push_subscription.data['policy']).to eq 'all' %w(follow follow_request favourite reblog mention poll status).each do |type| - expect(push_subscription.data['alerts'][type]).to eq(alerts_payload[:data][:alerts][type.to_sym].to_s) + expect(created_push_subscription.data['alerts'][type]).to eq(alerts_payload[:data][:alerts][type.to_sym].to_s) end end end @@ -75,23 +87,23 @@ describe Api::Web::PushSubscriptionsController do describe 'PUT #update' do it 'changes alert settings' do - sign_in(user) - - stub_request(:post, create_payload[:subscription][:endpoint]).to_return(status: 200) - post :create, format: :json, params: create_payload - alerts_payload[:id] = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint]).id + expect(response).to have_http_status(200) + + alerts_payload[:id] = created_push_subscription.id put :update, format: :json, params: alerts_payload - push_subscription = Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint]) - - expect(push_subscription.data['policy']).to eq 'all' + expect(created_push_subscription.data['policy']).to eq 'all' %w(follow follow_request favourite reblog mention poll status).each do |type| - expect(push_subscription.data['alerts'][type]).to eq(alerts_payload[:data][:alerts][type.to_sym].to_s) + expect(created_push_subscription.data['alerts'][type]).to eq(alerts_payload[:data][:alerts][type.to_sym].to_s) end end end + + def created_push_subscription + Web::PushSubscription.find_by(endpoint: create_payload[:subscription][:endpoint]) + end end From 12a5b7391d0298a99b94386538fe4ca625cea7e9 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 15 Nov 2023 08:21:18 -0500 Subject: [PATCH 044/255] Add spec for well known change password endpoint (#27856) --- spec/requests/well_known/change_password_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 spec/requests/well_known/change_password_spec.rb diff --git a/spec/requests/well_known/change_password_spec.rb b/spec/requests/well_known/change_password_spec.rb new file mode 100644 index 000000000..04134b71f --- /dev/null +++ b/spec/requests/well_known/change_password_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'The /.well-known/change-password request' do + it 'redirects to the change password page' do + get '/.well-known/change-password' + + expect(response).to redirect_to '/auth/edit' + end +end From bd575a1dd69d87ca0f69873f7badf28d38e8b9ed Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Wed, 15 Nov 2023 15:18:43 +0100 Subject: [PATCH 045/255] Add banner for forwarded reports made by remote users about remote content (#27549) --- app/views/admin/reports/_header_details.html.haml | 2 +- app/views/admin/reports/show.html.haml | 3 +++ config/locales/en.yml | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/views/admin/reports/_header_details.html.haml b/app/views/admin/reports/_header_details.html.haml index 5878cd2ff..45790b9cd 100644 --- a/app/views/admin/reports/_header_details.html.haml +++ b/app/views/admin/reports/_header_details.html.haml @@ -22,7 +22,7 @@ = t('admin.reports.resolved') - else = t('admin.reports.unresolved') - - unless report.target_account.local? + - if report.account.local? && !report.target_account.local? .report-header__details__item .report-header__details__item__header %strong= t('admin.reports.forwarded') diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml index 13a4d4834..4376e5af4 100644 --- a/app/views/admin/reports/show.html.haml +++ b/app/views/admin/reports/show.html.haml @@ -7,6 +7,9 @@ - else = link_to t('admin.reports.mark_as_unresolved'), reopen_admin_report_path(@report), method: :post, class: 'button' +- unless @report.account.local? || @report.target_account.local? + .flash-message= t('admin.reports.forwarded_replies_explanation') + .report-header = render 'admin/reports/header_card', report: @report = render 'admin/reports/header_details', report: @report diff --git a/config/locales/en.yml b/config/locales/en.yml index 7319de53d..057f7a584 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -611,6 +611,7 @@ en: created_at: Reported delete_and_resolve: Delete posts forwarded: Forwarded + forwarded_replies_explanation: This report is from a remote user and about remote content. It has been forwarded to you because the reported content is in reply to one of your users. forwarded_to: Forwarded to %{domain} mark_as_resolved: Mark as resolved mark_as_sensitive: Mark as sensitive From 3de91456132ffadf5b98848409fa2a0377a3bef6 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 15 Nov 2023 14:12:02 -0500 Subject: [PATCH 046/255] Move controller specs for `well-known` endpoints to request specs (#27855) --- .../well_known/host_meta_controller_spec.rb | 22 -- .../well_known/node_info_controller_spec.rb | 41 --- .../well_known/webfinger_controller_spec.rb | 235 ---------------- spec/requests/host_meta_request_spec.rb | 14 - spec/requests/webfinger_request_spec.rb | 33 --- spec/requests/well_known/host_meta_spec.rb | 27 ++ spec/requests/well_known/node_info_spec.rb | 58 ++++ spec/requests/well_known/webfinger_spec.rb | 255 ++++++++++++++++++ 8 files changed, 340 insertions(+), 345 deletions(-) delete mode 100644 spec/controllers/well_known/host_meta_controller_spec.rb delete mode 100644 spec/controllers/well_known/node_info_controller_spec.rb delete mode 100644 spec/controllers/well_known/webfinger_controller_spec.rb delete mode 100644 spec/requests/host_meta_request_spec.rb delete mode 100644 spec/requests/webfinger_request_spec.rb create mode 100644 spec/requests/well_known/host_meta_spec.rb create mode 100644 spec/requests/well_known/node_info_spec.rb create mode 100644 spec/requests/well_known/webfinger_spec.rb diff --git a/spec/controllers/well_known/host_meta_controller_spec.rb b/spec/controllers/well_known/host_meta_controller_spec.rb deleted file mode 100644 index 4bd161cd9..000000000 --- a/spec/controllers/well_known/host_meta_controller_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe WellKnown::HostMetaController do - render_views - - describe 'GET #show' do - it 'returns http success' do - get :show, format: :xml - - expect(response).to have_http_status(200) - expect(response.media_type).to eq 'application/xrd+xml' - expect(response.body).to eq <<~XML - <?xml version="1.0" encoding="UTF-8"?> - <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"> - <Link rel="lrdd" template="https://cb6e6126.ngrok.io/.well-known/webfinger?resource={uri}"/> - </XRD> - XML - end - end -end diff --git a/spec/controllers/well_known/node_info_controller_spec.rb b/spec/controllers/well_known/node_info_controller_spec.rb deleted file mode 100644 index 6ec34afd0..000000000 --- a/spec/controllers/well_known/node_info_controller_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe WellKnown::NodeInfoController do - render_views - - describe 'GET #index' do - it 'returns json document pointing to node info' do - get :index - - expect(response).to have_http_status(200) - expect(response.media_type).to eq 'application/json' - - json = body_as_json - - expect(json[:links]).to be_an Array - expect(json[:links][0][:rel]).to eq 'http://nodeinfo.diaspora.software/ns/schema/2.0' - expect(json[:links][0][:href]).to include 'nodeinfo/2.0' - end - end - - describe 'GET #show' do - it 'returns json document with node info properties' do - get :show - - expect(response).to have_http_status(200) - expect(response.media_type).to eq 'application/json' - - json = body_as_json - foo = { 'foo' => 0 } - - expect(foo).to_not match_json_schema('nodeinfo_2.0') - expect(json).to match_json_schema('nodeinfo_2.0') - expect(json[:version]).to eq '2.0' - expect(json[:usage]).to be_a Hash - expect(json[:software]).to be_a Hash - expect(json[:protocols]).to be_an Array - end - end -end diff --git a/spec/controllers/well_known/webfinger_controller_spec.rb b/spec/controllers/well_known/webfinger_controller_spec.rb deleted file mode 100644 index 6610f4d13..000000000 --- a/spec/controllers/well_known/webfinger_controller_spec.rb +++ /dev/null @@ -1,235 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe WellKnown::WebfingerController do - include RoutingHelper - - render_views - - describe 'GET #show' do - subject(:perform_show!) do - get :show, params: { resource: resource }, format: :json - end - - let(:alternate_domains) { [] } - let(:alice) { Fabricate(:account, username: 'alice') } - let(:resource) { nil } - - around do |example| - tmp = Rails.configuration.x.alternate_domains - Rails.configuration.x.alternate_domains = alternate_domains - example.run - Rails.configuration.x.alternate_domains = tmp - end - - shared_examples 'a successful response' do - it 'returns http success' do - expect(response).to have_http_status(200) - end - - it 'does not set a Vary header' do - expect(response.headers['Vary']).to be_nil - end - - it 'returns application/jrd+json' do - expect(response.media_type).to eq 'application/jrd+json' - end - - it 'returns links for the account' do - json = body_as_json - expect(json[:subject]).to eq 'acct:alice@cb6e6126.ngrok.io' - expect(json[:aliases]).to include('https://cb6e6126.ngrok.io/@alice', 'https://cb6e6126.ngrok.io/users/alice') - end - end - - context 'when an account exists' do - let(:resource) { alice.to_webfinger_s } - - before do - perform_show! - end - - it_behaves_like 'a successful response' - end - - context 'when an account is temporarily suspended' do - let(:resource) { alice.to_webfinger_s } - - before do - alice.suspend! - perform_show! - end - - it_behaves_like 'a successful response' - end - - context 'when an account is permanently suspended or deleted' do - let(:resource) { alice.to_webfinger_s } - - before do - alice.suspend! - alice.deletion_request.destroy - perform_show! - end - - it 'returns http gone' do - expect(response).to have_http_status(410) - end - end - - context 'when an account is not found' do - let(:resource) { 'acct:not@existing.com' } - - before do - perform_show! - end - - it 'returns http not found' do - expect(response).to have_http_status(404) - end - end - - context 'with an alternate domain' do - let(:alternate_domains) { ['foo.org'] } - - before do - perform_show! - end - - context 'when an account exists' do - let(:resource) do - username, = alice.to_webfinger_s.split('@') - "#{username}@foo.org" - end - - it_behaves_like 'a successful response' - end - - context 'when the domain is wrong' do - let(:resource) do - username, = alice.to_webfinger_s.split('@') - "#{username}@bar.org" - end - - it 'returns http not found' do - expect(response).to have_http_status(404) - end - end - end - - context 'when the old name scheme is used to query the instance actor' do - let(:resource) do - "#{Rails.configuration.x.local_domain}@#{Rails.configuration.x.local_domain}" - end - - before do - perform_show! - end - - it 'returns http success' do - expect(response).to have_http_status(200) - end - - it 'does not set a Vary header' do - expect(response.headers['Vary']).to be_nil - end - - it 'returns application/jrd+json' do - expect(response.media_type).to eq 'application/jrd+json' - end - - it 'returns links for the internal account' do - json = body_as_json - expect(json[:subject]).to eq 'acct:mastodon.internal@cb6e6126.ngrok.io' - expect(json[:aliases]).to eq ['https://cb6e6126.ngrok.io/actor'] - end - end - - context 'with no resource parameter' do - let(:resource) { nil } - - before do - perform_show! - end - - it 'returns http bad request' do - expect(response).to have_http_status(400) - end - end - - context 'with a nonsense parameter' do - let(:resource) { 'df/:dfkj' } - - before do - perform_show! - end - - it 'returns http bad request' do - expect(response).to have_http_status(400) - end - end - - context 'when an account has an avatar' do - let(:alice) { Fabricate(:account, username: 'alice', avatar: attachment_fixture('attachment.jpg')) } - let(:resource) { alice.to_webfinger_s } - - it 'returns avatar in response' do - perform_show! - - avatar_link = get_avatar_link(body_as_json) - expect(avatar_link).to_not be_nil - expect(avatar_link[:type]).to eq alice.avatar.content_type - expect(avatar_link[:href]).to eq full_asset_url(alice.avatar) - end - - context 'with limited federation mode' do - before do - allow(Rails.configuration.x).to receive(:limited_federation_mode).and_return(true) - end - - it 'does not return avatar in response' do - perform_show! - - avatar_link = get_avatar_link(body_as_json) - expect(avatar_link).to be_nil - end - end - - context 'when enabling DISALLOW_UNAUTHENTICATED_API_ACCESS' do - around do |example| - ClimateControl.modify DISALLOW_UNAUTHENTICATED_API_ACCESS: 'true' do - example.run - end - end - - it 'does not return avatar in response' do - perform_show! - - avatar_link = get_avatar_link(body_as_json) - expect(avatar_link).to be_nil - end - end - end - - context 'when an account does not have an avatar' do - let(:alice) { Fabricate(:account, username: 'alice', avatar: nil) } - let(:resource) { alice.to_webfinger_s } - - before do - perform_show! - end - - it 'does not return avatar in response' do - avatar_link = get_avatar_link(body_as_json) - expect(avatar_link).to be_nil - end - end - end - - private - - def get_avatar_link(json) - json[:links].find { |link| link[:rel] == 'http://webfinger.net/rel/avatar' } - end -end diff --git a/spec/requests/host_meta_request_spec.rb b/spec/requests/host_meta_request_spec.rb deleted file mode 100644 index ec26ecba7..000000000 --- a/spec/requests/host_meta_request_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'The host_meta route' do - describe 'requested without accepts headers' do - it 'returns an xml response' do - get host_meta_url - - expect(response).to have_http_status(200) - expect(response.media_type).to eq 'application/xrd+xml' - end - end -end diff --git a/spec/requests/webfinger_request_spec.rb b/spec/requests/webfinger_request_spec.rb deleted file mode 100644 index 68a1478be..000000000 --- a/spec/requests/webfinger_request_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'The webfinger route' do - let(:alice) { Fabricate(:account, username: 'alice') } - - describe 'requested with standard accepts headers' do - it 'returns a json response' do - get webfinger_url(resource: alice.to_webfinger_s) - - expect(response).to have_http_status(200) - expect(response.media_type).to eq 'application/jrd+json' - end - end - - describe 'asking for json format' do - it 'returns a json response for json format' do - get webfinger_url(resource: alice.to_webfinger_s, format: :json) - - expect(response).to have_http_status(200) - expect(response.media_type).to eq 'application/jrd+json' - end - - it 'returns a json response for json accept header' do - headers = { 'HTTP_ACCEPT' => 'application/jrd+json' } - get webfinger_url(resource: alice.to_webfinger_s), headers: headers - - expect(response).to have_http_status(200) - expect(response.media_type).to eq 'application/jrd+json' - end - end -end diff --git a/spec/requests/well_known/host_meta_spec.rb b/spec/requests/well_known/host_meta_spec.rb new file mode 100644 index 000000000..ca10a51a0 --- /dev/null +++ b/spec/requests/well_known/host_meta_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'The /.well-known/host-meta request' do + it 'returns http success with valid XML response' do + get '/.well-known/host-meta' + + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: 'application/xrd+xml', + body: host_meta_xml_template + ) + end + + private + + def host_meta_xml_template + <<~XML + <?xml version="1.0" encoding="UTF-8"?> + <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"> + <Link rel="lrdd" template="https://cb6e6126.ngrok.io/.well-known/webfinger?resource={uri}"/> + </XRD> + XML + end +end diff --git a/spec/requests/well_known/node_info_spec.rb b/spec/requests/well_known/node_info_spec.rb new file mode 100644 index 000000000..0934b0fde --- /dev/null +++ b/spec/requests/well_known/node_info_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'The well-known node-info endpoints' do + describe 'The /.well-known/node-info endpoint' do + it 'returns JSON document pointing to node info' do + get '/.well-known/nodeinfo' + + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: 'application/json' + ) + + expect(body_as_json).to include( + links: be_an(Array).and( + contain_exactly( + include( + rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0', + href: include('nodeinfo/2.0') + ) + ) + ) + ) + end + end + + describe 'The /nodeinfo/2.0 endpoint' do + it 'returns JSON document with node info properties' do + get '/nodeinfo/2.0' + + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: 'application/json' + ) + + expect(non_matching_hash) + .to_not match_json_schema('nodeinfo_2.0') + + expect(body_as_json) + .to match_json_schema('nodeinfo_2.0') + .and include( + version: '2.0', + usage: be_a(Hash), + software: be_a(Hash), + protocols: be_a(Array) + ) + end + + private + + def non_matching_hash + { 'foo' => 0 } + end + end +end diff --git a/spec/requests/well_known/webfinger_spec.rb b/spec/requests/well_known/webfinger_spec.rb new file mode 100644 index 000000000..779f1bba5 --- /dev/null +++ b/spec/requests/well_known/webfinger_spec.rb @@ -0,0 +1,255 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'The /.well-known/webfinger endpoint' do + subject(:perform_request!) { get webfinger_url(resource: resource) } + + let(:alternate_domains) { [] } + let(:alice) { Fabricate(:account, username: 'alice') } + let(:resource) { nil } + + around do |example| + tmp = Rails.configuration.x.alternate_domains + Rails.configuration.x.alternate_domains = alternate_domains + example.run + Rails.configuration.x.alternate_domains = tmp + end + + shared_examples 'a successful response' do + it 'returns http success' do + expect(response).to have_http_status(200) + end + + it 'sets only a Vary Origin header' do + expect(response.headers['Vary']).to eq('Origin') + end + + it 'returns application/jrd+json' do + expect(response.media_type).to eq 'application/jrd+json' + end + + it 'returns links for the account' do + json = body_as_json + expect(json[:subject]).to eq 'acct:alice@cb6e6126.ngrok.io' + expect(json[:aliases]).to include('https://cb6e6126.ngrok.io/@alice', 'https://cb6e6126.ngrok.io/users/alice') + end + end + + context 'when an account exists' do + let(:resource) { alice.to_webfinger_s } + + before do + perform_request! + end + + it_behaves_like 'a successful response' + end + + context 'when an account is temporarily suspended' do + let(:resource) { alice.to_webfinger_s } + + before do + alice.suspend! + perform_request! + end + + it_behaves_like 'a successful response' + end + + context 'when an account is permanently suspended or deleted' do + let(:resource) { alice.to_webfinger_s } + + before do + alice.suspend! + alice.deletion_request.destroy + perform_request! + end + + it 'returns http gone' do + expect(response).to have_http_status(410) + end + end + + context 'when an account is not found' do + let(:resource) { 'acct:not@existing.com' } + + before do + perform_request! + end + + it 'returns http not found' do + expect(response).to have_http_status(404) + end + end + + context 'with an alternate domain' do + let(:alternate_domains) { ['foo.org'] } + + before do + perform_request! + end + + context 'when an account exists' do + let(:resource) do + username, = alice.to_webfinger_s.split('@') + "#{username}@foo.org" + end + + it_behaves_like 'a successful response' + end + + context 'when the domain is wrong' do + let(:resource) do + username, = alice.to_webfinger_s.split('@') + "#{username}@bar.org" + end + + it 'returns http not found' do + expect(response).to have_http_status(404) + end + end + end + + context 'when the old name scheme is used to query the instance actor' do + let(:resource) do + "#{Rails.configuration.x.local_domain}@#{Rails.configuration.x.local_domain}" + end + + before do + perform_request! + end + + it 'returns http success' do + expect(response).to have_http_status(200) + end + + it 'sets only a Vary Origin header' do + expect(response.headers['Vary']).to eq('Origin') + end + + it 'returns application/jrd+json' do + expect(response.media_type).to eq 'application/jrd+json' + end + + it 'returns links for the internal account' do + json = body_as_json + expect(json[:subject]).to eq 'acct:mastodon.internal@cb6e6126.ngrok.io' + expect(json[:aliases]).to eq ['https://cb6e6126.ngrok.io/actor'] + end + end + + context 'with no resource parameter' do + let(:resource) { nil } + + before do + perform_request! + end + + it 'returns http bad request' do + expect(response).to have_http_status(400) + end + end + + context 'with a nonsense parameter' do + let(:resource) { 'df/:dfkj' } + + before do + perform_request! + end + + it 'returns http bad request' do + expect(response).to have_http_status(400) + end + end + + context 'when an account has an avatar' do + let(:alice) { Fabricate(:account, username: 'alice', avatar: attachment_fixture('attachment.jpg')) } + let(:resource) { alice.to_webfinger_s } + + it 'returns avatar in response' do + perform_request! + + avatar_link = get_avatar_link(body_as_json) + expect(avatar_link).to_not be_nil + expect(avatar_link[:type]).to eq alice.avatar.content_type + expect(avatar_link[:href]).to eq Addressable::URI.new(host: Rails.configuration.x.local_domain, path: alice.avatar.to_s, scheme: 'https').to_s + end + + context 'with limited federation mode' do + before do + allow(Rails.configuration.x).to receive(:limited_federation_mode).and_return(true) + end + + it 'does not return avatar in response' do + perform_request! + + avatar_link = get_avatar_link(body_as_json) + expect(avatar_link).to be_nil + end + end + + context 'when enabling DISALLOW_UNAUTHENTICATED_API_ACCESS' do + around do |example| + ClimateControl.modify DISALLOW_UNAUTHENTICATED_API_ACCESS: 'true' do + example.run + end + end + + it 'does not return avatar in response' do + perform_request! + + avatar_link = get_avatar_link(body_as_json) + expect(avatar_link).to be_nil + end + end + end + + context 'when an account does not have an avatar' do + let(:alice) { Fabricate(:account, username: 'alice', avatar: nil) } + let(:resource) { alice.to_webfinger_s } + + before do + perform_request! + end + + it 'does not return avatar in response' do + avatar_link = get_avatar_link(body_as_json) + expect(avatar_link).to be_nil + end + end + + context 'with different headers' do + describe 'requested with standard accepts headers' do + it 'returns a json response' do + get webfinger_url(resource: alice.to_webfinger_s) + + expect(response).to have_http_status(200) + expect(response.media_type).to eq 'application/jrd+json' + end + end + + describe 'asking for json format' do + it 'returns a json response for json format' do + get webfinger_url(resource: alice.to_webfinger_s, format: :json) + + expect(response).to have_http_status(200) + expect(response.media_type).to eq 'application/jrd+json' + end + + it 'returns a json response for json accept header' do + headers = { 'HTTP_ACCEPT' => 'application/jrd+json' } + get webfinger_url(resource: alice.to_webfinger_s), headers: headers + + expect(response).to have_http_status(200) + expect(response.media_type).to eq 'application/jrd+json' + end + end + end + + private + + def get_avatar_link(json) + json[:links].find { |link| link[:rel] == 'http://webfinger.net/rel/avatar' } + end +end From 04121bd02059b8246233d0421349005d75a6b1a1 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 15 Nov 2023 18:09:31 -0500 Subject: [PATCH 047/255] Disable simplecov `enable_coverage_for_eval` option, move to standalone file (#27869) --- .simplecov | 22 ++++++++++++++++++++++ spec/spec_helper.rb | 25 ++----------------------- 2 files changed, 24 insertions(+), 23 deletions(-) create mode 100644 .simplecov diff --git a/.simplecov b/.simplecov new file mode 100644 index 000000000..fbd0207be --- /dev/null +++ b/.simplecov @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +if ENV['CI'] + require 'simplecov-lcov' + SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true + SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter +else + SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter +end + +SimpleCov.start 'rails' do + enable_coverage :branch + + add_filter 'lib/linter' + + add_group 'Libraries', 'lib' + add_group 'Policies', 'app/policies' + add_group 'Presenters', 'app/presenters' + add_group 'Serializers', 'app/serializers' + add_group 'Services', 'app/services' + add_group 'Validators', 'app/validators' +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0bb4f88cf..dc60976d0 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,28 +1,7 @@ # frozen_string_literal: true -if ENV['DISABLE_SIMPLECOV'] != 'true' - require 'simplecov' - - if ENV['CI'] - require 'simplecov-lcov' - SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true - SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter - else - SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter - end - SimpleCov.start 'rails' do - enable_coverage :branch - enable_coverage_for_eval - - add_filter 'lib/linter' - add_group 'Policies', 'app/policies' - add_group 'Presenters', 'app/presenters' - add_group 'Serializers', 'app/serializers' - add_group 'Services', 'app/services' - add_group 'Validators', 'app/validators' - - add_group 'Libraries', 'lib' - end +unless ENV['DISABLE_SIMPLECOV'] == 'true' + require 'simplecov' # Configuration details loaded from .simplecov end RSpec.configure do |config| From 91a05f3cad55fa3932e8364db1a87becd2d6f14c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 16 Nov 2023 10:33:54 +0100 Subject: [PATCH 048/255] Update libretranslate/libretranslate Docker tag to v1.5.2 (#27716) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .devcontainer/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 137bebc59..40dc72c12 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -70,7 +70,7 @@ services: hard: -1 libretranslate: - image: libretranslate/libretranslate:v1.4.1 + image: libretranslate/libretranslate:v1.5.2 restart: unless-stopped volumes: - lt-data:/home/libretranslate/.local From 669a7157cbc2d950988a80244a1f7cdec5aa59f5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 16 Nov 2023 10:52:23 +0100 Subject: [PATCH 049/255] Update dependency webpack-bundle-analyzer to v4.10.1 (#27885) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index e66f58f8b..32c2546e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17014,8 +17014,8 @@ __metadata: linkType: hard "webpack-bundle-analyzer@npm:^4.8.0": - version: 4.10.0 - resolution: "webpack-bundle-analyzer@npm:4.10.0" + version: 4.10.1 + resolution: "webpack-bundle-analyzer@npm:4.10.1" dependencies: "@discoveryjs/json-ext": "npm:0.5.7" acorn: "npm:^8.0.4" @@ -17032,7 +17032,7 @@ __metadata: ws: "npm:^7.3.1" bin: webpack-bundle-analyzer: lib/bin/analyzer.js - checksum: f812a8d3c0198ce518baf742bff656526f3eae69fb7a64c7f0c9cff202f6fb3380cabf3baaae965b8d6ffbbb6fb802eacb373fca03a596a38b01b84cfb2e8329 + checksum: 6a94c8f6aa03296fb2eb00d6ad3b27bd5c551590fd253772bc61debf3177414d42701014079d4f85c74ba1ca685ae9f0cb4063812b58c21f294d108e9908e5cd languageName: node linkType: hard From c1f93def403e2bdcf3338118a17802a038090a35 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 16 Nov 2023 04:54:51 -0500 Subject: [PATCH 050/255] Reduce expectations for `RSpec/MultipleExpectations` cop in `controllers/statuses` spec (#27875) --- spec/controllers/statuses_controller_spec.rb | 221 +++++++++++-------- 1 file changed, 134 insertions(+), 87 deletions(-) diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb index 8b715824b..fe40ee6de 100644 --- a/spec/controllers/statuses_controller_spec.rb +++ b/spec/controllers/statuses_controller_spec.rb @@ -57,11 +57,14 @@ describe StatusesController do let(:format) { 'html' } it 'renders status successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'public' - expect(response).to render_template(:show) + expect(response) + .to have_http_status(200) + .and render_template(:show) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('public'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) expect(response.body).to include status.text end end @@ -72,12 +75,15 @@ describe StatusesController do it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie' it 'renders ActivityPub Note object successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Content-Type']).to include 'application/activity+json' - json = body_as_json - expect(json[:content]).to include status.text + expect(response) + .to have_http_status(200) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Content-Type' => include('application/activity+json'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) + expect(body_as_json) + .to include(content: include(status.text)) end end end @@ -157,11 +163,14 @@ describe StatusesController do let(:format) { 'html' } it 'renders status successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'private' - expect(response).to render_template(:show) + expect(response) + .to have_http_status(200) + .and render_template(:show) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('private'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) expect(response.body).to include status.text end end @@ -170,13 +179,16 @@ describe StatusesController do let(:format) { 'json' } it 'renders ActivityPub Note object successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'private' - expect(response.headers['Content-Type']).to include 'application/activity+json' - json = body_as_json - expect(json[:content]).to include status.text + expect(response) + .to have_http_status(200) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('private'), + 'Content-Type' => include('application/activity+json'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) + expect(body_as_json) + .to include(content: include(status.text)) end end end @@ -194,11 +206,15 @@ describe StatusesController do let(:format) { 'html' } it 'renders status successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'private' - expect(response).to render_template(:show) + expect(response) + .to have_http_status(200) + .and render_template(:show) + + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('private'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) expect(response.body).to include status.text end end @@ -207,13 +223,16 @@ describe StatusesController do let(:format) { 'json' } it 'renders ActivityPub Note object successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'private' - expect(response.headers['Content-Type']).to include 'application/activity+json' - json = body_as_json - expect(json[:content]).to include status.text + expect(response) + .to have_http_status(200) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('private'), + 'Content-Type' => include('application/activity+json'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) + expect(body_as_json) + .to include(content: include(status.text)) end end end @@ -254,11 +273,14 @@ describe StatusesController do let(:format) { 'html' } it 'renders status successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'private' - expect(response).to render_template(:show) + expect(response) + .to have_http_status(200) + .and render_template(:show) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('private'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) expect(response.body).to include status.text end end @@ -267,13 +289,16 @@ describe StatusesController do let(:format) { 'json' } it 'renders ActivityPub Note object successfully' do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'private' - expect(response.headers['Content-Type']).to include 'application/activity+json' - json = body_as_json - expect(json[:content]).to include status.text + expect(response) + .to have_http_status(200) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('private'), + 'Content-Type' => include('application/activity+json'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) + expect(body_as_json) + .to include(content: include(status.text)) end end end @@ -340,11 +365,14 @@ describe StatusesController do let(:format) { 'html' } it 'renders status successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'private' - expect(response).to render_template(:show) + expect(response) + .to have_http_status(200) + .and render_template(:show) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('private'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) expect(response.body).to include status.text end end @@ -355,12 +383,15 @@ describe StatusesController do it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie' it 'renders ActivityPub Note object successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Content-Type']).to include 'application/activity+json' - json = body_as_json - expect(json[:content]).to include status.text + expect(response) + .to have_http_status(200) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Content-Type' => include('application/activity+json'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) + expect(body_as_json) + .to include(content: include(status.text)) end end end @@ -378,11 +409,14 @@ describe StatusesController do let(:format) { 'html' } it 'renders status successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'private' - expect(response).to render_template(:show) + expect(response) + .to have_http_status(200) + .and render_template(:show) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('private'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) expect(response.body).to include status.text end end @@ -391,13 +425,17 @@ describe StatusesController do let(:format) { 'json' } it 'renders ActivityPub Note object successfully' do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'private' - expect(response.headers['Content-Type']).to include 'application/activity+json' - json = body_as_json - expect(json[:content]).to include status.text + expect(response) + .to have_http_status(200) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('private'), + 'Content-Type' => include('application/activity+json'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) + + expect(body_as_json) + .to include(content: include(status.text)) end end end @@ -438,11 +476,14 @@ describe StatusesController do let(:format) { 'html' } it 'renders status successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'private' - expect(response).to render_template(:show) + expect(response) + .to have_http_status(200) + .and render_template(:show) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('private'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) expect(response.body).to include status.text end end @@ -451,13 +492,16 @@ describe StatusesController do let(:format) { 'json' } it 'renders ActivityPub Note object', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'private' - expect(response.headers['Content-Type']).to include 'application/activity+json' - json = body_as_json - expect(json[:content]).to include status.text + expect(response) + .to have_http_status(200) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('private'), + 'Content-Type' => include('application/activity+json'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) + expect(body_as_json) + .to include(content: include(status.text)) end end end @@ -732,11 +776,14 @@ describe StatusesController do end it 'renders status successfully', :aggregate_failures do - expect(response).to have_http_status(200) - expect(response.headers['Link'].to_s).to include 'activity+json' - expect(response.headers['Vary']).to eq 'Accept, Accept-Language, Cookie' - expect(response.headers['Cache-Control']).to include 'public' - expect(response).to render_template(:embed) + expect(response) + .to have_http_status(200) + .and render_template(:embed) + expect(response.headers).to include( + 'Vary' => 'Accept, Accept-Language, Cookie', + 'Cache-Control' => include('public'), + 'Link' => satisfy { |header| header.to_s.include?('activity+json') } + ) expect(response.body).to include status.text end end From 3f0c1566c34f4114d191e0eb94c0f1477874e091 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 16 Nov 2023 04:55:50 -0500 Subject: [PATCH 051/255] Reduce expectations for `RSpec/MultipleExpectations` cop in `api/v1/accounts/relationships` spec (#27879) --- .../api/v1/accounts/relationships_spec.rb | 130 ++++++++++-------- 1 file changed, 76 insertions(+), 54 deletions(-) diff --git a/spec/requests/api/v1/accounts/relationships_spec.rb b/spec/requests/api/v1/accounts/relationships_spec.rb index 5011352c6..e06ffdfae 100644 --- a/spec/requests/api/v1/accounts/relationships_spec.rb +++ b/spec/requests/api/v1/accounts/relationships_spec.rb @@ -27,12 +27,16 @@ describe 'GET /api/v1/accounts/relationships' do it 'returns JSON with correct data', :aggregate_failures do subject - json = body_as_json - - expect(response).to have_http_status(200) - expect(json).to be_a Enumerable - expect(json.first[:following]).to be true - expect(json.first[:followed_by]).to be false + expect(response) + .to have_http_status(200) + expect(body_as_json) + .to be_an(Enumerable) + .and have_attributes( + first: include( + following: true, + followed_by: false + ) + ) end end @@ -40,18 +44,19 @@ describe 'GET /api/v1/accounts/relationships' do let(:params) { { id: [simon.id, lewis.id, bob.id] } } context 'when there is returned JSON data' do - let(:json) { body_as_json } - context 'with default parameters' do it 'returns an enumerable json with correct elements, excluding suspended accounts', :aggregate_failures do subject - expect(response).to have_http_status(200) - expect(json).to be_a Enumerable - expect(json.size).to eq 2 - - expect_simon_item_one - expect_lewis_item_two + expect(response) + .to have_http_status(200) + expect(body_as_json) + .to be_an(Enumerable) + .and have_attributes( + size: 2, + first: include(simon_item), + second: include(lewis_item) + ) end end @@ -61,62 +66,75 @@ describe 'GET /api/v1/accounts/relationships' do it 'returns an enumerable json with correct elements, including suspended accounts', :aggregate_failures do subject - expect(response).to have_http_status(200) - expect(json).to be_a Enumerable - expect(json.size).to eq 3 - - expect_simon_item_one - expect_lewis_item_two - expect_bob_item_three + expect(response) + .to have_http_status(200) + expect(body_as_json) + .to be_an(Enumerable) + .and have_attributes( + size: 3, + first: include(simon_item), + second: include(lewis_item), + third: include(bob_item) + ) end end - def expect_simon_item_one - expect(json.first[:id]).to eq simon.id.to_s - expect(json.first[:following]).to be true - expect(json.first[:showing_reblogs]).to be true - expect(json.first[:followed_by]).to be false - expect(json.first[:muting]).to be false - expect(json.first[:requested]).to be false - expect(json.first[:domain_blocking]).to be false + def simon_item + { + id: simon.id.to_s, + following: true, + showing_reblogs: true, + followed_by: false, + muting: false, + requested: false, + domain_blocking: false, + } end - def expect_lewis_item_two - expect(json.second[:id]).to eq lewis.id.to_s - expect(json.second[:following]).to be false - expect(json.second[:showing_reblogs]).to be false - expect(json.second[:followed_by]).to be true - expect(json.second[:muting]).to be false - expect(json.second[:requested]).to be false - expect(json.second[:domain_blocking]).to be false + def lewis_item + { + id: lewis.id.to_s, + following: false, + showing_reblogs: false, + followed_by: true, + muting: false, + requested: false, + domain_blocking: false, + + } end - def expect_bob_item_three - expect(json.third[:id]).to eq bob.id.to_s - expect(json.third[:following]).to be false - expect(json.third[:showing_reblogs]).to be false - expect(json.third[:followed_by]).to be false - expect(json.third[:muting]).to be false - expect(json.third[:requested]).to be false - expect(json.third[:domain_blocking]).to be false + def bob_item + { + id: bob.id.to_s, + following: false, + showing_reblogs: false, + followed_by: false, + muting: false, + requested: false, + domain_blocking: false, + + } end end it 'returns JSON with correct data on previously cached requests' do # Initial request including multiple accounts in params get '/api/v1/accounts/relationships', headers: headers, params: { id: [simon.id, lewis.id] } - expect(body_as_json.size).to eq(2) + expect(body_as_json) + .to have_attributes(size: 2) # Subsequent request with different id, should override cache from first request get '/api/v1/accounts/relationships', headers: headers, params: { id: [simon.id] } - expect(response).to have_http_status(200) + expect(response) + .to have_http_status(200) expect(body_as_json) .to be_an(Enumerable) .and have_attributes( size: 1, - first: hash_including( + first: include( following: true, showing_reblogs: true ) @@ -129,13 +147,17 @@ describe 'GET /api/v1/accounts/relationships' do get '/api/v1/accounts/relationships', headers: headers, params: { id: [simon.id] } - expect(response).to have_http_status(200) + expect(response) + .to have_http_status(200) - json = body_as_json - - expect(json).to be_a Enumerable - expect(json.first[:following]).to be false - expect(json.first[:showing_reblogs]).to be false + expect(body_as_json) + .to be_an(Enumerable) + .and have_attributes( + first: include( + following: false, + showing_reblogs: false + ) + ) end end end From 8a285413f71eac89d87ab64c985cd9f33aabdaaa Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 16 Nov 2023 05:03:51 -0500 Subject: [PATCH 052/255] Reduce expectations for `RSpec/MultipleExpectations` cop in `MoveWorker` spec (#27880) --- spec/workers/move_worker_spec.rb | 36 +++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/spec/workers/move_worker_spec.rb b/spec/workers/move_worker_spec.rb index efad92c04..774296fda 100644 --- a/spec/workers/move_worker_spec.rb +++ b/spec/workers/move_worker_spec.rb @@ -35,17 +35,16 @@ describe MoveWorker do context 'when user notes are short enough' do it 'copies user note with prelude' do subject.perform(source_account.id, target_account.id) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(source_account.acct) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(account_note.comment) + expect(relevant_account_note.comment) + .to include(source_account.acct, account_note.comment) end it 'merges user notes when needed' do new_account_note = AccountNote.create!(account: account_note.account, target_account: target_account, comment: 'new note prior to move') subject.perform(source_account.id, target_account.id) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(source_account.acct) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(account_note.comment) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(new_account_note.comment) + expect(relevant_account_note.comment) + .to include(source_account.acct, account_note.comment, new_account_note.comment) end end @@ -54,16 +53,24 @@ describe MoveWorker do it 'copies user note without prelude' do subject.perform(source_account.id, target_account.id) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(account_note.comment) + expect(relevant_account_note.comment) + .to include(account_note.comment) end it 'keeps user notes unchanged' do new_account_note = AccountNote.create!(account: account_note.account, target_account: target_account, comment: 'new note prior to move') subject.perform(source_account.id, target_account.id) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(new_account_note.comment) + expect(relevant_account_note.comment) + .to include(new_account_note.comment) end end + + private + + def relevant_account_note + AccountNote.find_by(account: account_note.account, target_account: target_account) + end end shared_examples 'block and mute handling' do @@ -71,10 +78,19 @@ describe MoveWorker do subject.perform(source_account.id, target_account.id) expect(block_service).to have_received(:call).with(blocking_account, target_account) - expect(AccountNote.find_by(account: blocking_account, target_account: target_account).comment).to include(source_account.acct) - expect(muting_account.muting?(target_account)).to be true - expect(AccountNote.find_by(account: muting_account, target_account: target_account).comment).to include(source_account.acct) + + expect( + [note_account_comment, mute_account_comment] + ).to all include(source_account.acct) + end + + def note_account_comment + AccountNote.find_by(account: blocking_account, target_account: target_account).comment + end + + def mute_account_comment + AccountNote.find_by(account: muting_account, target_account: target_account).comment end end From 7232d4750dedcde879bde81889fbd028897e15b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:08:22 +0100 Subject: [PATCH 053/255] New Crowdin Translations (automated) (#27884) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/an.json | 1 - app/javascript/mastodon/locales/ar.json | 1 - app/javascript/mastodon/locales/ast.json | 1 - app/javascript/mastodon/locales/be.json | 13 ++++++++++++- app/javascript/mastodon/locales/bg.json | 14 +++++++++++++- app/javascript/mastodon/locales/bn.json | 1 - app/javascript/mastodon/locales/br.json | 1 - app/javascript/mastodon/locales/ca.json | 1 - app/javascript/mastodon/locales/ckb.json | 1 - app/javascript/mastodon/locales/co.json | 1 - app/javascript/mastodon/locales/cs.json | 1 - app/javascript/mastodon/locales/cy.json | 1 - app/javascript/mastodon/locales/da.json | 13 ++++++++++++- app/javascript/mastodon/locales/de.json | 13 ++++++++++++- app/javascript/mastodon/locales/el.json | 1 - app/javascript/mastodon/locales/en-GB.json | 13 ++++++++++++- app/javascript/mastodon/locales/eo.json | 1 - app/javascript/mastodon/locales/es-AR.json | 13 ++++++++++++- app/javascript/mastodon/locales/es-MX.json | 11 +++++++++++ app/javascript/mastodon/locales/es.json | 1 + app/javascript/mastodon/locales/et.json | 1 - app/javascript/mastodon/locales/eu.json | 13 ++++++++++++- app/javascript/mastodon/locales/fa.json | 9 ++++++++- app/javascript/mastodon/locales/fi.json | 13 ++++++++++++- app/javascript/mastodon/locales/fo.json | 1 - app/javascript/mastodon/locales/fr-QC.json | 1 - app/javascript/mastodon/locales/fr.json | 1 - app/javascript/mastodon/locales/fy.json | 1 - app/javascript/mastodon/locales/ga.json | 1 - app/javascript/mastodon/locales/gd.json | 1 - app/javascript/mastodon/locales/gl.json | 1 - app/javascript/mastodon/locales/he.json | 15 +++++++++++++-- app/javascript/mastodon/locales/hi.json | 1 - app/javascript/mastodon/locales/hr.json | 1 - app/javascript/mastodon/locales/hu.json | 13 ++++++++++++- app/javascript/mastodon/locales/hy.json | 1 - app/javascript/mastodon/locales/id.json | 1 - app/javascript/mastodon/locales/ig.json | 1 - app/javascript/mastodon/locales/io.json | 1 - app/javascript/mastodon/locales/is.json | 13 ++++++++++++- app/javascript/mastodon/locales/it.json | 13 ++++++++++++- app/javascript/mastodon/locales/ja.json | 2 +- app/javascript/mastodon/locales/ka.json | 1 - app/javascript/mastodon/locales/kab.json | 1 - app/javascript/mastodon/locales/kk.json | 1 - app/javascript/mastodon/locales/ko.json | 11 +++++++++++ app/javascript/mastodon/locales/ku.json | 1 - app/javascript/mastodon/locales/kw.json | 1 - app/javascript/mastodon/locales/lt.json | 12 ++++++++++++ app/javascript/mastodon/locales/lv.json | 1 - app/javascript/mastodon/locales/ml.json | 1 - app/javascript/mastodon/locales/mr.json | 1 - app/javascript/mastodon/locales/ms.json | 1 - app/javascript/mastodon/locales/my.json | 1 - app/javascript/mastodon/locales/nl.json | 11 +++++++++++ app/javascript/mastodon/locales/nn.json | 13 ++++++++++++- app/javascript/mastodon/locales/no.json | 13 ++++++++++++- app/javascript/mastodon/locales/oc.json | 1 - app/javascript/mastodon/locales/pa.json | 1 - app/javascript/mastodon/locales/pl.json | 11 +++++++++++ app/javascript/mastodon/locales/pt-BR.json | 1 - app/javascript/mastodon/locales/pt-PT.json | 13 ++++++++++++- app/javascript/mastodon/locales/ro.json | 1 - app/javascript/mastodon/locales/ru.json | 1 - app/javascript/mastodon/locales/sa.json | 1 - app/javascript/mastodon/locales/sc.json | 1 - app/javascript/mastodon/locales/sco.json | 1 - app/javascript/mastodon/locales/si.json | 1 - app/javascript/mastodon/locales/sk.json | 1 - app/javascript/mastodon/locales/sl.json | 1 - app/javascript/mastodon/locales/sq.json | 11 +++++++++++ app/javascript/mastodon/locales/sr-Latn.json | 1 - app/javascript/mastodon/locales/sr.json | 1 - app/javascript/mastodon/locales/sv.json | 10 +++++++++- app/javascript/mastodon/locales/ta.json | 1 - app/javascript/mastodon/locales/te.json | 1 - app/javascript/mastodon/locales/th.json | 13 ++++++++++++- app/javascript/mastodon/locales/tr.json | 13 ++++++++++++- app/javascript/mastodon/locales/tt.json | 1 - app/javascript/mastodon/locales/uk.json | 13 ++++++++++++- app/javascript/mastodon/locales/uz.json | 1 - app/javascript/mastodon/locales/vi.json | 1 - app/javascript/mastodon/locales/zgh.json | 1 - app/javascript/mastodon/locales/zh-CN.json | 13 ++++++++++++- app/javascript/mastodon/locales/zh-HK.json | 13 ++++++++++++- app/javascript/mastodon/locales/zh-TW.json | 13 ++++++++++++- config/locales/be.yml | 1 + config/locales/bg.yml | 1 + config/locales/da.yml | 1 + config/locales/de.yml | 1 + config/locales/es-AR.yml | 1 + config/locales/es-MX.yml | 1 + config/locales/fi.yml | 2 ++ config/locales/he.yml | 11 ++++++----- config/locales/hu.yml | 1 + config/locales/is.yml | 1 + config/locales/it.yml | 1 + config/locales/ko.yml | 1 + config/locales/lt.yml | 1 + config/locales/nl.yml | 1 + config/locales/nn.yml | 1 + config/locales/no.yml | 1 + config/locales/pl.yml | 1 + config/locales/pt-PT.yml | 1 + config/locales/simple_form.fi.yml | 2 +- config/locales/simple_form.he.yml | 6 +++--- config/locales/simple_form.ko.yml | 4 ++-- config/locales/sq.yml | 12 +++++++----- config/locales/th.yml | 1 + config/locales/uk.yml | 1 + config/locales/zh-HK.yml | 1 + config/locales/zh-TW.yml | 5 +++-- 112 files changed, 383 insertions(+), 98 deletions(-) diff --git a/app/javascript/mastodon/locales/an.json b/app/javascript/mastodon/locales/an.json index 6243f8d4c..a652272fa 100644 --- a/app/javascript/mastodon/locales/an.json +++ b/app/javascript/mastodon/locales/an.json @@ -334,7 +334,6 @@ "lists.search": "Buscar entre la chent a la quala sigues", "lists.subheading": "Las tuyas listas", "load_pending": "{count, plural, one {# nuevo elemento} other {# nuevos elementos}}", - "loading_indicator.label": "Cargando...", "media_gallery.toggle_visible": "{number, plural, one {Amaga la imachen} other {Amaga las imáchens}}", "moved_to_account_banner.text": "La tuya cuenta {disabledAccount} ye actualment deshabilitada perque t'has mudau a {movedToAccount}.", "mute_modal.duration": "Duración", diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index 4a5e04764..979bc9a70 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -389,7 +389,6 @@ "lists.search": "إبحث في قائمة الحسابات التي تُتابِعها", "lists.subheading": "قوائمك", "load_pending": "{count, plural, one {# عنصر جديد} other {# عناصر جديدة}}", - "loading_indicator.label": "جارٍ التحميل…", "media_gallery.toggle_visible": "{number, plural, zero {} one {اخف الصورة} two {اخف الصورتين} few {اخف الصور} many {اخف الصور} other {اخف الصور}}", "moved_to_account_banner.text": "حسابك {disabledAccount} معطل حاليًا لأنك انتقلت إلى {movedToAccount}.", "mute_modal.duration": "المدة", diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json index fed324e2d..0d49d9a19 100644 --- a/app/javascript/mastodon/locales/ast.json +++ b/app/javascript/mastodon/locales/ast.json @@ -272,7 +272,6 @@ "lists.search": "Buscar ente los perfiles que sigues", "lists.subheading": "Les tos llistes", "load_pending": "{count, plural, one {# elementu nuevu} other {# elementos nuevos}}", - "loading_indicator.label": "Cargando…", "media_gallery.toggle_visible": "{number, plural, one {Anubrir la imaxe} other {Anubrir les imáxenes}}", "mute_modal.duration": "Duración", "mute_modal.hide_notifications": "¿Quies anubrir los avisos d'esti perfil?", diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index e8a52ee29..4f5b247b6 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -390,7 +390,7 @@ "lists.search": "Шукайце сярод людзей, на якіх Вы падпісаны", "lists.subheading": "Вашыя спісы", "load_pending": "{count, plural, one {# новы элемент} few {# новыя элементы} many {# новых элементаў} other {# новых элементаў}}", - "loading_indicator.label": "Загрузка...", + "loading_indicator.label": "Загрузка…", "media_gallery.toggle_visible": "{number, plural, one {Схаваць відарыс} other {Схаваць відарысы}}", "moved_to_account_banner.text": "Ваш уліковы запіс {disabledAccount} зараз адключаны таму што вы перанесены на {movedToAccount}.", "mute_modal.duration": "Працягласць", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "На жаль, зараз немагчыма паказаць вынікі. Вы можаце паспрабаваць выкарыстоўваць пошук і праглядзець старонку агляду, каб знайсці людзей, на якіх можна падпісацца, або паўтарыце спробу пазней.", "onboarding.follows.lead": "Вы самі ствараеце свой хатні канал. Чым больш людзей вы падпішаце, тым больш актыўна і цікавей гэта будзе. Гэтыя профілі могуць стаць добрай адпраўной кропкай — вы заўсёды можаце адмяніць падпіску на іх пазней!", "onboarding.follows.title": "Папулярна на Mastodon", + "onboarding.profile.discoverable": "Уключыць профіль і допісы ў алгарытмы рэкамендацый", + "onboarding.profile.display_name": "Бачнае імя", + "onboarding.profile.display_name_hint": "Ваша поўнае імя або ваш псеўданім…", + "onboarding.profile.indexable": "Індэксаваць публічныя допісы ў пошукавых сістэмах", + "onboarding.profile.lead": "Вы заўсёды можаце выканаць гэта пазней у Наладах, дзе даступна яшчэ больш параметраў.", + "onboarding.profile.note": "Біяграфія", + "onboarding.profile.note_hint": "Вы можаце @згадаць іншых людзей або выкарыстоўваць #хэштэгі…", + "onboarding.profile.save_and_continue": "Захаваць і працягнуць", + "onboarding.profile.title": "Налады профілю", + "onboarding.profile.upload_avatar": "Загрузіць фота профілю", + "onboarding.profile.upload_header": "Загрузіць шапку профілю", "onboarding.share.lead": "Дайце людзям ведаць, як яны могуць знайсці вас на Mastodon!", "onboarding.share.message": "Я {username} на #Mastodon! Сачыце за мной на {url}", "onboarding.share.next_steps": "Магчымыя наступныя крокі:", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 83bffd946..b30dfecaa 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -222,6 +222,7 @@ "emoji_button.search_results": "Резултати от търсене", "emoji_button.symbols": "Символи", "emoji_button.travel": "Пътуване и места", + "empty_column.account_hides_collections": "Този потребител е избрал да не прави това сведение достъпно", "empty_column.account_suspended": "Спрян акаунт", "empty_column.account_timeline": "Тук няма публикации!", "empty_column.account_unavailable": "Профилът не е наличен", @@ -389,7 +390,7 @@ "lists.search": "Търсене измежду последваните", "lists.subheading": "Вашите списъци", "load_pending": "{count, plural, one {# нов елемент} other {# нови елемента}}", - "loading_indicator.label": "Зареждане...", + "loading_indicator.label": "Зареждане…", "media_gallery.toggle_visible": "Скриване на {number, plural, one {изображение} other {изображения}}", "moved_to_account_banner.text": "Вашият акаунт {disabledAccount} сега е изключен, защото се преместихте в {movedToAccount}.", "mute_modal.duration": "Времетраене", @@ -478,6 +479,17 @@ "onboarding.follows.empty": "За съжаление, в момента не могат да се показват резултати. Може да опитате да употребявате търсене или да прегледате страницата за изследване, за да намерите страница за последване, или да опитате пак по-късно.", "onboarding.follows.lead": "Може да бъдете куратор на началния си инфоканал. Последвайки повече хора, по-деен и по-интересен ще става. Тези профили може да са добра начална точка, от която винаги по-късно да спрете да следвате!", "onboarding.follows.title": "Популярно в Mastodon", + "onboarding.profile.discoverable": "Включване на профила и публикации в алгоритмите за откриване", + "onboarding.profile.display_name": "Името на показ", + "onboarding.profile.display_name_hint": "Вашето пълно име или псевдоним…", + "onboarding.profile.indexable": "Включване на обществени публикации в резултатите от търсене", + "onboarding.profile.lead": "Винаги може да завършите това по-късно в настройките, където дори има повече възможности за настройване.", + "onboarding.profile.note": "Биогр.", + "onboarding.profile.note_hint": "Може да @споменавате други хора или #хаштагове…", + "onboarding.profile.save_and_continue": "Запазване и продължаване", + "onboarding.profile.title": "Настройване на профила", + "onboarding.profile.upload_avatar": "Качване на снимка на профила", + "onboarding.profile.upload_header": "Качване на заглавка на профила", "onboarding.share.lead": "Позволете на хората да знаят, че могат да ви намерят в Mastodon!", "onboarding.share.message": "Аз съм {username} в #Mastodon! Елате да ме последвате при {url}", "onboarding.share.next_steps": "Възможни следващи стъпки:", diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json index 85d6f2474..b6e4fbb96 100644 --- a/app/javascript/mastodon/locales/bn.json +++ b/app/javascript/mastodon/locales/bn.json @@ -314,7 +314,6 @@ "lists.search": "যাদের অনুসরণ করেন তাদের ভেতরে খুঁজুন", "lists.subheading": "আপনার তালিকা", "load_pending": "{count, plural, one {# নতুন জিনিস} other {# নতুন জিনিস}}", - "loading_indicator.label": "আসছে...", "media_gallery.toggle_visible": "দৃশ্যতার অবস্থা বদলান", "mute_modal.duration": "সময়কাল", "mute_modal.hide_notifications": "এই ব্যবহারকারীর প্রজ্ঞাপন বন্ধ করবেন ?", diff --git a/app/javascript/mastodon/locales/br.json b/app/javascript/mastodon/locales/br.json index 8449762c2..39cd73241 100644 --- a/app/javascript/mastodon/locales/br.json +++ b/app/javascript/mastodon/locales/br.json @@ -329,7 +329,6 @@ "lists.search": "Klask e-touez tud heuliet ganeoc'h", "lists.subheading": "Ho listennoù", "load_pending": "{count, plural, one {# dra nevez} other {# dra nevez}}", - "loading_indicator.label": "O kargañ...", "media_gallery.toggle_visible": "{number, plural, one {Kuzhat ar skeudenn} other {Kuzhat ar skeudenn}}", "mute_modal.duration": "Padelezh", "mute_modal.hide_notifications": "Kuzhat kemenadennoù eus an implijer-se ?", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 99cae584b..926343f67 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -390,7 +390,6 @@ "lists.search": "Cerca entre les persones que segueixes", "lists.subheading": "Les teves llistes", "load_pending": "{count, plural, one {# element nou} other {# elements nous}}", - "loading_indicator.label": "Es carrega...", "media_gallery.toggle_visible": "{number, plural, one {Amaga la imatge} other {Amaga les imatges}}", "moved_to_account_banner.text": "El teu compte {disabledAccount} està desactivat perquè l'has mogut a {movedToAccount}.", "mute_modal.duration": "Durada", diff --git a/app/javascript/mastodon/locales/ckb.json b/app/javascript/mastodon/locales/ckb.json index 381eaa5b1..7e9641832 100644 --- a/app/javascript/mastodon/locales/ckb.json +++ b/app/javascript/mastodon/locales/ckb.json @@ -342,7 +342,6 @@ "lists.search": "بگەڕێ لەناو ئەو کەسانەی کە شوێنیان کەوتویت", "lists.subheading": "لیستەکانت", "load_pending": "{count, plural, one {# بەڕگەی نوێ} other {# بەڕگەی نوێ}}", - "loading_indicator.label": "بارکردن...", "media_gallery.toggle_visible": "شاردنەوەی {number, plural, one {image} other {images}}", "moved_to_account_banner.text": "ئەکاونتەکەت {disabledAccount} لە ئێستادا لەکارخراوە چونکە تۆ چوویتە {movedToAccount}.", "mute_modal.duration": "ماوە", diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json index 1d878a0cd..d4bb2f82b 100644 --- a/app/javascript/mastodon/locales/co.json +++ b/app/javascript/mastodon/locales/co.json @@ -236,7 +236,6 @@ "lists.search": "Circà indè i vostr'abbunamenti", "lists.subheading": "E vo liste", "load_pending": "{count, plural, one {# entrata nova} other {# entrate nove}}", - "loading_indicator.label": "Caricamentu...", "media_gallery.toggle_visible": "Piattà {number, plural, one {ritrattu} other {ritratti}}", "mute_modal.duration": "Durata", "mute_modal.hide_notifications": "Piattà nutificazione da st'utilizatore?", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index aaf50d67c..20ef43733 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -386,7 +386,6 @@ "lists.search": "Hledejte mezi lidmi, které sledujete", "lists.subheading": "Vaše seznamy", "load_pending": "{count, plural, one {# nová položka} few {# nové položky} many {# nových položek} other {# nových položek}}", - "loading_indicator.label": "Načítání...", "media_gallery.toggle_visible": "{number, plural, one {Skrýt obrázek} few {Skrýt obrázky} many {Skrýt obrázky} other {Skrýt obrázky}}", "moved_to_account_banner.text": "Váš účet {disabledAccount} je momentálně deaktivován, protože jste se přesunul/a na {movedToAccount}.", "mute_modal.duration": "Trvání", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 183ab6955..dcd5406d0 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -390,7 +390,6 @@ "lists.search": "Chwilio ymysg pobl rydych yn eu dilyn", "lists.subheading": "Eich rhestrau", "load_pending": "{count, plural, one {# eitem newydd} other {# eitem newydd}}", - "loading_indicator.label": "Llwytho...", "media_gallery.toggle_visible": "{number, plural, one {Cuddio delwedd} other {Cuddio delwedd}}", "moved_to_account_banner.text": "Ar hyn y bryd, mae eich cyfrif {disabledAccount} wedi ei analluogi am i chi symud i {movedToAccount}.", "mute_modal.duration": "Hyd", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index bb8b72bca..33eda6f43 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -390,7 +390,7 @@ "lists.search": "Søg blandt personer, som følges", "lists.subheading": "Dine lister", "load_pending": "{count, plural, one {# nyt emne} other {# nye emner}}", - "loading_indicator.label": "Indlæser...", + "loading_indicator.label": "Indlæser…", "media_gallery.toggle_visible": "{number, plural, one {Skjul billede} other {Skjul billeder}}", "moved_to_account_banner.text": "Din konto {disabledAccount} er pt. deaktiveret, da du flyttede til {movedToAccount}.", "mute_modal.duration": "Varighed", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Ingen resultater tilgængelige pt. Prøv at bruge søgning eller gennemse siden for at finde personer at følge, eller forsøg igen senere.", "onboarding.follows.lead": "Man kurerer sin eget hjemme-feed. Jo flere personer man følger, des mere aktiv og interessant vil det være. Disse profiler kan være et godt udgangspunkt – de kan altid fjernes senere!", "onboarding.follows.title": "Populært på Mastodon", + "onboarding.profile.discoverable": "Fremhæv profil og indlæg i detekteringsalgoritmer", + "onboarding.profile.display_name": "Visningsnavn", + "onboarding.profile.display_name_hint": "Fulde navn eller dit sjove navn…", + "onboarding.profile.indexable": "Medtag offentlige indlæg i søgeresultater", + "onboarding.profile.lead": "Dette kan altid færdiggøres senere i indstillingerne, hvor endnu flere tilpasningsmuligheder forefindes.", + "onboarding.profile.note": "Bio", + "onboarding.profile.note_hint": "Man kan @omtale andre personer eller #hashtags…", + "onboarding.profile.save_and_continue": "Gem og fortsæt", + "onboarding.profile.title": "Profilopsætning", + "onboarding.profile.upload_avatar": "Upload profilbillede", + "onboarding.profile.upload_header": "Upload profiloverskrift", "onboarding.share.lead": "Lad folk vide, hvordan de kan finde dig på Mastodon!", "onboarding.share.message": "Jeg er {username} på #Mastodon! Følg mig på {url}", "onboarding.share.next_steps": "Mulige næste trin:", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index e4f7fe6ce..5c1ccf46d 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -390,7 +390,7 @@ "lists.search": "Suche nach Leuten, denen du folgst", "lists.subheading": "Deine Listen", "load_pending": "{count, plural, one {# neuer Beitrag} other {# neue Beiträge}}", - "loading_indicator.label": "Wird geladen …", + "loading_indicator.label": "Wird geladen …", "media_gallery.toggle_visible": "{number, plural, one {Medium ausblenden} other {Medien ausblenden}}", "moved_to_account_banner.text": "Dein Konto {disabledAccount} ist derzeit deaktiviert, weil du zu {movedToAccount} umgezogen bist.", "mute_modal.duration": "Dauer", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Bedauerlicherweise können aktuell keine Ergebnisse angezeigt werden. Du kannst die Suche verwenden oder den Reiter „Entdecken“ auswählen, um neue Leute zum Folgen zu finden – oder du versuchst es später erneut.", "onboarding.follows.lead": "Deine Startseite ist der primäre Anlaufpunkt, um Mastodon zu erleben. Je mehr Profilen du folgst, umso aktiver und interessanter wird sie. Damit du direkt loslegen kannst, gibt es hier ein paar Vorschläge:", "onboarding.follows.title": "Personalisiere deine Startseite", + "onboarding.profile.discoverable": "Profil und Beiträge in Suchalgorithmen berücksichtigen", + "onboarding.profile.display_name": "Anzeigename", + "onboarding.profile.display_name_hint": "Dein richtiger Name oder dein Fantasiename …", + "onboarding.profile.indexable": "Öffentliche Beiträge in die Suchergebnisse einbeziehen", + "onboarding.profile.lead": "Du kannst das später in den Einstellungen vervollständigen, wo noch mehr Anpassungsmöglichkeiten zur Verfügung stehen.", + "onboarding.profile.note": "Über mich", + "onboarding.profile.note_hint": "Du kannst andere @Profile erwähnen oder #Hashtags verwenden …", + "onboarding.profile.save_and_continue": "Speichern und fortsetzen", + "onboarding.profile.title": "Profil einrichten", + "onboarding.profile.upload_avatar": "Profilbild hochladen", + "onboarding.profile.upload_header": "Titelbild hochladen", "onboarding.share.lead": "Lass die Leute wissen, wie sie dich auf Mastodon finden können!", "onboarding.share.message": "Ich bin {username} auf #Mastodon! Folge mir auf {url}", "onboarding.share.next_steps": "Mögliche nächste Schritte:", diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index d3be386b4..31806bcfb 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -345,7 +345,6 @@ "lists.search": "Αναζήτησε μεταξύ των ανθρώπων που ακουλουθείς", "lists.subheading": "Οι λίστες σου", "load_pending": "{count, plural, one {# νέο στοιχείο} other {# νέα στοιχεία}}", - "loading_indicator.label": "Φορτώνει...", "media_gallery.toggle_visible": "{number, plural, one {Απόκρυψη εικόνας} other {Απόκρυψη εικόνων}}", "moved_to_account_banner.text": "Ο λογαριασμός σου {disabledAccount} είναι προσωρινά απενεργοποιημένος επειδή μεταφέρθηκες στον {movedToAccount}.", "mute_modal.duration": "Διάρκεια", diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index 20ed8937b..d00782592 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -389,7 +389,7 @@ "lists.search": "Search among people you follow", "lists.subheading": "Your lists", "load_pending": "{count, plural, one {# new item} other {# new items}}", - "loading_indicator.label": "Loading...", + "loading_indicator.label": "Loading…", "media_gallery.toggle_visible": "{number, plural, one {Hide image} other {Hide images}}", "moved_to_account_banner.text": "Your account {disabledAccount} is currently disabled because you moved to {movedToAccount}.", "mute_modal.duration": "Duration", @@ -478,6 +478,17 @@ "onboarding.follows.empty": "Unfortunately, no results can be shown right now. You can try using search or browsing the explore page to find people to follow, or try again later.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Personalize your home feed", + "onboarding.profile.discoverable": "Feature profile and posts in discovery algorithms", + "onboarding.profile.display_name": "Display name", + "onboarding.profile.display_name_hint": "Your full name or your fun name…", + "onboarding.profile.indexable": "Include public posts in search results", + "onboarding.profile.lead": "You can always complete this later in the settings, where even more customisation options are available.", + "onboarding.profile.note": "Bio", + "onboarding.profile.note_hint": "You can @mention other people or #hashtags…", + "onboarding.profile.save_and_continue": "Save and continue", + "onboarding.profile.title": "Profile setup", + "onboarding.profile.upload_avatar": "Upload profile picture", + "onboarding.profile.upload_header": "Upload profile header", "onboarding.share.lead": "Let people know how they can find you on Mastodon!", "onboarding.share.message": "I'm {username} on #Mastodon! Come follow me at {url}", "onboarding.share.next_steps": "Possible next steps:", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 6b4258a6b..5679d5e41 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -365,7 +365,6 @@ "lists.search": "Serĉi inter la homoj, kiujn vi sekvas", "lists.subheading": "Viaj listoj", "load_pending": "{count,plural, one {# nova elemento} other {# novaj elementoj}}", - "loading_indicator.label": "Ŝargado…", "media_gallery.toggle_visible": "{number, plural, one {Kaŝi la bildon} other {Kaŝi la bildojn}}", "moved_to_account_banner.text": "Via konto {disabledAccount} estas malvalidigita ĉar vi movis ĝin al {movedToAccount}.", "mute_modal.duration": "Daŭro", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 71d6e3119..680336369 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -390,7 +390,7 @@ "lists.search": "Buscar entre la gente que seguís", "lists.subheading": "Tus listas", "load_pending": "{count, plural, one {# elemento nuevo} other {# elementos nuevos}}", - "loading_indicator.label": "Cargando...", + "loading_indicator.label": "Cargando…", "media_gallery.toggle_visible": "Ocultar {number, plural, one {imagen} other {imágenes}}", "moved_to_account_banner.text": "Tu cuenta {disabledAccount} está actualmente deshabilitada porque te mudaste a {movedToAccount}.", "mute_modal.duration": "Duración", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Desafortunadamente, no se pueden mostrar resultados en este momento. Podés intentar usar la búsqueda o navegar por la página de exploración para encontrar cuentas a las que seguir, o intentarlo de nuevo más tarde.", "onboarding.follows.lead": "Tu línea temporal de inicio es la forma principal de experimentar Mastodon. Cuanta más cuentas sigás, más activa e interesante será. Para empezar, acá tenés algunas sugerencias:", "onboarding.follows.title": "Personalizá tu línea de tiempo principal", + "onboarding.profile.discoverable": "Destacar perfil y mensajes en algoritmos de descubrimiento", + "onboarding.profile.display_name": "Nombre para mostrar", + "onboarding.profile.display_name_hint": "Tu nombre completo o tu pseudónimo…", + "onboarding.profile.indexable": "Incluir mensajes públicos en resultados de búsqueda", + "onboarding.profile.lead": "Siempre podés completar esto más tarde en la configuración, donde hay disponibles más opciones de personalización.", + "onboarding.profile.note": "Biografía", + "onboarding.profile.note_hint": "Podés @mencionar otras cuentas o usar #etiquetas…", + "onboarding.profile.save_and_continue": "Guardar y continuar", + "onboarding.profile.title": "Configuración del perfil", + "onboarding.profile.upload_avatar": "Subir avatar", + "onboarding.profile.upload_header": "Subir cabecera", "onboarding.share.lead": "¡Decile a la gente cómo te pueden encontrar en Mastodon!", "onboarding.share.message": "¡En #Mastodon soy «{username}»! Podés seguirme desde {url}", "onboarding.share.next_steps": "Posibles próximos pasos:", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index aadc901f9..aa8a21edb 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Desafortunadamente, no se pueden mostrar resultados en este momento. Puedes intentar usar la búsqueda o navegar por la página de exploración para encontrar gente a la que seguir, o inténtalo de nuevo más tarde.", "onboarding.follows.lead": "Tienes que personalizar tu inicio. Cuantas más personas sigas, más activo e interesante será. Estos perfiles pueden ser un buen punto de partida, ¡pero siempre puedes dejar de seguirlos más adelante!", "onboarding.follows.title": "Popular en Mastodon", + "onboarding.profile.discoverable": "Destacar el perfil y las publicaciones en el algoritmo de descubrimiento", + "onboarding.profile.display_name": "Nombre a mostrar", + "onboarding.profile.display_name_hint": "Tu nombre completo o tu apodo…", + "onboarding.profile.indexable": "Incluir publicaciones públicas en los resultados de búsqueda", + "onboarding.profile.lead": "Siempre puedes completar esto más tarde en los ajustes, donde hay aún más opciones de personalización disponibles.", + "onboarding.profile.note": "Biografía", + "onboarding.profile.note_hint": "Puedes @mencionar a otras personas o #hashtags…", + "onboarding.profile.save_and_continue": "Guardar y continuar", + "onboarding.profile.title": "Configuración del perfil", + "onboarding.profile.upload_avatar": "Subir foto de perfil", + "onboarding.profile.upload_header": "Subir foto de cabecera", "onboarding.share.lead": "¡Dile a la gente cómo te pueden encontrar en Mastodon!", "onboarding.share.message": "¡Soy {username} en #Mastodon! Ven a seguirme en {url}", "onboarding.share.next_steps": "Posibles siguientes pasos:", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index f3735d968..5d1aa004b 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -479,6 +479,7 @@ "onboarding.follows.empty": "Desafortunadamente, no se pueden mostrar resultados en este momento. Puedes intentar usar la búsqueda o navegar por la página de exploración para encontrar personas a las que seguir, o inténtalo de nuevo más tarde.", "onboarding.follows.lead": "Tu línea de inicio es la forma principal de experimentar Mastodon. Cuanta más personas sigas, más activa e interesante será. Para empezar, aquí hay algunas sugerencias:", "onboarding.follows.title": "Personaliza tu línea de inicio", + "onboarding.profile.display_name": "Nombre para mostrar", "onboarding.share.lead": "¡Cuéntale a otras personas cómo te pueden encontrar en Mastodon!", "onboarding.share.message": "¡Soy {username} en #Mastodon! Ven a seguirme en {url}", "onboarding.share.next_steps": "Posibles siguientes pasos:", diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index c4182a073..3b6d86a9d 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -390,7 +390,6 @@ "lists.search": "Otsi enda jälgitavate inimeste hulgast", "lists.subheading": "Sinu nimekirjad", "load_pending": "{count, plural, one {# uus kirje} other {# uut kirjet}}", - "loading_indicator.label": "Laeb..", "media_gallery.toggle_visible": "{number, plural, one {Varja pilt} other {Varja pildid}}", "moved_to_account_banner.text": "Kontot {disabledAccount} ei ole praegu võimalik kasutada, sest kolisid kontole {movedToAccount}.", "mute_modal.duration": "Kestus", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index 419589aba..88f70cffb 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -390,7 +390,7 @@ "lists.search": "Bilatu jarraitzen dituzun pertsonen artean", "lists.subheading": "Zure zerrendak", "load_pending": "{count, plural, one {elementu berri #} other {# elementu berri}}", - "loading_indicator.label": "Kargatzen...", + "loading_indicator.label": "Kargatzen…", "media_gallery.toggle_visible": "Txandakatu ikusgaitasuna", "moved_to_account_banner.text": "Zure {disabledAccount} kontua desgaituta dago une honetan, {movedToAccount} kontura aldatu zinelako.", "mute_modal.duration": "Iraupena", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Zoritxarrez, ezin da emaitzik erakutsi orain. Bilaketa erabil dezakezu edo Arakatu orrian jendea bilatu jarraitzeko, edo saiatu geroago.", "onboarding.follows.lead": "Hasierako orria zuk pertsonalizatzen duzu. Gero eta jende gehiagori jarraitu, orduan eta aktibo eta interesgarriago izango da. Profil hauek egokiak izan daitezke hasteko, beti ere, geroago jarraitzeari utz diezazkiekezu!", "onboarding.follows.title": "Mastodonen pil-pilean", + "onboarding.profile.discoverable": "Ezagutarazi profila eta bidalketak bilaketa algoritmoetan", + "onboarding.profile.display_name": "Bistaratzeko izena", + "onboarding.profile.display_name_hint": "Zure izena edo ezizena…", + "onboarding.profile.indexable": "Gehitu argitalpen publikoak bilaketa-emaitzetan", + "onboarding.profile.lead": "Geroagoago bete daiteke konfigurazioan, non pertsonalizatzeko aukera gehiago dauden.", + "onboarding.profile.note": "Biografia", + "onboarding.profile.note_hint": "Beste pertsona batzuk @aipa ditzakezu edo #traolak erabili…", + "onboarding.profile.save_and_continue": "Gorde eta jarraitu", + "onboarding.profile.title": "Profilaren konfigurazioa", + "onboarding.profile.upload_avatar": "Igo profilaren irudia", + "onboarding.profile.upload_header": "Igo profilaren goiburua", "onboarding.share.lead": "Esan jendeari nola aurki zaitzaketen Mastodonen!", "onboarding.share.message": "{username} naiz #Mastodon-en! Jarrai nazazu hemen: {url}", "onboarding.share.next_steps": "Hurrengo urrats posibleak:", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 246f21899..97dae30d4 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -390,7 +390,7 @@ "lists.search": "جستوجو بین کسانی که پیگرفتهاید", "lists.subheading": "سیاهههایتان", "load_pending": "{count, plural, one {# مورد جدید} other {# مورد جدید}}", - "loading_indicator.label": "بار کردن…", + "loading_indicator.label": "در حال بارگذاری…", "media_gallery.toggle_visible": "{number, plural, one {نهفتن تصویر} other {نهفتن تصاویر}}", "moved_to_account_banner.text": "حسابتان {disabledAccount} اکنون از کار افتاده؛ چرا که به {movedToAccount} منتقل شدید.", "mute_modal.duration": "مدت زمان", @@ -479,6 +479,13 @@ "onboarding.follows.empty": "متأسفانه هماکنون نتیجهای قابل نمایش نیست. میتوانید استفاده از جستوجو یا مرور صفحهٔ کاوش را برای یافتن افرادی برای پیگیری آزموده یا دوباره تلاش کنید.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.discoverable": "معرفی نمایه و فرستهها در الگوریتمهای کشف", + "onboarding.profile.display_name": "نام نمایشی", + "onboarding.profile.display_name_hint": "نام کامل یا نام باحالتان…", + "onboarding.profile.note": "درباره شما", + "onboarding.profile.note_hint": "میتوانید افراد دیگر را @نامبردن یا #برچسب بزنید…", + "onboarding.profile.save_and_continue": "ذخیره کن و ادامه بده", + "onboarding.profile.title": "تنظیم نمایه", "onboarding.share.lead": "بگذارید افراد بدانند چگونه میتوانند در ماستادون بیابندتان!", "onboarding.share.message": "من {username} روی #ماستودون هستم! مرا در {url} پیبگیرید", "onboarding.share.next_steps": "گامهای ممکن بعدی:", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 9aa2e7355..849a7f463 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -390,7 +390,7 @@ "lists.search": "Etsi seuraamistasi henkilöistä", "lists.subheading": "Omat listasi", "load_pending": "{count, plural, one {# uusi kohde} other {# uutta kohdetta}}", - "loading_indicator.label": "Ladataan...", + "loading_indicator.label": "Ladataan…", "media_gallery.toggle_visible": "{number, plural, one {Piilota kuva} other {Piilota kuvat}}", "moved_to_account_banner.text": "Tilisi {disabledAccount} on tällä hetkellä poissa käytöstä, koska teit siirron tiliin {movedToAccount}.", "mute_modal.duration": "Kesto", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Valitettavasti tuloksia ei voida näyttää juuri nyt. Voit kokeilla hakua tai selata tutustumissivua löytääksesi seurattavaa tai yrittää myöhemmin uudelleen.", "onboarding.follows.lead": "Kokoat oman kotisyötteesi itse. Mitä enemmän ihmisiä seuraat, sitä aktiivisempi ja kiinnostavampi syöte on. Nämä profiilit voivat olla alkuun hyvä lähtökohta — voit aina lopettaa niiden seuraamisen myöhemmin!", "onboarding.follows.title": "Mukauta kotisyötettäsi", + "onboarding.profile.discoverable": "Pidä profiilia ja julkaisuja esillä löytämisalgoritmeissa", + "onboarding.profile.display_name": "Näyttönimi", + "onboarding.profile.display_name_hint": "Koko nimesi tai lempinimesi…", + "onboarding.profile.indexable": "Sisällytä julkiset julkaisut hakutuloksiin", + "onboarding.profile.lead": "Voit viimeistellä tämän milloin tahansa asetuksissa, jossa on saatavilla vielä enemmän mukautusvalintoja.", + "onboarding.profile.note": "Elämäkerta", + "onboarding.profile.note_hint": "Voit @mainita muita käyttäjiä tai #aihetunnisteita…", + "onboarding.profile.save_and_continue": "Tallenna ja jatka", + "onboarding.profile.title": "Profiilin määritys", + "onboarding.profile.upload_avatar": "Lataa profiilikuva", + "onboarding.profile.upload_header": "Lataa profiilin otsakekuva", "onboarding.share.lead": "Kerro ihmisille, kuinka he voivat löytää sinut Mastodonista!", "onboarding.share.message": "Olen {username} #Mastodonissa! Seuraa minua osoitteessa {url}", "onboarding.share.next_steps": "Mahdolliset seuraavat vaiheet:", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index 42a1317db..61c1287ea 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -390,7 +390,6 @@ "lists.search": "Leita millum fólk, sum tú fylgir", "lists.subheading": "Tínir listar", "load_pending": "{count, plural, one {# nýtt evni} other {# nýggj evni}}", - "loading_indicator.label": "Innlesi...", "media_gallery.toggle_visible": "{number, plural, one {Fjal mynd} other {Fjal myndir}}", "moved_to_account_banner.text": "Konta tín {disabledAccount} er í løtuni óvirkin, tí tú flutti til {movedToAccount}.", "mute_modal.duration": "Tíðarbil", diff --git a/app/javascript/mastodon/locales/fr-QC.json b/app/javascript/mastodon/locales/fr-QC.json index a6dd91bec..e858882f8 100644 --- a/app/javascript/mastodon/locales/fr-QC.json +++ b/app/javascript/mastodon/locales/fr-QC.json @@ -390,7 +390,6 @@ "lists.search": "Rechercher parmi les gens que vous suivez", "lists.subheading": "Vos listes", "load_pending": "{count, plural, one {# nouvel élément} other {# nouveaux éléments}}", - "loading_indicator.label": "Chargement…", "media_gallery.toggle_visible": "{number, plural, one {Cacher l’image} other {Cacher les images}}", "moved_to_account_banner.text": "Votre compte {disabledAccount} est actuellement désactivé parce que vous avez déménagé sur {movedToAccount}.", "mute_modal.duration": "Durée", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 0d2ba2bb9..a7bb4a12f 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -390,7 +390,6 @@ "lists.search": "Rechercher parmi les gens que vous suivez", "lists.subheading": "Vos listes", "load_pending": "{count, plural, one {# nouvel élément} other {# nouveaux éléments}}", - "loading_indicator.label": "Chargement…", "media_gallery.toggle_visible": "{number, plural, one {Cacher l’image} other {Cacher les images}}", "moved_to_account_banner.text": "Votre compte {disabledAccount} est actuellement désactivé parce que vous l'avez déplacé à {movedToAccount}.", "mute_modal.duration": "Durée", diff --git a/app/javascript/mastodon/locales/fy.json b/app/javascript/mastodon/locales/fy.json index 9d3b41606..2128a045b 100644 --- a/app/javascript/mastodon/locales/fy.json +++ b/app/javascript/mastodon/locales/fy.json @@ -390,7 +390,6 @@ "lists.search": "Sykje nei minsken dy’t jo folgje", "lists.subheading": "Jo listen", "load_pending": "{count, plural, one {# nij item} other {# nije items}}", - "loading_indicator.label": "Lade…", "media_gallery.toggle_visible": "{number, plural, one {ôfbylding ferstopje} other {ôfbyldingen ferstopje}}", "moved_to_account_banner.text": "Omdat jo nei {movedToAccount} ferhuze binne is jo account {disabledAccount} op dit stuit útskeakele.", "mute_modal.duration": "Doer", diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index 388a557e8..ee6b44c88 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -316,7 +316,6 @@ "lists.replies_policy.title": "Taispeáin freagraí:", "lists.search": "Cuardaigh i measc daoine atá á leanúint agat", "lists.subheading": "Do liostaí", - "loading_indicator.label": "Ag lódáil...", "mute_modal.duration": "Tréimhse", "mute_modal.hide_notifications": "Cuir póstalacha ón t-úsáideoir seo i bhfolach?", "mute_modal.indefinite": "Gan téarma", diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json index 4f485cfc5..91333c1a0 100644 --- a/app/javascript/mastodon/locales/gd.json +++ b/app/javascript/mastodon/locales/gd.json @@ -389,7 +389,6 @@ "lists.search": "Lorg am measg nan daoine a leanas tu", "lists.subheading": "Na liostaichean agad", "load_pending": "{count, plural, one {# nì ùr} two {# nì ùr} few {# nithean ùra} other {# nì ùr}}", - "loading_indicator.label": "’Ga luchdadh…", "media_gallery.toggle_visible": "{number, plural, 1 {Falaich an dealbh} one {Falaich na dealbhan} two {Falaich na dealbhan} few {Falaich na dealbhan} other {Falaich na dealbhan}}", "moved_to_account_banner.text": "Tha an cunntas {disabledAccount} agad à comas on a rinn thu imrich gu {movedToAccount}.", "mute_modal.duration": "Faide", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index e79e54926..7d2c6dab9 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -390,7 +390,6 @@ "lists.search": "Procurar entre as persoas que segues", "lists.subheading": "As túas listaxes", "load_pending": "{count, plural, one {# novo elemento} other {# novos elementos}}", - "loading_indicator.label": "Estase a cargar...", "media_gallery.toggle_visible": "Agochar {number, plural, one {imaxe} other {imaxes}}", "moved_to_account_banner.text": "A túa conta {disabledAccount} está actualmente desactivada porque movéchela a {movedToAccount}.", "mute_modal.duration": "Duración", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 485e8313a..2e0009170 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -390,7 +390,7 @@ "lists.search": "חיפוש בין אנשים שאני עוקב\\ת אחריהם", "lists.subheading": "הרשימות שלך", "load_pending": "{count, plural, one {# פריט חדש} other {# פריטים חדשים}}", - "loading_indicator.label": "טוען...", + "loading_indicator.label": "בטעינה…", "media_gallery.toggle_visible": "{number, plural, one {להסתיר תמונה} two {להסתיר תמונותיים} many {להסתיר תמונות} other {להסתיר תמונות}}", "moved_to_account_banner.text": "חשבונך {disabledAccount} אינו פעיל כרגע עקב מעבר ל{movedToAccount}.", "mute_modal.duration": "משך הזמן", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "למצער, תוצאות לחיפושך אינן בנמצא. ניתן להשתמש בחיפוש או בדף החקירות לשם מציאת אנשים ולעקבם. אפשר גם לנסות שוב אחר כך.", "onboarding.follows.lead": "אתם אוצרים את הזרם הבייתי שלכם. ככל שתעקבו אחרי יותר אנשים, הוא יהיה עשיר ופעיל יותר. הנה כמה פרופילים להתחיל בהם - תמיד ניתן להפסיק מעקב אחריהם בהמשך!", "onboarding.follows.title": "פופולארי על מסטודון", + "onboarding.profile.discoverable": "הצגת פרופיל והודעות במסך התגליות", + "onboarding.profile.display_name": "שם להצגה", + "onboarding.profile.display_name_hint": "שמך המלא או כינוי הכיף שלך…", + "onboarding.profile.indexable": "הכללת הודעות ציבוריות בתוצאות החיפוש", + "onboarding.profile.lead": "תמיד ניתן להשלים זאת אחר כך בהגדרות, שם יש אפילו עוד אפשרויות להתאמה אישית.", + "onboarding.profile.note": "אודות", + "onboarding.profile.note_hint": "ניתן @לאזכר משתמשים אחרים או #תגיות…", + "onboarding.profile.save_and_continue": "לשמור ולהמשיך", + "onboarding.profile.title": "הגדרת פרופיל", + "onboarding.profile.upload_avatar": "העלאת תמונת פרופיל", + "onboarding.profile.upload_header": "העלאת כותרת פרופיל", "onboarding.share.lead": "כדאי להודיע לחברים היכן למצוא אותך במסטודון!", "onboarding.share.message": "אני {username} ברשת #מסטודון! בואו לעקוב אחרי בכתובת {url}", "onboarding.share.next_steps": "לאיפה להמשיך מכאן:", @@ -518,7 +529,7 @@ "privacy.private.short": "לעוקבים בלבד", "privacy.public.long": "גלוי לכל", "privacy.public.short": "פומבי", - "privacy.unlisted.long": "גלוי לכל, אבל מוסתר מאמצעי גילוי", + "privacy.unlisted.long": "גלוי לכל, אבל מוסתר מאמצעי תגלית", "privacy.unlisted.short": "לא רשום (לא לפיד הכללי)", "privacy_policy.last_updated": "עודכן לאחרונה {date}", "privacy_policy.title": "מדיניות פרטיות", diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json index 71694db76..f4473b716 100644 --- a/app/javascript/mastodon/locales/hi.json +++ b/app/javascript/mastodon/locales/hi.json @@ -360,7 +360,6 @@ "lists.replies_policy.none": "कोई नहीं", "lists.replies_policy.title": "इसके जवाब दिखाएं:", "lists.subheading": "आपकी सूचियाँ", - "loading_indicator.label": "लोड हो रहा है...", "mute_modal.duration": "अवधि", "mute_modal.hide_notifications": "इस सभ्य की ओरसे आनेवाली सूचनाए शांत करे", "mute_modal.indefinite": "अनिश्चितकालीन", diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index 16d25e784..01524e553 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -306,7 +306,6 @@ "lists.replies_policy.none": "Nitko", "lists.search": "Traži među praćenim ljudima", "lists.subheading": "Vaše liste", - "loading_indicator.label": "Učitavanje...", "media_gallery.toggle_visible": "Sakrij {number, plural, one {sliku} other {slike}}", "mute_modal.duration": "Trajanje", "mute_modal.hide_notifications": "Sakrij obavijesti ovog korisnika?", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index ca2027161..96fc720a4 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -390,7 +390,7 @@ "lists.search": "Keresés a követett személyek között", "lists.subheading": "Saját listák", "load_pending": "{count, plural, one {# új elem} other {# új elem}}", - "loading_indicator.label": "Betöltés...", + "loading_indicator.label": "Betöltés…", "media_gallery.toggle_visible": "{number, plural, one {Kép elrejtése} other {Képek elrejtése}}", "moved_to_account_banner.text": "A(z) {disabledAccount} fiókod jelenleg le van tiltva, mert átköltöztél ide: {movedToAccount}.", "mute_modal.duration": "Időtartam", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Sajnos jelenleg nem jeleníthető meg eredmény. Kipróbálhatod a keresést vagy böngészheted a felfedező oldalon a követni kívánt személyeket, vagy próbáld meg később.", "onboarding.follows.lead": "A saját hírfolyamod az elsődleges tapasztalás a Mastodonon. Minél több embert követsz, annál aktívabb és érdekesebb a dolog. Az induláshoz itt van néhány javaslat:", "onboarding.follows.title": "Népszerű a Mastodonon", + "onboarding.profile.discoverable": "Profil és bejegyzések szerepeltetése a felfedezési algoritmusokban", + "onboarding.profile.display_name": "Megjelenített név", + "onboarding.profile.display_name_hint": "Teljes név vagy becenév…", + "onboarding.profile.indexable": "Nyilvános bejegyzések is a keresési eredményekben", + "onboarding.profile.lead": "Ezt később bármikor elvégezhető a beállításoknál, ahol még több testreszabási lehetőség áll rendelkezésre.", + "onboarding.profile.note": "Biográfia", + "onboarding.profile.note_hint": "@említhetünk másokat vagy #hashtag elemeket…", + "onboarding.profile.save_and_continue": "Mentés és folytatás", + "onboarding.profile.title": "Profil beüzemelés", + "onboarding.profile.upload_avatar": "Profilkép feltöltése", + "onboarding.profile.upload_header": "Profil fejléc feltöltése", "onboarding.share.lead": "Tudassuk az emberekkel, hogyan találhatnak meg a Mastodonon!", "onboarding.share.message": "{username} vagyok a #Mastodon hálózaton! Kövess itt: {url}.", "onboarding.share.next_steps": "Lehetséges következő lépések:", diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json index 776991b01..f2548c7d3 100644 --- a/app/javascript/mastodon/locales/hy.json +++ b/app/javascript/mastodon/locales/hy.json @@ -314,7 +314,6 @@ "lists.search": "Փնտրել քո հետեւած մարդկանց մէջ", "lists.subheading": "Քո ցանկերը", "load_pending": "{count, plural, one {# նոր նիւթ} other {# նոր նիւթ}}", - "loading_indicator.label": "Բեռնւում է…", "media_gallery.toggle_visible": "Ցուցադրել/թաքցնել", "mute_modal.duration": "Տեւողութիւն", "mute_modal.hide_notifications": "Թաքցնե՞լ ծանուցումներն այս օգտատիրոջից։", diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json index 76542cc52..8ecf36125 100644 --- a/app/javascript/mastodon/locales/id.json +++ b/app/javascript/mastodon/locales/id.json @@ -353,7 +353,6 @@ "lists.search": "Cari di antara orang yang Anda ikuti", "lists.subheading": "Daftar Anda", "load_pending": "{count, plural, other {# item baru}}", - "loading_indicator.label": "Tunggu sebentar...", "media_gallery.toggle_visible": "Tampil/Sembunyikan", "moved_to_account_banner.text": "Akun {disabledAccount} Anda kini dinonaktifkan karena Anda pindah ke {movedToAccount}.", "mute_modal.duration": "Durasi", diff --git a/app/javascript/mastodon/locales/ig.json b/app/javascript/mastodon/locales/ig.json index 201bebc05..c24d28eea 100644 --- a/app/javascript/mastodon/locales/ig.json +++ b/app/javascript/mastodon/locales/ig.json @@ -88,7 +88,6 @@ "lists.delete": "Hichapụ ndepụta", "lists.edit": "Dezie ndepụta", "lists.subheading": "Ndepụta gị", - "loading_indicator.label": "Na-adọnye...", "navigation_bar.about": "Maka", "navigation_bar.bookmarks": "Ebenrụtụakā", "navigation_bar.domain_blocks": "Hidden domains", diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json index cfe1b4344..552debdb5 100644 --- a/app/javascript/mastodon/locales/io.json +++ b/app/javascript/mastodon/locales/io.json @@ -383,7 +383,6 @@ "lists.search": "Trovez inter personi quon vu sequas", "lists.subheading": "Vua listi", "load_pending": "{count, plural, one {# nova kozo} other {# nova kozi}}", - "loading_indicator.label": "Kargante...", "media_gallery.toggle_visible": "Chanjar videbleso", "moved_to_account_banner.text": "Vua konto {disabledAccount} es nune desaktiva pro ke vu movis a {movedToAccount}.", "mute_modal.duration": "Durado", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 0b6a8012a..54123ae4c 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -390,7 +390,7 @@ "lists.search": "Leita meðal þeirra sem þú fylgist með", "lists.subheading": "Listarnir þínir", "load_pending": "{count, plural, one {# nýtt atriði} other {# ný atriði}}", - "loading_indicator.label": "Hleð inn...", + "loading_indicator.label": "Hleð inn…", "media_gallery.toggle_visible": "Víxla sýnileika", "moved_to_account_banner.text": "Aðgangurinn þinn {disabledAccount} er óvirkur í augnablikinu vegna þess að þú fluttir þig yfir á {movedToAccount}.", "mute_modal.duration": "Lengd", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Því miður er ekki hægt að birta neinar niðurstöður í augnablikinu. Þú getur reynt að nota leitina eða skoðað könnunarsíðuna til að finna fólk til að fylgjast með, nú eða prófað aftur síðar.", "onboarding.follows.lead": "Þú ræktar heimastreymið þitt. Því fleira fólki sem þú fylgist með, því virkara og áhugaverðara verður það. Að fylgjast með þessum notendum gæti verið ágætt til að byrja með - þú getur alltaf hætt að fylgjast með þeim síðar!", "onboarding.follows.title": "Vinsælt á Mastodon", + "onboarding.profile.discoverable": "Hafa notandasnið og færslur með í reikniritum leitar", + "onboarding.profile.display_name": "Birtingarnafn", + "onboarding.profile.display_name_hint": "Fullt nafn þitt eða eitthvað til gamans…", + "onboarding.profile.indexable": "Hafa opinberar færslur með í leitarniðurstöðum", + "onboarding.profile.lead": "Þú getur alltaf klárað þetta seinna í stillingunum, þar sem enn fleiri möguleikar bjóðast á sérsníðingum.", + "onboarding.profile.note": "Æviágrip", + "onboarding.profile.note_hint": "Þú getur @minnst á annað fólk eða #myllumerki…", + "onboarding.profile.save_and_continue": "Vista og halda áfram", + "onboarding.profile.title": "Uppsetning notandasniðs", + "onboarding.profile.upload_avatar": "Sendu inn auðkennismynd", + "onboarding.profile.upload_header": "Sendu inn bakgrunnsmynd í haus notandasniðs", "onboarding.share.lead": "Láttu fólk vita hvernig það getur fundið þig á Mastodon!", "onboarding.share.message": "Ég heiti {username} á #Mastodon! Þú getur fylgst með mér á {url}", "onboarding.share.next_steps": "Möguleg næstu skref:", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 8ad791bfe..284d7739c 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -390,7 +390,7 @@ "lists.search": "Cerca tra le persone che segui", "lists.subheading": "Le tue liste", "load_pending": "{count, plural, one {# nuovo oggetto} other {# nuovi oggetti}}", - "loading_indicator.label": "Caricamento...", + "loading_indicator.label": "Caricamento…", "media_gallery.toggle_visible": "{number, plural, one {Nascondi immagine} other {Nascondi immagini}}", "moved_to_account_banner.text": "Il tuo profilo {disabledAccount} è correntemente disabilitato perché ti sei spostato a {movedToAccount}.", "mute_modal.duration": "Durata", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Sfortunatamente, nessun risultato può essere mostrato in questo momento. Puoi provare a utilizzare la ricerca o sfogliare la pagina di esplorazione per trovare persone da seguire, oppure riprova più tardi.", "onboarding.follows.lead": "La cronologia della tua home è gestita da te. Più persone segui, più attiva e interessante sarà. Questi profili possono essere un buon punto di partenza; puoi sempre smettere di seguirli in seguito!", "onboarding.follows.title": "Popolare su Mastodon", + "onboarding.profile.discoverable": "Include il profilo e i post negli algoritmi di scoperta", + "onboarding.profile.display_name": "Nome da visualizzare", + "onboarding.profile.display_name_hint": "Il tuo nome completo o il tuo nome divertente…", + "onboarding.profile.indexable": "Includi i post pubblici nei risultati di ricerca", + "onboarding.profile.lead": "Puoi sempre completarlo in un secondo momento nelle impostazioni, dove sono disponibili ancora più opzioni di personalizzazione.", + "onboarding.profile.note": "Biografia", + "onboarding.profile.note_hint": "Puoi @menzionare altre persone o #hashtags…", + "onboarding.profile.save_and_continue": "Salva e continua", + "onboarding.profile.title": "Configurazione del profilo", + "onboarding.profile.upload_avatar": "Carica l'immagine del profilo", + "onboarding.profile.upload_header": "Carica l'intestazione del profilo", "onboarding.share.lead": "Fai sapere alle persone come possono trovarti su Mastodon!", "onboarding.share.message": "Sono {username} su #Mastodon! Vieni a seguirmi su {url}", "onboarding.share.next_steps": "Possibili passaggi successivi:", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 4cd7228c8..f8c85b774 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -390,7 +390,7 @@ "lists.search": "フォローしている人の中から検索", "lists.subheading": "あなたのリスト", "load_pending": "{count}件の新着", - "loading_indicator.label": "読み込み中...", + "loading_indicator.label": "", "media_gallery.toggle_visible": "{number, plural, one {画像を閉じる} other {画像を閉じる}}", "moved_to_account_banner.text": "あなたのアカウント『{disabledAccount}』は『{movedToAccount}』に移動したため現在無効になっています。", "mute_modal.duration": "ミュートする期間", diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json index 256aa93f4..875ac3c19 100644 --- a/app/javascript/mastodon/locales/ka.json +++ b/app/javascript/mastodon/locales/ka.json @@ -165,7 +165,6 @@ "lists.new.title_placeholder": "ახალი სიის სათაური", "lists.search": "ძებნა ადამიანებს შორის რომელთაც მიჰყვებით", "lists.subheading": "თქვენი სიები", - "loading_indicator.label": "იტვირთება...", "media_gallery.toggle_visible": "ხილვადობის ჩართვა", "mute_modal.hide_notifications": "დავმალოთ შეტყობინებები ამ მომხმარებლისგან?", "navigation_bar.blocks": "დაბლოკილი მომხმარებლები", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index 8f9576c26..e9d4b57de 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -274,7 +274,6 @@ "lists.search": "Nadi gar yemdanen i teṭṭafaṛeḍ", "lists.subheading": "Tibdarin-ik·im", "load_pending": "{count, plural, one {# n uferdis amaynut} other {# n yiferdisen imaynuten}}", - "loading_indicator.label": "Yessalay-d…", "media_gallery.toggle_visible": "Ffer {number, plural, one {tugna} other {tugniwin}}", "mute_modal.duration": "Tanzagt", "mute_modal.hide_notifications": "Tebɣiḍ ad teffreḍ talɣutin n umseqdac-a?", diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json index 6a4b2161b..189d792e3 100644 --- a/app/javascript/mastodon/locales/kk.json +++ b/app/javascript/mastodon/locales/kk.json @@ -242,7 +242,6 @@ "lists.search": "Сіз іздеген адамдар арасында іздеу", "lists.subheading": "Тізімдеріңіз", "load_pending": "{count, plural, one {# жаңа нәрсе} other {# жаңа нәрсе}}", - "loading_indicator.label": "Жүктеу...", "media_gallery.toggle_visible": "Көрінуді қосу", "mute_modal.hide_notifications": "Бұл қолданушы ескертпелерін жасырамыз ба?", "navigation_bar.blocks": "Бұғатталғандар", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 574d8e211..1420be8e0 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -479,6 +479,17 @@ "onboarding.follows.empty": "안타깝지만 아직은 아무 것도 보여드릴 수 없습니다. 검색을 이용하거나 발견하기 페이지에서 팔로우 할 사람을 찾을 수 있습니다. 아니면 잠시 후에 다시 시도하세요.", "onboarding.follows.lead": "홈 피드는 마스토돈을 경험하는 주된 경로입니다. 더 많은 사람들을 팔로우 할수록 더 활발하고 흥미로워질 것입니다. 여기 시작을 위한 몇몇 추천을 드립니다:", "onboarding.follows.title": "내게 맞는 홈 피드 꾸미기", + "onboarding.profile.discoverable": "발견하기 알고리즘에 프로필과 게시물을 추천하기", + "onboarding.profile.display_name": "표시되는 이름", + "onboarding.profile.display_name_hint": "진짜 이름 또는 재미난 이름…", + "onboarding.profile.indexable": "공개 게시물을 검색 결과에 포함시키기", + "onboarding.profile.lead": "언제든지 나중에 설정 메뉴에서 마저 할 수 있고, 그곳에서 더 많은 맞춤 옵션을 고를 수 있습니다.", + "onboarding.profile.note": "자기소개", + "onboarding.profile.note_hint": "남을 @mention 하거나 #hashtag 태그를 달 수 있습니다…", + "onboarding.profile.save_and_continue": "저장 및 계속", + "onboarding.profile.title": "프로필 설정", + "onboarding.profile.upload_avatar": "프로필 사진 업로드", + "onboarding.profile.upload_header": "프로필 헤더 업로드", "onboarding.share.lead": "여러 사람에게 마스토돈에서 나를 찾을 수 있는 방법을 알려주세요!", "onboarding.share.message": "#마스토돈 이용하는 {username}입니다! {url} 에서 저를 팔로우 해보세요", "onboarding.share.next_steps": "할만한 다음 단계:", diff --git a/app/javascript/mastodon/locales/ku.json b/app/javascript/mastodon/locales/ku.json index 8c9aaf3e8..b94054267 100644 --- a/app/javascript/mastodon/locales/ku.json +++ b/app/javascript/mastodon/locales/ku.json @@ -339,7 +339,6 @@ "lists.search": "Di navbera kesên ku te dişopînin bigere", "lists.subheading": "Lîsteyên te", "load_pending": "{count, plural, one {# hêmaneke nû} other {#hêmaneke nû}}", - "loading_indicator.label": "Tê barkirin...", "media_gallery.toggle_visible": "{number, plural, one {Wêneyê veşêre} other {Wêneyan veşêre}}", "moved_to_account_banner.text": "Ajimêrê te {disabledAccount} niha neçalak e ji ber ku te bar kir bo {movedToAccount}.", "mute_modal.duration": "Dem", diff --git a/app/javascript/mastodon/locales/kw.json b/app/javascript/mastodon/locales/kw.json index 6b46d8231..ca08ca836 100644 --- a/app/javascript/mastodon/locales/kw.json +++ b/app/javascript/mastodon/locales/kw.json @@ -235,7 +235,6 @@ "lists.search": "Hwilas yn-mysk tus a holyewgh", "lists.subheading": "Agas rolyow", "load_pending": "{count, plural, one {# daklennowydh} other {# a daklennow nowydh}}", - "loading_indicator.label": "Ow karga...", "media_gallery.toggle_visible": "Hide {number, plural, one {aven} other {aven}}", "mute_modal.duration": "Duryans", "mute_modal.hide_notifications": "Kudha gwarnyansow a'n devnydhyer ma?", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 5675799e7..21aa797b4 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -26,6 +26,7 @@ "account.domain_blocked": "Užblokuotas domenas", "account.edit_profile": "Redaguoti profilį", "account.enable_notifications": "Pranešti man, kai @{name} paskelbia", + "account.endorse": "Savybė profilyje", "account.featured_tags.last_status_at": "Paskutinį kartą paskelbta {date}", "account.featured_tags.last_status_never": "Nėra įrašų", "account.follow": "Sekti", @@ -191,6 +192,7 @@ "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", "keyboard_shortcuts.up": "to move up in the list", "lightbox.close": "Uždaryti", + "loading_indicator.label": "Kraunama…", "media_gallery.toggle_visible": "{number, plural, one {Slėpti vaizdą} few {Slėpti vaizdus} many {Slėpti vaizdo} other {Slėpti vaizdų}}", "navigation_bar.compose": "Compose new toot", "navigation_bar.domain_blocks": "Hidden domains", @@ -217,6 +219,16 @@ "onboarding.actions.go_to_home": "Go to your home feed", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.display_name": "Rodomas vardas", + "onboarding.profile.display_name_hint": "Tavo pilnas vardas arba linksmas vardas…", + "onboarding.profile.indexable": "Įtraukti viešus įrašus į paieškos rezultatus", + "onboarding.profile.lead": "Gali visada tai užbaigti vėliau nustatymuose, kur yra dar daugiau pritaikymo parinkčių.", + "onboarding.profile.note": "Biografija", + "onboarding.profile.note_hint": "Gali @paminėti kitus žmones arba #saitažodžius…", + "onboarding.profile.save_and_continue": "Išsaugoti ir tęsti", + "onboarding.profile.title": "Profilio konfigūravimas", + "onboarding.profile.upload_avatar": "Įkelti profilio nuotrauką", + "onboarding.profile.upload_header": "Įkelti profilio antraštę", "onboarding.share.message": "Aš {username} #Mastodon! Ateik sekti manęs adresu {url}", "onboarding.start.lead": "Dabar esi Mastodon dalis – unikalios decentralizuotos socialinės žiniasklaidos platformos, kurioje tu, o ne algoritmas, pats nustatai savo patirtį. Pradėkime tavo kelionę šioje naujoje socialinėje erdvėje:", "onboarding.start.skip": "Want to skip right ahead?", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index 5d681b829..63ec6275b 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -390,7 +390,6 @@ "lists.search": "Meklēt starp cilvēkiem, kuriem tu seko", "lists.subheading": "Tavi saraksti", "load_pending": "{count, plural, one {# jauna lieta} other {# jaunas lietas}}", - "loading_indicator.label": "Ielādē...", "media_gallery.toggle_visible": "{number, plural, one {Slēpt attēlu} other {Slēpt attēlus}}", "moved_to_account_banner.text": "Tavs konts {disabledAccount} pašlaik ir atspējots, jo pārcēlies uz kontu {movedToAccount}.", "mute_modal.duration": "Ilgums", diff --git a/app/javascript/mastodon/locales/ml.json b/app/javascript/mastodon/locales/ml.json index 6bf04ce75..b00cedc6f 100644 --- a/app/javascript/mastodon/locales/ml.json +++ b/app/javascript/mastodon/locales/ml.json @@ -237,7 +237,6 @@ "lists.replies_policy.none": "ആരുമില്ല", "lists.replies_policy.title": "ഇതിനുള്ള മറുപടികൾ കാണിക്കുക:", "lists.subheading": "എന്റെ പട്ടികകൾ", - "loading_indicator.label": "ലോഡിംഗ്...", "mute_modal.duration": "കാലാവധി", "mute_modal.indefinite": "അനിശ്ചിതകാല", "navigation_bar.blocks": "തടയപ്പെട്ട ഉപയോക്താക്കൾ", diff --git a/app/javascript/mastodon/locales/mr.json b/app/javascript/mastodon/locales/mr.json index ef0efbdec..75b75375b 100644 --- a/app/javascript/mastodon/locales/mr.json +++ b/app/javascript/mastodon/locales/mr.json @@ -196,7 +196,6 @@ "lists.search": "तुम्ही फॉलो करत असलेल्या लोकांमध्ये शोधा", "lists.subheading": "तुमच्या याद्या", "load_pending": "{count, plural, one {# new item} other {# new items}}", - "loading_indicator.label": "लोड करत आहे...", "navigation_bar.compose": "Compose new toot", "navigation_bar.domain_blocks": "Hidden domains", "navigation_bar.pins": "Pinned toots", diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json index a3bbd0067..724e07ae7 100644 --- a/app/javascript/mastodon/locales/ms.json +++ b/app/javascript/mastodon/locales/ms.json @@ -386,7 +386,6 @@ "lists.search": "Cari dalam kalangan orang yang anda ikuti", "lists.subheading": "Senarai anda", "load_pending": "{count, plural, one {# item baharu} other {# item baharu}}", - "loading_indicator.label": "Memuatkan...", "media_gallery.toggle_visible": "{number, plural, other {Sembunyikan imej}}", "moved_to_account_banner.text": "Akaun anda {disabledAccount} kini dinyahdayakan kerana anda berpindah ke {movedToAccount}.", "mute_modal.duration": "Tempoh", diff --git a/app/javascript/mastodon/locales/my.json b/app/javascript/mastodon/locales/my.json index 103f4e0f8..4078a4c06 100644 --- a/app/javascript/mastodon/locales/my.json +++ b/app/javascript/mastodon/locales/my.json @@ -389,7 +389,6 @@ "lists.search": "မိမိဖောလိုးထားသူများမှရှာဖွေမည်", "lists.subheading": "သင့်၏စာရင်းများ", "load_pending": "{count, plural, one {# new item} other {# new items}}", - "loading_indicator.label": "လုပ်ဆောင်နေသည်…", "media_gallery.toggle_visible": "{number, plural, one {Hide image} other {Hide images}}", "moved_to_account_banner.text": "{movedToAccount} အကောင့်သို့ပြောင်းလဲထားသဖြင့် {disabledAccount} အကောင့်မှာပိတ်ထားသည်", "mute_modal.duration": "ကြာချိန်", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 131d2e4aa..6f941999f 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Helaas kunnen op dit moment geen resultaten worden getoond. Je kunt proberen te zoeken of op de verkenningspagina te bladeren om mensen te vinden die je kunt volgen, of probeer het later opnieuw.", "onboarding.follows.lead": "Jouw starttijdlijn is de belangrijkste manier om Mastodon te ervaren. Hoe meer mensen je volgt, hoe actiever en interessanter het zal zijn. Om te beginnen, zijn hier enkele suggesties:", "onboarding.follows.title": "Je starttijdlijn aan jouw wensen aanpassen", + "onboarding.profile.discoverable": "Profiel en berichten laten uitlichten in ontdekkingsalgoritmes", + "onboarding.profile.display_name": "Weergavenaam", + "onboarding.profile.display_name_hint": "Jouw volledige naam of een leuke bijnaam…", + "onboarding.profile.indexable": "Openbare berichten in zoekresultaten opnemen", + "onboarding.profile.lead": "Je kunt dit later altijd aanvullen in de instellingen, waar nog meer aanpassingsopties beschikbaar zijn.", + "onboarding.profile.note": "Biografie", + "onboarding.profile.note_hint": "Je kunt andere mensen @vermelden of #hashtags gebruiken…", + "onboarding.profile.save_and_continue": "Opslaan en doorgaan", + "onboarding.profile.title": "Profiel instellen", + "onboarding.profile.upload_avatar": "Profielfoto uploaden", + "onboarding.profile.upload_header": "Kop voor het profiel uploaden", "onboarding.share.lead": "Laat mensen weten hoe ze je kunnen vinden op Mastodon!", "onboarding.share.message": "Ik ben {username} op #Mastodon! Volg mij op {url}", "onboarding.share.next_steps": "Mogelijke volgende stappen:", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index aa30aef7d..a3402d660 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -390,7 +390,7 @@ "lists.search": "Søk blant folk du fylgjer", "lists.subheading": "Listene dine", "load_pending": "{count, plural, one {# nytt element} other {# nye element}}", - "loading_indicator.label": "Lastar...", + "loading_indicator.label": "Laster…", "media_gallery.toggle_visible": "{number, plural, one {Skjul bilete} other {Skjul bilete}}", "moved_to_account_banner.text": "Kontoen din, {disabledAccount} er for tida deaktivert fordi du har flytta til {movedToAccount}.", "mute_modal.duration": "Varigheit", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Me kan ikkje visa deg nokon resultat no. Du kan prøva å søkja eller bla gjennom utforsk-sida for å finna folk å fylgja, eller du kan prøva att seinare.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.discoverable": "Fremhevede profiler og innlegg i oppdagelsealgoritmer", + "onboarding.profile.display_name": "Visningsnavn", + "onboarding.profile.display_name_hint": "Ditt fulle navn eller ditt morsomme navn…", + "onboarding.profile.indexable": "Inkluder offentlige innlegg i søkeresultatene", + "onboarding.profile.lead": "Du kan alltid fullføre dette senere i innstillingene, der enda flere tilpasningsalternativer er tilgjengelige.", + "onboarding.profile.note": "Om meg", + "onboarding.profile.note_hint": "Du kan @nevne andre eller #emneknagger…", + "onboarding.profile.save_and_continue": "Lagre og fortsett", + "onboarding.profile.title": "Konfigurering av profil", + "onboarding.profile.upload_avatar": "Last opp profilbilde", + "onboarding.profile.upload_header": "Last opp profiltoppbilde", "onboarding.share.lead": "La folk vita korleis dei kan finna deg på Mastodon!", "onboarding.share.message": "Eg er {username} på #Mastodon! Du kan fylgja meg på {url}", "onboarding.share.next_steps": "Dette kan du gjera no:", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index 7421c780f..fe3979f0f 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -390,7 +390,7 @@ "lists.search": "Søk blant personer du følger", "lists.subheading": "Dine lister", "load_pending": "{count, plural,one {# ny gjenstand} other {# nye gjenstander}}", - "loading_indicator.label": "Laster...", + "loading_indicator.label": "Laster…", "media_gallery.toggle_visible": "Veksle synlighet", "moved_to_account_banner.text": "Din konto {disabledAccount} er for øyeblikket deaktivert fordi du flyttet til {movedToAccount}.", "mute_modal.duration": "Varighet", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Dessverre kan ingen resultater vises akkurat nå. Du kan prøve å bruke søk eller bla gjennom utforske-siden for å finne folk å følge, eller prøve igjen senere.", "onboarding.follows.lead": "Hjem-skjermen din er den viktigste måten å oppleve Mastodon på. Jo flere du følger, jo mer aktiv og interessant blir det. For å komme i gang, er her noen forslag:", "onboarding.follows.title": "Populært på Mastodon", + "onboarding.profile.discoverable": "Fremhevede profiler og innlegg i oppdagelsealgoritmer", + "onboarding.profile.display_name": "Visningsnavn", + "onboarding.profile.display_name_hint": "Ditt fulle navn eller ditt morsomme navn…", + "onboarding.profile.indexable": "Inkluder offentlige innlegg i søkeresultatene", + "onboarding.profile.lead": "Du kan alltid fullføre dette senere i innstillingene, der enda flere tilpasningsalternativer er tilgjengelige.", + "onboarding.profile.note": "Om meg", + "onboarding.profile.note_hint": "Du kan @nevne andre eller #emneknagger…", + "onboarding.profile.save_and_continue": "Lagre og fortsett", + "onboarding.profile.title": "Konfigurering av profil", + "onboarding.profile.upload_avatar": "Last opp profilbilde", + "onboarding.profile.upload_header": "Last opp profiltoppbilde", "onboarding.share.lead": "La folk vite hvordan de kan finne deg på Mastodon!", "onboarding.share.message": "Jeg er {username} på #Mastodon! Kom og følg meg på {url}", "onboarding.share.next_steps": "Mulige neste trinn:", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index 6b8265450..3812057fb 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -340,7 +340,6 @@ "lists.search": "Cercar demest lo mond que seguètz", "lists.subheading": "Vòstras listas", "load_pending": "{count, plural, one {# nòu element} other {# nòu elements}}", - "loading_indicator.label": "Cargament…", "media_gallery.toggle_visible": "Modificar la visibilitat", "mute_modal.duration": "Durada", "mute_modal.hide_notifications": "Rescondre las notificacions d’aquesta persona ?", diff --git a/app/javascript/mastodon/locales/pa.json b/app/javascript/mastodon/locales/pa.json index 371f9622d..7faf27971 100644 --- a/app/javascript/mastodon/locales/pa.json +++ b/app/javascript/mastodon/locales/pa.json @@ -122,7 +122,6 @@ "lightbox.next": "ਅਗਲੀ", "lightbox.previous": "ਪਿਛਲੀ", "lists.delete": "ਸੂਚੀ ਮਿਟਾਓ", - "loading_indicator.label": "ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ...", "mute_modal.duration": "ਮਿਆਦ", "navigation_bar.about": "ਸਾਡੇ ਬਾਰੇ", "navigation_bar.bookmarks": "ਬੁੱਕਮਾਰਕ", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 643f78a88..a1cc0e26e 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Niestety w tej chwili nie można przedstawić żadnych wyników. Możesz spróbować wyszukać lub przeglądać stronę, aby znaleźć osoby do śledzenia, lub spróbować ponownie później.", "onboarding.follows.lead": "Zarządasz swoim własnym kanałem. Im więcej ludzi śledzisz, tym bardziej aktywny i ciekawy będzie Twój kanał. Te profile mogą być dobrym punktem wyjścia— możesz przestać je obserwować w dowolnej chwili!", "onboarding.follows.title": "Popularne na Mastodonie", + "onboarding.profile.discoverable": "Udostępniaj profil i wpisy funkcjom odkrywania", + "onboarding.profile.display_name": "Nazwa wyświetlana", + "onboarding.profile.display_name_hint": "Twoje imię lub pseudonim…", + "onboarding.profile.indexable": "Pokaż publiczne wpisy w wynikach wyszukiwania", + "onboarding.profile.lead": "Możesz wypełnić te dane później w menu ustawień, gdzie dostępnych jest jeszcze więcej opcji.", + "onboarding.profile.note": "O mnie", + "onboarding.profile.note_hint": "Możesz @wspomnieć użytkowników albo #hasztagi…", + "onboarding.profile.save_and_continue": "Zapisz i kontynuuj", + "onboarding.profile.title": "Ustawienia profilu", + "onboarding.profile.upload_avatar": "Dodaj zdjęcie profilowe", + "onboarding.profile.upload_header": "Dodaj zdjęcie nagłówkowe", "onboarding.share.lead": "Daj znać ludziom, jak mogą cię znaleźć na Mastodonie!", "onboarding.share.message": "Jestem {username} na #Mastodon! Śledź mnie tutaj {url}", "onboarding.share.next_steps": "Możliwe dalsze kroki:", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 9c09e2d71..7ce63e9b1 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -390,7 +390,6 @@ "lists.search": "Procurar entre as pessoas que segue", "lists.subheading": "Suas listas", "load_pending": "{count, plural, one {# novo item} other {# novos items}}", - "loading_indicator.label": "Carregando...", "media_gallery.toggle_visible": "{number, plural, one {Ocultar mídia} other {Ocultar mídias}}", "moved_to_account_banner.text": "Sua conta {disabledAccount} está desativada porque você a moveu para {movedToAccount}.", "mute_modal.duration": "Duração", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index 988bec9b0..69e804878 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -390,7 +390,7 @@ "lists.search": "Pesquisa entre as pessoas que segues", "lists.subheading": "As tuas listas", "load_pending": "{count, plural, one {# novo item} other {# novos itens}}", - "loading_indicator.label": "A carregar...", + "loading_indicator.label": "A carregar…", "media_gallery.toggle_visible": "Alternar visibilidade", "moved_to_account_banner.text": "A sua conta {disabledAccount} está, no momento, desativada, porque você migrou para {movedToAccount}.", "mute_modal.duration": "Duração", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Infelizmente, não é possível mostrar resultados neste momento. Pode tentar utilizar a pesquisa ou navegar na página \"Explorar\" para encontrar pessoas para seguir ou tentar novamente mais tarde.", "onboarding.follows.lead": "Você personaliza a sua própria página inicial. Quanto mais pessoas seguir, mais ativa e interessante ela será. Estes perfis podem ser um bom ponto de partida - pode sempre deixar de os seguir mais tarde!", "onboarding.follows.title": "Popular no Mastodon", + "onboarding.profile.discoverable": "Destacar perfil e publicações nos algoritmos de descoberta", + "onboarding.profile.display_name": "Nome a apresentar", + "onboarding.profile.display_name_hint": "O seu nome completo ou o seu nome divertido…", + "onboarding.profile.indexable": "Incluir publicações públicas nos resultados de pesquisa", + "onboarding.profile.lead": "Pode sempre completar isto mais tarde, nas configurações, onde ainda estão disponíveis mais opções de personalização.", + "onboarding.profile.note": "Bio", + "onboarding.profile.note_hint": "Pode @mencionar outras pessoas ou #hashtags…", + "onboarding.profile.save_and_continue": "Guardar e continuar", + "onboarding.profile.title": "Configuração do perfil", + "onboarding.profile.upload_avatar": "Carregar foto de perfil", + "onboarding.profile.upload_header": "Carregar cabeçalho do perfil", "onboarding.share.lead": "Deixe as pessoas saber como o podem encontrar no Mastodon!", "onboarding.share.message": "Eu sou {username} no #Mastodon! Venha seguir-me em {url}", "onboarding.share.next_steps": "Próximos passos possíveis:", diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json index f0e84463b..5355f9935 100644 --- a/app/javascript/mastodon/locales/ro.json +++ b/app/javascript/mastodon/locales/ro.json @@ -353,7 +353,6 @@ "lists.search": "Caută printre persoanele la care ești abonat", "lists.subheading": "Listele tale", "load_pending": "{count, plural, one {# element nou} other {# elemente noi}}", - "loading_indicator.label": "Se încarcă...", "media_gallery.toggle_visible": "{number, plural, one {Ascunde imaginea} other {Ascunde imaginile}}", "moved_to_account_banner.text": "Contul tău {disabledAccount} este în acest moment dezactivat deoarece te-ai mutat la {movedToAccount}.", "mute_modal.duration": "Durata", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index 69db89dc8..5c98d906b 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -389,7 +389,6 @@ "lists.search": "Искать среди подписок", "lists.subheading": "Ваши списки", "load_pending": "{count, plural, one {# новый элемент} few {# новых элемента} other {# новых элементов}}", - "loading_indicator.label": "Загрузка...", "media_gallery.toggle_visible": "Показать/скрыть {number, plural, =1 {изображение} other {изображения}}", "moved_to_account_banner.text": "Ваша учетная запись {disabledAccount} в настоящее время заморожена, потому что вы переехали на {movedToAccount}.", "mute_modal.duration": "Продолжительность", diff --git a/app/javascript/mastodon/locales/sa.json b/app/javascript/mastodon/locales/sa.json index cb92914e5..59379343b 100644 --- a/app/javascript/mastodon/locales/sa.json +++ b/app/javascript/mastodon/locales/sa.json @@ -345,7 +345,6 @@ "lists.search": "त्वया अनुसारितजनेषु अन्विष्य", "lists.subheading": "तव सूचयः", "load_pending": "{count, plural, one {# नूतनवस्तु} other {# नूतनवस्तूनि}}", - "loading_indicator.label": "आरोपयति...", "media_gallery.toggle_visible": "{number, plural, one {चित्रं प्रच्छादय} other {चित्राणि प्रच्छादय}}", "moved_to_account_banner.text": "तव एकौण्ट् {disabledAccount} अधुना निष्कृतो यतोहि {movedToAccount} अस्मिन्त्वमसार्षीः।", "mute_modal.duration": "परिमाणम्", diff --git a/app/javascript/mastodon/locales/sc.json b/app/javascript/mastodon/locales/sc.json index 4528e161b..59c834b95 100644 --- a/app/javascript/mastodon/locales/sc.json +++ b/app/javascript/mastodon/locales/sc.json @@ -263,7 +263,6 @@ "lists.search": "Chirca intre sa gente chi ses sighende", "lists.subheading": "Is listas tuas", "load_pending": "{count, plural, one {# elementu nou} other {# elementos noos}}", - "loading_indicator.label": "Carrighende...", "media_gallery.toggle_visible": "Cua {number, plural, one {immàgine} other {immàgines}}", "mute_modal.duration": "Durada", "mute_modal.hide_notifications": "Boles cuare is notìficas de custa persone?", diff --git a/app/javascript/mastodon/locales/sco.json b/app/javascript/mastodon/locales/sco.json index 9b8e6a215..28dac9c2a 100644 --- a/app/javascript/mastodon/locales/sco.json +++ b/app/javascript/mastodon/locales/sco.json @@ -330,7 +330,6 @@ "lists.search": "Seirch amang the fowk ye ken", "lists.subheading": "Yer lists", "load_pending": "{count, plural, one {# new item} other {# new items}}", - "loading_indicator.label": "Loadin...", "media_gallery.toggle_visible": "{number, plural, one {Hide image} other {Hide images}}", "moved_to_account_banner.text": "Yer accoont {disabledAccount} is disabilt the noo acause ye flittit tae {movedToAccount}.", "mute_modal.duration": "Lenth", diff --git a/app/javascript/mastodon/locales/si.json b/app/javascript/mastodon/locales/si.json index 7b26a9b48..835f699b8 100644 --- a/app/javascript/mastodon/locales/si.json +++ b/app/javascript/mastodon/locales/si.json @@ -261,7 +261,6 @@ "lists.replies_policy.none": "කිසිවෙක් නැත", "lists.replies_policy.title": "පිළිතුරු පෙන්වන්න:", "lists.subheading": "ඔබගේ ලැයිස්තු", - "loading_indicator.label": "පූරණය වෙමින්...", "mute_modal.duration": "පරාසය", "mute_modal.hide_notifications": "මෙම පුද්ගලයාගේ දැනුම්දීම් සඟවන්නද?", "navigation_bar.about": "පිළිබඳව", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index f2616b31c..24186794b 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -389,7 +389,6 @@ "lists.search": "Vyhľadávaj medzi užívateľmi, ktorých sleduješ", "lists.subheading": "Tvoje zoznamy", "load_pending": "{count, plural, one {# nová položka} other {# nových položiek}}", - "loading_indicator.label": "Načítam...", "media_gallery.toggle_visible": "Zapni/Vypni viditeľnosť", "moved_to_account_banner.text": "Vaše konto {disabledAccount} je momentálne zablokované, pretože ste sa presunuli na {movedToAccount}.", "mute_modal.duration": "Trvanie", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index f16a91d65..d179a8656 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -390,7 +390,6 @@ "lists.search": "Iščite med ljudmi, katerim sledite", "lists.subheading": "Vaši seznami", "load_pending": "{count, plural, one {# nov element} two {# nova elementa} few {# novi elementi} other {# novih elementov}}", - "loading_indicator.label": "Nalaganje ...", "media_gallery.toggle_visible": "{number, plural,one {Skrij sliko} two {Skrij sliki} other {Skrij slike}}", "moved_to_account_banner.text": "Vaš račun {disabledAccount} je trenutno onemogočen, ker ste se prestavili na {movedToAccount}.", "mute_modal.duration": "Trajanje", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 8d54ef41b..1417bed5f 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Mjerisht, s’mund të shfaqen përfundime tani. Mund të provoni të përdorni kërkimin, ose të shfletoni faqen e eksplorimit, që të gjeni persona për ndjekje, ose të riprovoni më vonë.", "onboarding.follows.lead": "Ju kujdeseni për prurjen tuaj. Sa më tepër persona të tjerë të ndiqni, aq më aktive dhe interesante do të bëhet ajo. Këto profile mund të jenë një pikënisje e mirë—mundeni përherë të ndërpritni ndjekjen e tyre më vonë!", "onboarding.follows.title": "Popullore në Mastodon", + "onboarding.profile.discoverable": "Profilin dhe postimet bëji objekt të algoritmeve të zbulimit", + "onboarding.profile.display_name": "Emër në ekran", + "onboarding.profile.display_name_hint": "Emri juaj i plotë, ose ç’të doni…", + "onboarding.profile.indexable": "Përfshi postime publike në përfundime kërkimi", + "onboarding.profile.lead": "Këtë mund ta plotësoni përherë më vonë, te rregullimet, ku ka edhe më tepër mundësi përshtatjeje.", + "onboarding.profile.note": "Jetëshkrim", + "onboarding.profile.note_hint": "Mund të @përmendni persona të tjerë, ose #hashtagë…", + "onboarding.profile.save_and_continue": "Ruaje dhe vazhdo", + "onboarding.profile.title": "Udjisje profili", + "onboarding.profile.upload_avatar": "Ngarkoni foto profili", + "onboarding.profile.upload_header": "Ngarkoni krye profili", "onboarding.share.lead": "Bëjuni të ditur njerëzve se si mund t’ju gjejnë në Mastodon!", "onboarding.share.message": "Jam {username} në #Mastodon! Ejani dhe ndiqmëni te {url}", "onboarding.share.next_steps": "Hapa pasues të mundshëm:", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index aa948b1f0..ea6e188cb 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -390,7 +390,6 @@ "lists.search": "Pretraži među ljudima koje pratite", "lists.subheading": "Vaše liste", "load_pending": "{count, plural, one {# nova stavka} few {# nove stavke} other {# novih stavki}}", - "loading_indicator.label": "Učitavanje...", "media_gallery.toggle_visible": "{number, plural, one {Sakrij sliku} few {Sakrij slike} other {Sakrij slike}}", "moved_to_account_banner.text": "Vaš nalog {disabledAccount} je trenutno onemogućen jer ste prešli na {movedToAccount}.", "mute_modal.duration": "Trajanje", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index 9e6716927..b0a76b32a 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -390,7 +390,6 @@ "lists.search": "Претражи међу људима које пратите", "lists.subheading": "Ваше листе", "load_pending": "{count, plural, one {# нова ставка} few {# нове ставке} other {# нових ставки}}", - "loading_indicator.label": "Учитавање...", "media_gallery.toggle_visible": "{number, plural, one {Сакриј слику} few {Сакриј слике} other {Сакриј слике}}", "moved_to_account_banner.text": "Ваш налог {disabledAccount} је тренутно онемогућен јер сте прешли на {movedToAccount}.", "mute_modal.duration": "Трајање", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index edf981e11..6f9f37ea1 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -390,7 +390,7 @@ "lists.search": "Sök bland personer du följer", "lists.subheading": "Dina listor", "load_pending": "{count, plural, one {# nytt objekt} other {# nya objekt}}", - "loading_indicator.label": "Laddar...", + "loading_indicator.label": "Laddar…", "media_gallery.toggle_visible": "Växla synlighet", "moved_to_account_banner.text": "Ditt konto {disabledAccount} är för närvarande inaktiverat eftersom du flyttat till {movedToAccount}.", "mute_modal.duration": "Varaktighet", @@ -479,6 +479,14 @@ "onboarding.follows.empty": "Tyvärr kan inga resultat visas just nu. Du kan prova att använda sökfunktionen eller utforska sidan för att hitta personer att följa, eller försök igen senare.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.display_name": "Visningsnamn", + "onboarding.profile.display_name_hint": "Fullständigt namn eller ditt roliga namn…", + "onboarding.profile.indexable": "Inkludera offentliga inlägg i sökresultaten", + "onboarding.profile.lead": "Du kan alltid slutföra detta senare i inställningarna, där ännu fler anpassningsalternativ finns tillgängliga.", + "onboarding.profile.note": "Bio", + "onboarding.profile.note_hint": "Du kan @nämna andra personer eller #hashtags…", + "onboarding.profile.save_and_continue": "Spara och fortsätt", + "onboarding.profile.upload_avatar": "Ladda upp profilbild", "onboarding.share.lead": "Låt folk veta hur de kan hitta dig på Mastodon!", "onboarding.share.message": "Jag är {username} på #Mastodon! Följ mig på {url}", "onboarding.share.next_steps": "Möjliga nästa steg:", diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json index f62088f62..ce9042e62 100644 --- a/app/javascript/mastodon/locales/ta.json +++ b/app/javascript/mastodon/locales/ta.json @@ -248,7 +248,6 @@ "lists.search": "நீங்கள் பின்தொடரும் நபர்கள் மத்தியில் தேடுதல்", "lists.subheading": "உங்கள் பட்டியல்கள்", "load_pending": "{count, plural,one {# புதியது}other {# புதியவை}}", - "loading_indicator.label": "ஏற்றுதல்...", "media_gallery.toggle_visible": "நிலைமாற்று தெரியும்", "mute_modal.hide_notifications": "இந்த பயனரின் அறிவிப்புகளை மறைக்கவா?", "navigation_bar.blocks": "தடுக்கப்பட்ட பயனர்கள்", diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json index 6cf735991..f21c0ef57 100644 --- a/app/javascript/mastodon/locales/te.json +++ b/app/javascript/mastodon/locales/te.json @@ -180,7 +180,6 @@ "lists.new.title_placeholder": "కొత్త జాబితా శీర్షిక", "lists.search": "మీరు అనుసరించే వ్యక్తులలో శోధించండి", "lists.subheading": "మీ జాబితాలు", - "loading_indicator.label": "లోడ్ అవుతోంది...", "media_gallery.toggle_visible": "దృశ్యమానతను టోగుల్ చేయండి", "mute_modal.hide_notifications": "ఈ వినియోగదారు నుండి నోటిఫికేషన్లను దాచాలా?", "navigation_bar.blocks": "బ్లాక్ చేయబడిన వినియోగదారులు", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 80f862cbe..2166cd2dd 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -390,7 +390,7 @@ "lists.search": "ค้นหาในหมู่ผู้คนที่คุณติดตาม", "lists.subheading": "รายการของคุณ", "load_pending": "{count, plural, other {# รายการใหม่}}", - "loading_indicator.label": "กำลังโหลด...", + "loading_indicator.label": "กำลังโหลด…", "media_gallery.toggle_visible": "{number, plural, other {ซ่อนภาพ}}", "moved_to_account_banner.text": "มีการปิดใช้งานบัญชีของคุณ {disabledAccount} ในปัจจุบันเนื่องจากคุณได้ย้ายไปยัง {movedToAccount}", "mute_modal.duration": "ระยะเวลา", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "น่าเสียดาย ไม่สามารถแสดงผลลัพธ์ได้ในตอนนี้ คุณสามารถลองใช้การค้นหาหรือเรียกดูหน้าสำรวจเพื่อค้นหาผู้คนที่จะติดตาม หรือลองอีกครั้งในภายหลัง", "onboarding.follows.lead": "ฟีดหน้าแรกของคุณเป็นวิธีหลักในการสัมผัส Mastodon ยิ่งคุณติดตามผู้คนมากเท่าไร ฟีดหน้าแรกก็จะยิ่งมีการใช้งานและน่าสนใจมากขึ้นเท่านั้น เพื่อช่วยให้คุณเริ่มต้นใช้งาน นี่คือข้อเสนอแนะบางส่วน:", "onboarding.follows.title": "ปรับแต่งฟีดหน้าแรกของคุณ", + "onboarding.profile.discoverable": "แสดงโปรไฟล์และโพสต์ในอัลกอริทึมการค้นพบ", + "onboarding.profile.display_name": "ชื่อที่แสดง", + "onboarding.profile.display_name_hint": "ชื่อเต็มหรือชื่อแบบสนุกสนานของคุณ", + "onboarding.profile.indexable": "รวมโพสต์สาธารณะในผลลัพธ์การค้นหา", + "onboarding.profile.lead": "คุณสามารถกลับมาทำต่อได้เสมอในการตั้งค่า ซึ่งจะมีตัวเลือกในการปรับแต่งมากกว่า", + "onboarding.profile.note": "ชีวประวัติ", + "onboarding.profile.note_hint": "คุณสามารถ @กล่าวถึง ผู้คนอื่น ๆ หรือ #แฮชแท็ก", + "onboarding.profile.save_and_continue": "บันทึกและดำเนินการต่อ", + "onboarding.profile.title": "การตั้งค่าโปรไฟล์", + "onboarding.profile.upload_avatar": "อัปโหลดรูปโปรไฟล์", + "onboarding.profile.upload_header": "อัปโหลดรูปส่วนหัวโปรไฟล์", "onboarding.share.lead": "แจ้งให้ผู้คนทราบวิธีที่เขาสามารถค้นหาคุณใน Mastodon!", "onboarding.share.message": "ฉันคือ {username} ใน #Mastodon! มาติดตามฉันที่ {url}", "onboarding.share.next_steps": "ขั้นตอนถัดไปที่เป็นไปได้:", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index 9ad259493..505b16f4b 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -390,7 +390,7 @@ "lists.search": "Takip ettiğiniz kişiler arasından arayın", "lists.subheading": "Listeleriniz", "load_pending": "{count, plural, one {# yeni öğe} other {# yeni öğe}}", - "loading_indicator.label": "Yükleniyor...", + "loading_indicator.label": "Yükleniyor…", "media_gallery.toggle_visible": "{number, plural, one {Resmi} other {Resimleri}} gizle", "moved_to_account_banner.text": "{disabledAccount} hesabınız, {movedToAccount} hesabına taşıdığınız için şu an devre dışı.", "mute_modal.duration": "Süre", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "Maalesef şu an bir sonuç gösterilemiyor. Takip edilecek kişileri bulmak için arama veya keşfet sayfasına gözatmayı kullanabilirsiniz veya daha sonra tekrar deneyin.", "onboarding.follows.lead": "Kendi ana akışınızı siz düzenliyorsunuz. Siz daha fazla insanı takip ettikçe, daha etkin ve ilgi çekici olacaktır. Bu profiller iyi bir başlangıç olabilir, isterseniz izlemeyi daha sonra bırakabilirsiniz:", "onboarding.follows.title": "Mastodon'da Popüler", + "onboarding.profile.discoverable": "Profil ve gönderileri keşif algoritmalarında kullan", + "onboarding.profile.display_name": "Görünen isim", + "onboarding.profile.display_name_hint": "Tam adınız veya kullanıcı adınız…", + "onboarding.profile.indexable": "Herkese açık gönderileri arama sonuçlarına ekle", + "onboarding.profile.lead": "Bunu her zaman daha sonra ayarlardan tamamlayabilirsiniz, hatta daha fazla özelleştirme seçeneğine de ulaşabilirsiniz.", + "onboarding.profile.note": "Kişisel bilgiler", + "onboarding.profile.note_hint": "Diğer insanlara @değinebilir veya #etiketler kullanabilirsiniz…", + "onboarding.profile.save_and_continue": "Kaydet ve ilerle", + "onboarding.profile.title": "Profilini ayarla", + "onboarding.profile.upload_avatar": "Profil resmi yükle", + "onboarding.profile.upload_header": "Profil başlığı yükle", "onboarding.share.lead": "Kullanıcılara Mastodon'da size nasıl ulaşabileceklerini ifade edin!", "onboarding.share.message": "#Mastodon'da kullanıcı adım {username}! Beni takip etmek için {url} bağlantısını kullanın", "onboarding.share.next_steps": "Olası sonraki adımlar:", diff --git a/app/javascript/mastodon/locales/tt.json b/app/javascript/mastodon/locales/tt.json index e84bc66cc..6727f3e59 100644 --- a/app/javascript/mastodon/locales/tt.json +++ b/app/javascript/mastodon/locales/tt.json @@ -314,7 +314,6 @@ "lists.replies_policy.none": "Һичкем", "lists.subheading": "Исемлегегегезләр", "load_pending": "{count, plural, one {# яңа элемент} other {# яңа элемент}}", - "loading_indicator.label": "Йөкләү...", "mute_modal.duration": "Дәвамлык", "mute_modal.indefinite": "Билгесез", "navigation_bar.about": "Проект турында", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 09fa58fbf..8649d9310 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -390,7 +390,7 @@ "lists.search": "Шукати серед людей, на яких ви підписані", "lists.subheading": "Ваші списки", "load_pending": "{count, plural, one {# новий елемент} other {# нових елементів}}", - "loading_indicator.label": "Завантаження...", + "loading_indicator.label": "Завантаження…", "media_gallery.toggle_visible": "{number, plural, one {Приховати зображення} other {Приховати зображення}}", "moved_to_account_banner.text": "Ваш обліковий запис {disabledAccount} наразі вимкнений, оскільки вас перенесено до {movedToAccount}.", "mute_modal.duration": "Тривалість", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "На жаль, жоден результат не може бути показаний просто зараз. Ви можете спробувати скористатися пошуком або переглядом сторінки огляду, щоб знайти людей для слідкування або повторіть спробу пізніше.", "onboarding.follows.lead": "Ваша домашня стрічка - основний спосіб роботи Mastodon. Чим більше людей, які ви підписані, тим активнішою і цікавою. Ось деякі пропозиції на початок:", "onboarding.follows.title": "Персоналізуйте домашню стрічку", + "onboarding.profile.discoverable": "Враховувати профіль та дописи в алгоритмах пошуку", + "onboarding.profile.display_name": "Видиме ім'я", + "onboarding.profile.display_name_hint": "Ваше повне ім'я або ваш псевдонім…", + "onboarding.profile.indexable": "Включити загальнодоступні дописи в результати пошуку", + "onboarding.profile.lead": "Ви завжди можете завершити це пізніше в Налаштуваннях, де доступно ще більше опцій налаштування.", + "onboarding.profile.note": "Біографія", + "onboarding.profile.note_hint": "Ви можете @згадувати інших людей або #гештеґи…", + "onboarding.profile.save_and_continue": "Зберегти і продовжити", + "onboarding.profile.title": "Налаштування профілю", + "onboarding.profile.upload_avatar": "Завантажити зображення профілю", + "onboarding.profile.upload_header": "Завантажити заголовок профілю", "onboarding.share.lead": "Розкажіть людям про те, як вони можуть знайти вас на Mastodon!", "onboarding.share.message": "Я {username} на #Mastodon! Стежте за мною на {url}", "onboarding.share.next_steps": "Можливі такі кроки:", diff --git a/app/javascript/mastodon/locales/uz.json b/app/javascript/mastodon/locales/uz.json index afb4c4c4c..026cc115c 100644 --- a/app/javascript/mastodon/locales/uz.json +++ b/app/javascript/mastodon/locales/uz.json @@ -325,7 +325,6 @@ "lists.search": "Siz kuzatadigan odamlar orasidan qidiring", "lists.subheading": "Sizning ro'yxatlaringiz", "load_pending": "{count, plural, one {# yangi element} other {# yangi elementlar}}", - "loading_indicator.label": "Yuklanmoqda...", "media_gallery.toggle_visible": "{number, plural, one {Rasmni yashirish} other {Rasmlarni yashirish}}", "moved_to_account_banner.text": "{movedToAccount} hisobiga koʻchganingiz uchun {disabledAccount} hisobingiz hozirda oʻchirib qoʻyilgan.", "mute_modal.duration": "Davomiyligi", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index aa229eceb..c98be2b74 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -390,7 +390,6 @@ "lists.search": "Tìm kiếm những người mà bạn quan tâm", "lists.subheading": "Danh sách của bạn", "load_pending": "{count, plural, one {# tút mới} other {# tút mới}}", - "loading_indicator.label": "Đang tải...", "media_gallery.toggle_visible": "{number, plural, other {Ẩn hình ảnh}}", "moved_to_account_banner.text": "Tài khoản {disabledAccount} của bạn hiện không khả dụng vì bạn đã chuyển sang {movedToAccount}.", "mute_modal.duration": "Thời hạn", diff --git a/app/javascript/mastodon/locales/zgh.json b/app/javascript/mastodon/locales/zgh.json index 7b19e0e6a..5896a25b0 100644 --- a/app/javascript/mastodon/locales/zgh.json +++ b/app/javascript/mastodon/locales/zgh.json @@ -127,7 +127,6 @@ "lists.replies_policy.title": "ⵙⴽⵏ ⵜⵉⵔⴰⵔⵉⵏ ⵉ:", "lists.subheading": "ⵜⵉⵍⴳⴰⵎⵉⵏ ⵏⵏⴽ", "load_pending": "{count, plural, one {# ⵓⴼⵔⴷⵉⵙ ⴰⵎⴰⵢⵏⵓ} other {# ⵉⴼⵔⴷⴰⵙ ⵉⵎⴰⵢⵏⵓⵜⵏ}}", - "loading_indicator.label": "ⴰⵣⴷⴰⵎ...", "media_gallery.toggle_visible": "ⴼⴼⵔ {number, plural, one {ⵜⴰⵡⵍⴰⴼⵜ} other {ⵜⵉⵡⵍⴰⴼⵉⵏ}}", "navigation_bar.compose": "Compose new toot", "navigation_bar.domain_blocks": "Hidden domains", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index f830aa298..cc6d8994d 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -193,7 +193,7 @@ "conversation.with": "与 {names}", "copypaste.copied": "已复制", "copypaste.copy_to_clipboard": "复制到剪贴板", - "directory.federated": "来自已知联邦宇宙", + "directory.federated": "来自已知的联邦宇宙", "directory.local": "仅来自 {domain}", "directory.new_arrivals": "新来者", "directory.recently_active": "最近活跃", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "很抱歉,现在无法显示任何结果。您可以尝试使用搜索或浏览探索页面来查找要关注的人,或稍后再试。", "onboarding.follows.lead": "你管理你自己的家庭饲料。你关注的人越多,它将越活跃和有趣。 这些配置文件可能是一个很好的起点——你可以随时取消关注它们!", "onboarding.follows.title": "定制您的主页动态", + "onboarding.profile.discoverable": "在发现算法中展示您的个人资料和嘟文", + "onboarding.profile.display_name": "昵称", + "onboarding.profile.display_name_hint": "您的全名或昵称…", + "onboarding.profile.indexable": "将您的公开嘟文纳入搜索范围", + "onboarding.profile.lead": "您可以稍后在设置中完成此操作,设置中有更多的自定义选项。", + "onboarding.profile.note": "简介", + "onboarding.profile.note_hint": "您可以提及 @其他人 或 #标签…", + "onboarding.profile.save_and_continue": "保存并继续", + "onboarding.profile.title": "设置个人资料", + "onboarding.profile.upload_avatar": "上传头像", + "onboarding.profile.upload_header": "上传资料卡头图", "onboarding.share.lead": "让人们知道他们如何在Mastodon找到你!", "onboarding.share.message": "我是来自 #Mastodon 的 {username}!请在 {url} 关注我。", "onboarding.share.next_steps": "可能的下一步:", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index 7121a7d03..ea932bc5a 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -390,7 +390,7 @@ "lists.search": "從你關注的人搜索", "lists.subheading": "列表", "load_pending": "{count, plural, other {# 個新項目}}", - "loading_indicator.label": "載入中...", + "loading_indicator.label": "載入中…", "media_gallery.toggle_visible": "隱藏圖片", "moved_to_account_banner.text": "您的帳號 {disabledAccount} 目前已停用,因為您已搬家至 {movedToAccount}。", "mute_modal.duration": "時間", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "很遺憾,現在無法顯示任何結果。你可以嘗試搜尋或瀏覽探索頁面來找使用者來追蹤,或者稍後再試。", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.discoverable": "在探索的演算法中展示個人檔案和帖文", + "onboarding.profile.display_name": "顯示名稱", + "onboarding.profile.display_name_hint": "你的全名或暱稱…", + "onboarding.profile.indexable": "將公開帖文納入搜尋結果中", + "onboarding.profile.lead": "你可以隨時在設定中完成此動作,那裏有更多自訂選項。", + "onboarding.profile.note": "簡介", + "onboarding.profile.note_hint": "你可以 @提及他人 或使用 #標籤…", + "onboarding.profile.save_and_continue": "儲存並繼續", + "onboarding.profile.title": "個人檔案設定", + "onboarding.profile.upload_avatar": "上載個人檔案頭像", + "onboarding.profile.upload_header": "上載個人檔案橫幅圖片", "onboarding.share.lead": "讓大家知道如何在 Mastodon 上找到你吧!", "onboarding.share.message": "我在 #Mastodon 的使用者名稱是 {username}!快來追蹤我吧 {url}", "onboarding.share.next_steps": "接下來你可以:", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 974096d2f..4c52693cc 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -390,7 +390,7 @@ "lists.search": "搜尋您跟隨的使用者", "lists.subheading": "您的列表", "load_pending": "{count, plural, one {# 個新項目} other {# 個新項目}}", - "loading_indicator.label": "讀取中...", + "loading_indicator.label": "正在載入...", "media_gallery.toggle_visible": "切換可見性", "moved_to_account_banner.text": "您的帳號 {disabledAccount} 目前已停用,因為您已搬家至 {movedToAccount}。", "mute_modal.duration": "持續時間", @@ -479,6 +479,17 @@ "onboarding.follows.empty": "很遺憾,目前未能顯示任何結果。您可以嘗試使用搜尋、瀏覽探索頁面以找尋人們跟隨、或稍候再試。", "onboarding.follows.lead": "您的首頁時間軸是 Mastodon 的核心體驗。若您跟隨更多人的話,它將會變得更活躍有趣。這些個人檔案也許是個好起點,您可以隨時取消跟隨他們!", "onboarding.follows.title": "客製化您的首頁時間軸", + "onboarding.profile.discoverable": "於探索演算法中推薦個人檔案及嘟文", + "onboarding.profile.display_name": "顯示名稱", + "onboarding.profile.display_name_hint": "完整名稱或暱稱...", + "onboarding.profile.indexable": "允許公開嘟文顯示於搜尋結果中", + "onboarding.profile.lead": "您隨時可以稍候於設定中完成此操作,將有更多自訂選項可使用。", + "onboarding.profile.note": "個人簡介", + "onboarding.profile.note_hint": "您可以 @mention 其他人或者使用 #主題標籤...", + "onboarding.profile.save_and_continue": "儲存並繼續", + "onboarding.profile.title": "個人檔案設定", + "onboarding.profile.upload_avatar": "上傳個人檔案大頭貼", + "onboarding.profile.upload_header": "上傳個人檔案封面圖片", "onboarding.share.lead": "讓其他人知道他們如何於 Mastodon 上面找到您!", "onboarding.share.message": "我是 #Mastodon 上的 {username}!歡迎於 {url} 跟隨我", "onboarding.share.next_steps": "可能的下一步:", diff --git a/config/locales/be.yml b/config/locales/be.yml index 223b4d1df..fa43373f6 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -635,6 +635,7 @@ be: created_at: Створана delete_and_resolve: Выдаліць допісы forwarded: Пераслана + forwarded_replies_explanation: Гэтае паведамленне паступіла ад выдаленага карыстальніка і дакранаецца выдаленага змесціва. Яно было накіраванае вам, бо змесціва паведамлення з'яўляецца адказам аднаму з вашых карыстальнікаў. forwarded_to: Пераслана на %{domain} mark_as_resolved: Пазначыць як вырашаную mark_as_sensitive: Пазначыць як далікатны diff --git a/config/locales/bg.yml b/config/locales/bg.yml index 9da834301..dfff7058d 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -1368,6 +1368,7 @@ bg: '86400': 1 ден expires_in_prompt: Никога generate: Генериране на линк за покана + invalid: Тази покана не е валидна invited_by: 'Бяхте поканени от:' max_uses: one: 1 използване diff --git a/config/locales/da.yml b/config/locales/da.yml index 13010e1ad..7344d789f 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -611,6 +611,7 @@ da: created_at: Anmeldt delete_and_resolve: Slet indlæg forwarded: Videresendt + forwarded_replies_explanation: Denne anmeldelse er fra en ekstern bruger og om eksternt indhold. Den er videresendt til dig, da det anmeldte indhold er som svar til en af dine brugere. forwarded_to: Videresendt til %{domain} mark_as_resolved: Markér som løst mark_as_sensitive: Markér som sensitiv diff --git a/config/locales/de.yml b/config/locales/de.yml index 81fa4b57f..69309737d 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -611,6 +611,7 @@ de: created_at: Gemeldet delete_and_resolve: Beiträge löschen forwarded: Weitergeleitet + forwarded_replies_explanation: Diese Meldung stammt von einem externen Profil und betrifft einen externen Inhalt. Der Inhalt wurde an Dich weitergeleitet, weil er eine Antwort auf ein bei Dir registriertes Profil ist. forwarded_to: Weitergeleitet an %{domain} mark_as_resolved: Als geklärt markieren mark_as_sensitive: Mit einer Inhaltswarnung versehen diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml index 9175a1fc1..88248d098 100644 --- a/config/locales/es-AR.yml +++ b/config/locales/es-AR.yml @@ -611,6 +611,7 @@ es-AR: created_at: Denunciado delete_and_resolve: Eliminar mensajes forwarded: Reenviado + forwarded_replies_explanation: Esta denuncia es de un usuario remoto y sobre contenido remoto. Se te reenvió porque el contenido denunciado es en respuesta a uno de tus usuarios. forwarded_to: Reenviado a %{domain} mark_as_resolved: Marcar como resuelta mark_as_sensitive: Marcar como sensible diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index 75d329b0a..4ecb666b0 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -611,6 +611,7 @@ es-MX: created_at: Denunciado delete_and_resolve: Eliminar publicaciones forwarded: Reenviado + forwarded_replies_explanation: Este reporte es de un usuario remoto y sobre contenido remoto. Se le ha enviado porque el contenido reportado es en respuesta a uno de sus usuarios. forwarded_to: Reenviado a %{domain} mark_as_resolved: Marcar como resuelto mark_as_sensitive: Marcar como sensible diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 4fe0179df..73442396f 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -611,6 +611,7 @@ fi: created_at: Raportoitu delete_and_resolve: Poista julkaisut forwarded: Välitetty + forwarded_replies_explanation: Tämä raportti on etäkäyttäjältä ja koskee etäsisältöä. Se on välitetty sinulle, koska raportoitu sisältö on vastaus jollekin käyttäjällesi. forwarded_to: Välitetty %{domain} mark_as_resolved: Merkitse ratkaistuksi mark_as_sensitive: Merkitse arkaluonteiseksi @@ -1368,6 +1369,7 @@ fi: '86400': 1 vuorokausi expires_in_prompt: Ei koskaan generate: Luo + invalid: Tämä kutsu ei ole kelvollinen invited_by: 'Sinut kutsui:' max_uses: one: kertakäyttöinen diff --git a/config/locales/he.yml b/config/locales/he.yml index 11e5db453..35dc99650 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -635,6 +635,7 @@ he: created_at: מדווח delete_and_resolve: מחיקת הודעות forwarded: קודם + forwarded_replies_explanation: דווח זה הגיע מחשבון משתמש חיצוני על תוכן חיצוני. הוא הועבר אליך כיוון שהתוכן שדווח הוא בתשובה למשתמש.ת שלך. forwarded_to: קודם ל-%{domain} mark_as_resolved: סימון כפתור mark_as_sensitive: סימון כרגיש @@ -786,7 +787,7 @@ he: public_timelines: פידים פומביים publish_discovered_servers: פרסום שרתים שנתגלו publish_statistics: פרסום הסטטיסטיקות בפומבי - title: גילוי + title: תגליות trends: נושאים חמים domain_blocks: all: לכולם @@ -1048,7 +1049,7 @@ he: advanced_web_interface_hint: 'אם ברצונך לעשות שימוש במלוא רוחב המסך, ממשק הווב המתקדם מאפשר לך להגדיר עמודות רבות ושונות כדי לראות בו זמנית כמה מידע שתרצה/י: פיד הבית, התראות, פרהסיה ומספר כלשהו של רשימות ותגיות.' animations_and_accessibility: הנפשות ונגישות confirmation_dialogs: חלונות אישור - discovery: גילוי + discovery: תגליות localization: body: מסטודון מתורגם על ידי מתנדבים. guide_link: https://crowdin.com/project/mastodon @@ -1336,7 +1337,7 @@ he: deselect: בטל בחירה של הכל none: כלום order_by: מיין לפי - save_changes: שמור שינויים + save_changes: לשמור שינויים select_all_matching_items: many: בחר.י %{count} פריטים שתאמו לחיפוש שלך. one: בחר.י פריט %{count} שתאם לחיפוש שלך. @@ -1780,7 +1781,7 @@ he: keep_media_hint: לא מוחק את הודעותיך שמצורפים אליהן קבצי מדיה keep_pinned: שמור הודעות מוצמדות keep_pinned_hint: לא מוחק אף אחד מההודעות המוצמדות שלך - keep_polls: שמור סקרים + keep_polls: לשמור סקרים keep_polls_hint: לא מוחר אף אחד מהסקרים שלך keep_self_bookmark: שמור הודעות שסימנת keep_self_bookmark_hint: לא מוחק הודעות שסימנת @@ -1868,7 +1869,7 @@ he: disable: אינך יכול/ה יותר להשתמש בחשבונך, אבל הפרופיל ושאר המידע נשארו על עומדם. ניתן לבקש גיבוי של המידע, לשנות את הגדרות החשבון או למחוק אותו. mark_statuses_as_sensitive: כמה מהודעותיך סומנו כרגישות על ידי מנחי הקהילה של %{instance}. זה אומר שאנשים יצטרכו להקיש על המדיה בהודעות לפני שתופיע תצוגה מקדימה. ניתן לסמן את המידע כרגיש בעצמך בהודעותיך העתידיות. sensitive: מעתה ואילך כל קבצי המדיה שיועלו על ידך יסומנו כרגישים ויוסתרו מאחורי אזהרה. - silence: ניתן עדיין להשתמש בחשבונך אבל רק אנשים שכבר עוקבים אחריך יראו את הודעותיך בשרת זה, וייתכן שתוחרג/י מאמצעי גילוי משתמשים. עם זאת, אחרים יוכלו עדיין לעקוב אחריך. + silence: ניתן עדיין להשתמש בחשבונך אבל רק אנשים שכבר עוקבים אחריך יראו את הודעותיך בשרת זה, וייתכן שתוחרג/י ממסכי התגליות. עם זאת, אחרים יוכלו עדיין לעקוב אחריך. suspend: לא ניתן יותר להשתמש בחשבונך, ופרופילך וכל מידע אחר לא נגישים יותר. ניתן עדיין להתחבר על מנת לבקש גיבוי של המידע שלך עד שיוסר סופית בעוד כ-30 יום, אבל מידע מסויים ישמר על מנת לוודא שלא תחמוק/י מההשעיה. reason: 'סיבה:' statuses: 'הודעות מצוטטות:' diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 48f9d5b9d..a0ff3061f 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -611,6 +611,7 @@ hu: created_at: Jelentve delete_and_resolve: Bejegyzések törlése forwarded: Továbbítva + forwarded_replies_explanation: Ez a jelentés egy távoli felhasználótól származik, és távoli tartalomról szól. Azért lett neked továbbítva, mert a jelentett tartalom az egyik felhasználódnak küldött válasz. forwarded_to: 'Továbbítva ide: %{domain}' mark_as_resolved: Megjelölés megoldottként mark_as_sensitive: Érzékenynek jelölés diff --git a/config/locales/is.yml b/config/locales/is.yml index 390ce0ac0..a4706ee51 100644 --- a/config/locales/is.yml +++ b/config/locales/is.yml @@ -611,6 +611,7 @@ is: created_at: Tilkynnt delete_and_resolve: Eyða færslum forwarded: Áframsent + forwarded_replies_explanation: Þessi kæra er frá fjartengdum notanda og er um fjartengt efni. Hún hefur verið framsend til þín þar sem kærða efnið er í svari til eins af notendunum þínum. forwarded_to: Áframsent á %{domain} mark_as_resolved: Merkja sem leyst mark_as_sensitive: Merkja sem viðkvæmt diff --git a/config/locales/it.yml b/config/locales/it.yml index f35e9e42b..82bbf7251 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -611,6 +611,7 @@ it: created_at: Segnalato delete_and_resolve: Cancella post forwarded: Inoltrato + forwarded_replies_explanation: Questa segnalazione proviene da un utente remoto e tratta di contenuti remoti. È stato inoltrato a voi perché il contenuto riportato è in risposta a uno dei vostri utenti. forwarded_to: Inoltrato a %{domain} mark_as_resolved: Segna come risolto mark_as_sensitive: Segna come sensibile diff --git a/config/locales/ko.yml b/config/locales/ko.yml index fb193c75f..e11081fcd 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -601,6 +601,7 @@ ko: created_at: 신고 시각 delete_and_resolve: 게시물 삭제 forwarded: 전달됨 + forwarded_replies_explanation: 이 신고는 리모트 사용자가 리모트 컨텐츠에 대해 신고한 것입니다. 이것은 신고된 내용이 로컬 사용자에 대한 답글이기 때문에 첨부되었습니다. forwarded_to: "%{domain}에게 전달됨" mark_as_resolved: 해결로 표시 mark_as_sensitive: 민감함으로 설정 diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 529eb5a44..035b04462 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -214,6 +214,7 @@ lt: comment: none: Nėra created_at: Reportuotas + forwarded_replies_explanation: Šis ataskaita yra iš nuotolinio naudotojo ir susijusi su nuotoliniu turiniu. Jis buvo persiųstas tau, nes turinys, apie kurį pranešta, yra atsakymas vienam iš tavo naudotojų. mark_as_resolved: Pažymėti kaip išsprestą mark_as_unresolved: Pažymėti kaip neišsprestą notes: diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 94a1f29f7..4147078d3 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -611,6 +611,7 @@ nl: created_at: Gerapporteerd op delete_and_resolve: Bericht verwijderen forwarded: Doorgestuurd + forwarded_replies_explanation: Dit rapport komt van een externe gebruiker en gaat over externe inhoud. Het is naar u doorgestuurd omdat de gerapporteerde inhoud een reactie is op een van uw gebruikers. forwarded_to: Doorgestuurd naar %{domain} mark_as_resolved: Markeer als opgelost mark_as_sensitive: Als gevoelig markeren diff --git a/config/locales/nn.yml b/config/locales/nn.yml index 4925d4463..09de24a67 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -611,6 +611,7 @@ nn: created_at: Rapportert delete_and_resolve: Slett innlegg forwarded: Videresendt + forwarded_replies_explanation: Denne rapporten er fra en ekstern bruker og handler om eksternt innhold. Den er videresendt til deg fordi det rapporterte innholdet svarer til en av brukerne dine. forwarded_to: Videresendt til %{domain} mark_as_resolved: Merk som løyst mark_as_sensitive: Marker som ømtolig diff --git a/config/locales/no.yml b/config/locales/no.yml index a1058bf9f..3cf2df3a1 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -611,6 +611,7 @@ created_at: Rapportert delete_and_resolve: Slettede innlegg forwarded: Videresendt + forwarded_replies_explanation: Denne rapporten er fra en ekstern bruker og handler om eksternt innhold. Den er videresendt til deg fordi det rapporterte innholdet svarer til en av brukerne dine. forwarded_to: Videresendt til %{domain} mark_as_resolved: Merk som løst mark_as_sensitive: Merk som følsomt diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 69b1aa0a9..4ff81e11e 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -635,6 +635,7 @@ pl: created_at: Zgłoszono delete_and_resolve: Usuń posty forwarded: Przekazano + forwarded_replies_explanation: Ten raport nadszedł od zdalnego użytkownika i dotyczy zdalnej treści. Został ci przekazany, bo raportowana treść jest odpowiedzią na jednego z twoich użytkowników. forwarded_to: Przekazano do %{domain} mark_as_resolved: Oznacz jako rozwiązane mark_as_sensitive: Oznacz jako wrażliwe diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index ce7479aa8..8e147ce4c 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -611,6 +611,7 @@ pt-PT: created_at: Denunciado delete_and_resolve: Eliminar publicações forwarded: Encaminhado + forwarded_replies_explanation: Esta denúncia é de um utilizador remoto e sobre conteúdo remoto. Foi encaminhada para si porque o conteúdo denunciado é em resposta a um dos seus utilizadores. forwarded_to: Encaminhado para %{domain} mark_as_resolved: Marcar como resolvido mark_as_sensitive: Marcar como problemático diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml index bada4c3d0..29f2398a9 100644 --- a/config/locales/simple_form.fi.yml +++ b/config/locales/simple_form.fi.yml @@ -188,7 +188,7 @@ fi: email: Sähköpostiosoite expires_in: Vanhenee fields: Lisäkentät - header: Otsikkokuva + header: Otsakekuva honeypot: "%{label} (älä täytä)" inbox_url: Välittäjän postilaatikon URL-osoite irreversible: Pudota piilottamisen sijaan diff --git a/config/locales/simple_form.he.yml b/config/locales/simple_form.he.yml index 13ea8a0c4..04b21cd1b 100644 --- a/config/locales/simple_form.he.yml +++ b/config/locales/simple_form.he.yml @@ -85,7 +85,7 @@ he: mascot: בחירת ציור למנשק הווב המתקדם. media_cache_retention_period: קבצי מדיה שהורדו ימחקו אחרי מספר הימים שיצוינו אם נבחר מספר חיובי, או-אז יורדו שוב מחדש בהתאם לצורך. peers_api_enabled: רשימת השרתים ששרת זה פגש בפדיוורס. לא כולל מידע לגבי קשר ישיר עם שרת נתון, אלא רק שידוע לשרת זה על קיומו. מידע זה משמש שירותים האוספים סטטיסטיקות כלליות על הפדרציה. - profile_directory: מדריך הפרופילים מפרט את כל המשתמשים שביקשו להיות ניתנים לגילוי. + profile_directory: ספריית הפרופילים מציגה ברשימה את כל המשתמשים שביקשו להיות ניתנים לגילוי. require_invite_text: כאשר הרשמות דורשות אישור ידני, הפיכת טקסט ה"מדוע את/ה רוצה להצטרף" להכרחי במקום אופציונלי site_contact_email: מה היא הדרך ליצור איתך קשר לצורך תמיכה או לצורך תאימות עם החוק. site_contact_username: כיצד יכולים אחרים ליצור איתך קשר על רשת מסטודון. @@ -140,7 +140,7 @@ he: url: היעד שאליו יישלחו אירועים labels: account: - discoverable: חשיפת פרופיל משתמש והודעות לאלגוריתם של האתר + discoverable: הצג משתמש ופוסטים בעמוד התגליות fields: name: תווית value: תוכן @@ -188,7 +188,7 @@ he: email: כתובת דוא"ל expires_in: תפוגה לאחר fields: מטא-נתונים על הפרופיל - header: כותרת + header: תמונת נושא honeypot: "%{label} (לא למלא)" inbox_url: קישורית לתיבת ממסר irreversible: הסרה במקום הסתרה diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml index 7b2656155..720012a31 100644 --- a/config/locales/simple_form.ko.yml +++ b/config/locales/simple_form.ko.yml @@ -4,7 +4,7 @@ ko: hints: account: discoverable: 내 공개 게시물과 프로필이 마스토돈의 다양한 추천 기능에 나타날 수 있고 프로필이 다른 사용자에게 제안될 수 있습니다 - display_name: 실명 혹은 별명. + display_name: 진짜 이름 또는 재미난 이름. fields: 홈페이지, 호칭, 나이, 뭐든지 적고 싶은 것들. indexable: 내 공개 게시물이 마스토돈의 검색 결과에 나타날 수 있습니다. 내 게시물과 상호작용했던 사람들은 이 설정과 관계 없이 그 게시물을 검색할 수 있습니다. note: '남을 @mention 하거나 #hashtag 태그를 달 수 있습니다.' @@ -195,7 +195,7 @@ ko: locale: 인터페이스 언어 max_uses: 사용 횟수 제한 new_password: 새로운 암호 입력 - note: 소개 + note: 자기소개 otp_attempt: 이중 인증 코드 password: 암호 phrase: 키워드 또는 문장 diff --git a/config/locales/sq.yml b/config/locales/sq.yml index bd01a8089..b6a7736df 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -1,18 +1,18 @@ --- sq: about: - about_mastodon_html: 'Rrjeti shoqëror i së ardhmes: Pa reklama, pa survejim nga korporata, konceptim etik dhe decentralizim! Jini zot i të dhënave tuaja, me Mastodon-in!' - contact_missing: I parregulluar + about_mastodon_html: 'Rrjeti social i së ardhmes: Pa reklama, pa sy vëzhguese nga korporata, etik dhe i decentralizuar! Merrni sërisht zotësinë e të dhënave tuaja, me Mastodon!' + contact_missing: E pacaktuar contact_unavailable: N/A - hosted_on: Mastodon i strehuar në %{domain} + hosted_on: Server Mastodon i strehuar në %{domain} title: Mbi accounts: follow: Ndiqeni followers: one: Ndjekës other: Ndjekës - following: Ndjekje - instance_actor_flash: Kjo llogari është një aktor virtual, i përdorur për të përfaqësuar vetë shërbyesin dhe jo ndonjë përdorues individual. Përdoret për qëllime federimi dhe s’duhet pezulluar. + following: Po ndjek + instance_actor_flash: Kjo llogari është një aktor virtual, i përdorur për të përfaqësuar vetë serverin dhe jo ndonjë përdorues. Përdoret për qëllime federimi dhe s’duhet pezulluar. last_active: aktiv së fundi link_verified_on: Pronësia e kësaj lidhjeje qe kontrolluar më %{date} nothing_here: S’ka gjë këtu! @@ -610,6 +610,7 @@ sq: created_at: Raportuar më delete_and_resolve: Fshiji postimet forwarded: U përcoll + forwarded_replies_explanation: Ky raportim është nga një përdorues i largët dhe rreth lënde të largët. Ju është përcjellë ngaqë lënda e raportuar gjendet në përgjigje ndaj njërit prej përdoruesve tuaj. forwarded_to: U përcoll te %{domain} mark_as_resolved: Vëri shenjë si i zgjidhur mark_as_sensitive: Vëri shenjë si rezervat @@ -925,6 +926,7 @@ sq: peaked_on_and_decaying: Kulmoi më %{date}, tani në rënie title: Hashtag-ë në modë trendable: Mund të shfaqet nën të modës + trending_rank: 'Trending #%{rank}' usable: Mund të përdoret usage_comparison: Përdorur %{today} herë sot, krahasuar me %{yesterday} dje used_by_over_week: diff --git a/config/locales/th.yml b/config/locales/th.yml index 661899896..79d668d3e 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -599,6 +599,7 @@ th: created_at: รายงานเมื่อ delete_and_resolve: ลบโพสต์ forwarded: ส่งต่อแล้ว + forwarded_replies_explanation: รายงานนี้มาจากผู้ใช้ระยะไกล และเป็นรายงานเกี่ยวกับเนื้อหาระยะไกล ซึ่งถูกส่งต่อมาหาคุณเนื่องจากเนื้อหาที่ถูกรายงานอยู่ในการตอบกลับไปยังหนึ่งในผู้ใช้ของคุณ forwarded_to: ส่งต่อไปยัง %{domain} แล้ว mark_as_resolved: ทำเครื่องหมายว่าแก้ปัญหาแล้ว mark_as_sensitive: ทำเครื่องหมายว่าละเอียดอ่อน diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 2261c647b..e9eee14a1 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -635,6 +635,7 @@ uk: created_at: Створено delete_and_resolve: Видалити дописи forwarded: Переслано + forwarded_replies_explanation: Цей звіт належить віддаленому користувачеві і про віддалений вміст. Контент був пересланий вам, тому що він містить повідомлення у відповідь одному з ваших користувачів. forwarded_to: Переслано до %{domain} mark_as_resolved: Позначити вирішеним mark_as_sensitive: Позначити делікатним diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml index f13cedad6..5dd0d2e61 100644 --- a/config/locales/zh-HK.yml +++ b/config/locales/zh-HK.yml @@ -599,6 +599,7 @@ zh-HK: created_at: 日期 delete_and_resolve: 刪除帖文 forwarded: 已轉寄 + forwarded_replies_explanation: 這份檢舉來自一位遠端使用者,並涉及遠端內容。之所以轉交給你,是因為被檢舉的內容是回覆你其中一位使用者。 forwarded_to: 已轉寄到 %{domain} mark_as_resolved: 標示為「已處理」 mark_as_sensitive: 標記為敏感內容 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 7259afdbe..2f65855fc 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -70,7 +70,7 @@ zh-TW: enabled_msg: 成功解除 %{username} 帳號的凍結 followers: 跟隨者 follows: 正在跟隨 - header: 開頭 + header: 封面圖片 inbox_url: 收件匣 (Inbox) URL invite_request_text: 加入原因 invited_by: 邀請者 @@ -117,7 +117,7 @@ zh-TW: remote_suspension_irreversible: 此帳號之資料已被不可逆地刪除。 remote_suspension_reversible_hint_html: 這個帳號已於此伺服器被停權,所有資料將會於 %{date} 被刪除。於此之前,遠端伺服器可以完全回復此的帳號。如果您想即時刪除這個帳號的資料,您能於下面進行操作。 remove_avatar: 取消大頭貼 - remove_header: 移除開頭 + remove_header: 移除封面圖片 removed_avatar_msg: 已成功刪除 %{username} 的大頭貼 removed_header_msg: 已成功刪除 %{username} 的封面圖片 resend_confirmation: @@ -599,6 +599,7 @@ zh-TW: created_at: 日期 delete_and_resolve: 刪除嘟文 forwarded: 已轉寄 + forwarded_replies_explanation: 此報告來自聯邦宇宙中非本伺服器帳號,關於非本伺服器內容。此報告轉發給您,因為報告之內容是回覆給您的伺服器上某位使用者。 forwarded_to: 轉寄到 %{domain} mark_as_resolved: 標記為「已解決」 mark_as_sensitive: 標記為敏感內容 From 87696ea26e832fda3cb7a335db6c5899c5ddbf6d Mon Sep 17 00:00:00 2001 From: Eugen Rochko <eugen@zeonfederated.com> Date: Thu, 16 Nov 2023 11:23:14 +0100 Subject: [PATCH 054/255] Add prominent share/copy button on profiles in web UI (#27865) --- .../mastodon/components/copy_icon_button.jsx | 44 +++++++++++++++++++ .../features/account/components/header.jsx | 23 ++++++---- app/javascript/mastodon/locales/en.json | 2 + .../styles/mastodon/components.scss | 21 +++++++++ 4 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 app/javascript/mastodon/components/copy_icon_button.jsx diff --git a/app/javascript/mastodon/components/copy_icon_button.jsx b/app/javascript/mastodon/components/copy_icon_button.jsx new file mode 100644 index 000000000..9b1a36d83 --- /dev/null +++ b/app/javascript/mastodon/components/copy_icon_button.jsx @@ -0,0 +1,44 @@ +import PropTypes from 'prop-types'; +import { useState, useCallback } from 'react'; + +import { defineMessages } from 'react-intl'; + +import classNames from 'classnames'; + +import { useDispatch } from 'react-redux'; + +import { ReactComponent as ContentCopyIcon } from '@material-symbols/svg-600/outlined/content_copy.svg'; + +import { showAlert } from 'mastodon/actions/alerts'; +import { IconButton } from 'mastodon/components/icon_button'; + +const messages = defineMessages({ + copied: { id: 'copy_icon_button.copied', defaultMessage: 'Copied to clipboard' }, +}); + +export const CopyIconButton = ({ title, value, className }) => { + const [copied, setCopied] = useState(false); + const dispatch = useDispatch(); + + const handleClick = useCallback(() => { + navigator.clipboard.writeText(value); + setCopied(true); + dispatch(showAlert({ message: messages.copied })); + setTimeout(() => setCopied(false), 700); + }, [setCopied, value, dispatch]); + + return ( + <IconButton + className={classNames(className, copied ? 'copied' : 'copyable')} + title={title} + onClick={handleClick} + iconComponent={ContentCopyIcon} + /> + ); +}; + +CopyIconButton.propTypes = { + title: PropTypes.string, + value: PropTypes.string, + className: PropTypes.string, +}; diff --git a/app/javascript/mastodon/features/account/components/header.jsx b/app/javascript/mastodon/features/account/components/header.jsx index 7594135a4..29b46cb43 100644 --- a/app/javascript/mastodon/features/account/components/header.jsx +++ b/app/javascript/mastodon/features/account/components/header.jsx @@ -14,10 +14,12 @@ import { ReactComponent as LockIcon } from '@material-symbols/svg-600/outlined/l import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg'; import { ReactComponent as NotificationsIcon } from '@material-symbols/svg-600/outlined/notifications.svg'; import { ReactComponent as NotificationsActiveIcon } from '@material-symbols/svg-600/outlined/notifications_active-fill.svg'; +import { ReactComponent as ShareIcon } from '@material-symbols/svg-600/outlined/share.svg'; import { Avatar } from 'mastodon/components/avatar'; import { Badge, AutomatedBadge, GroupBadge } from 'mastodon/components/badge'; import { Button } from 'mastodon/components/button'; +import { CopyIconButton } from 'mastodon/components/copy_icon_button'; import { FollowersCounter, FollowingCounter, StatusesCounter } from 'mastodon/components/counters'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from 'mastodon/components/icon_button'; @@ -46,6 +48,7 @@ const messages = defineMessages({ mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' }, report: { id: 'account.report', defaultMessage: 'Report @{name}' }, share: { id: 'account.share', defaultMessage: 'Share @{name}\'s profile' }, + copy: { id: 'account.copy', defaultMessage: 'Copy link to profile' }, media: { id: 'account.media', defaultMessage: 'Media' }, blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' }, unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' }, @@ -245,11 +248,10 @@ class Header extends ImmutablePureComponent { const isRemote = account.get('acct') !== account.get('username'); const remoteDomain = isRemote ? account.get('acct').split('@')[1] : null; - let info = []; - let actionBtn = ''; - let bellBtn = ''; - let lockedIcon = ''; - let menu = []; + let actionBtn, bellBtn, lockedIcon, shareBtn; + + let info = []; + let menu = []; if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) { info.push(<span key='followed_by' className='relationship-tag'><FormattedMessage id='account.follows_you' defaultMessage='Follows you' /></span>); @@ -267,6 +269,12 @@ class Header extends ImmutablePureComponent { bellBtn = <IconButton icon={account.getIn(['relationship', 'notifying']) ? 'bell' : 'bell-o'} iconComponent={account.getIn(['relationship', 'notifying']) ? NotificationsActiveIcon : NotificationsIcon} active={account.getIn(['relationship', 'notifying'])} title={intl.formatMessage(account.getIn(['relationship', 'notifying']) ? messages.disableNotifications : messages.enableNotifications, { name: account.get('username') })} onClick={this.props.onNotifyToggle} />; } + if ('share' in navigator) { + shareBtn = <IconButton className='optional' iconComponent={ShareIcon} title={intl.formatMessage(messages.share, { name: account.get('username') })} onClick={this.handleShare} />; + } else { + shareBtn = <CopyIconButton className='optional' title={intl.formatMessage(messages.copy)} value={account.get('url')} />; + } + if (me !== account.get('id')) { if (signedIn && !account.get('relationship')) { // Wait until the relationship is loaded actionBtn = ''; @@ -297,10 +305,6 @@ class Header extends ImmutablePureComponent { if (isRemote) { menu.push({ text: intl.formatMessage(messages.openOriginalPage), href: account.get('url') }); - } - - if ('share' in navigator && !account.get('suspended')) { - menu.push({ text: intl.formatMessage(messages.share, { name: account.get('username') }), action: this.handleShare }); menu.push(null); } @@ -414,6 +418,7 @@ class Header extends ImmutablePureComponent { <> {actionBtn} {bellBtn} + {shareBtn} </> )} diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 041446037..16941e2ca 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -21,6 +21,7 @@ "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", "account.cancel_follow_request": "Cancel follow", + "account.copy": "Copy link to profile", "account.direct": "Privately mention @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain blocked", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copy_icon_button.copied": "Copied to clipboard", "copypaste.copied": "Copied", "copypaste.copy_to_clipboard": "Copy to clipboard", "directory.federated": "From known fediverse", diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 9f87352f5..cc9b54d9e 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -286,6 +286,17 @@ font-size: 12px; font-weight: 500; } + + &.copyable { + transition: all 300ms linear; + } + + &.copied { + border-color: $valid-value-color; + color: $valid-value-color; + transition: none; + background-color: rgba($valid-value-color, 0.15); + } } .text-icon-button { @@ -7373,6 +7384,16 @@ noscript { width: 24px; height: 24px; } + + &.copied { + border-color: $valid-value-color; + } + } + + @media screen and (width <= 427px) { + .optional { + display: none; + } } } From c94bedf4e6e5987864b42d63aa90920f80d3644e Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Thu, 16 Nov 2023 12:59:45 +0100 Subject: [PATCH 055/255] Use container queries to hide profile share button (#27889) --- app/javascript/styles/mastodon/components.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index cc9b54d9e..8a79eddf0 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -7289,6 +7289,7 @@ noscript { .account__header { overflow: hidden; + container: account-header / inline-size; &.inactive { opacity: 0.5; @@ -7390,7 +7391,7 @@ noscript { } } - @media screen and (width <= 427px) { + @container account-header (max-width: 372px) { .optional { display: none; } From 0a6ec048a8123a26ba9e00896cecbd03c5e3a990 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Thu, 16 Nov 2023 14:43:02 +0100 Subject: [PATCH 056/255] Fix upper border radius of onboarding columns (#27890) --- app/javascript/styles/mastodon/components.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 8a79eddf0..9c3d9dc2c 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -2299,8 +2299,7 @@ $ui-header-height: 55px; > .scrollable { background: $ui-base-color; - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px; + border-radius: 0 0 4px 4px; } } From 155fb8414150e78b4e61aa33d483cc7713161134 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 16 Nov 2023 09:36:59 -0500 Subject: [PATCH 057/255] Improve spec coverage for collection of `workers/` classes (#27874) --- .../account_deletion_request_fabricator.rb | 5 ++ spec/fabricators/import_fabricator.rb | 7 +++ spec/workers/account_refresh_worker_spec.rb | 52 ++++++++++++++++ .../activitypub/post_upgrade_worker_spec.rb | 18 ++++++ ...ze_featured_tags_collection_worker_spec.rb | 29 +++++++++ spec/workers/admin/suspension_worker_spec.rb | 28 +++++++++ .../after_account_domain_block_worker_spec.rb | 29 +++++++++ spec/workers/backup_worker_spec.rb | 36 +++++++++++ spec/workers/delete_mute_worker_spec.rb | 42 +++++++++++++ spec/workers/feed_insert_worker_spec.rb | 21 ++++++- spec/workers/import_worker_spec.rb | 23 +++++++ .../workers/post_process_media_worker_spec.rb | 34 +++++++++-- ...blish_announcement_reaction_worker_spec.rb | 38 ++++++++++++ spec/workers/removal_worker_spec.rb | 28 +++++++++ .../scheduler/self_destruct_scheduler_spec.rb | 60 +++++++++++++++++++ spec/workers/webhooks/delivery_worker_spec.rb | 18 +++++- 16 files changed, 460 insertions(+), 8 deletions(-) create mode 100644 spec/fabricators/account_deletion_request_fabricator.rb create mode 100644 spec/fabricators/import_fabricator.rb create mode 100644 spec/workers/account_refresh_worker_spec.rb create mode 100644 spec/workers/activitypub/post_upgrade_worker_spec.rb create mode 100644 spec/workers/activitypub/synchronize_featured_tags_collection_worker_spec.rb create mode 100644 spec/workers/admin/suspension_worker_spec.rb create mode 100644 spec/workers/after_account_domain_block_worker_spec.rb create mode 100644 spec/workers/backup_worker_spec.rb create mode 100644 spec/workers/delete_mute_worker_spec.rb create mode 100644 spec/workers/import_worker_spec.rb create mode 100644 spec/workers/publish_announcement_reaction_worker_spec.rb create mode 100644 spec/workers/removal_worker_spec.rb create mode 100644 spec/workers/scheduler/self_destruct_scheduler_spec.rb diff --git a/spec/fabricators/account_deletion_request_fabricator.rb b/spec/fabricators/account_deletion_request_fabricator.rb new file mode 100644 index 000000000..3d3d37398 --- /dev/null +++ b/spec/fabricators/account_deletion_request_fabricator.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +Fabricator(:account_deletion_request) do + account +end diff --git a/spec/fabricators/import_fabricator.rb b/spec/fabricators/import_fabricator.rb new file mode 100644 index 000000000..4951bb9a4 --- /dev/null +++ b/spec/fabricators/import_fabricator.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +Fabricator(:import) do + account + type :following + data { attachment_fixture('imports.txt') } +end diff --git a/spec/workers/account_refresh_worker_spec.rb b/spec/workers/account_refresh_worker_spec.rb new file mode 100644 index 000000000..361d69aa0 --- /dev/null +++ b/spec/workers/account_refresh_worker_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe AccountRefreshWorker do + let(:worker) { described_class.new } + let(:service) { instance_double(ResolveAccountService, call: true) } + + describe '#perform' do + before do + allow(ResolveAccountService).to receive(:new).and_return(service) + end + + context 'when account does not exist' do + it 'returns immediately without processing' do + worker.perform(123_123_123) + + expect(service).to_not have_received(:call) + end + end + + context 'when account exists' do + context 'when account does not need refreshing' do + let(:account) { Fabricate(:account, last_webfingered_at: recent_webfinger_at) } + + it 'returns immediately without processing' do + worker.perform(account.id) + + expect(service).to_not have_received(:call) + end + end + + context 'when account needs refreshing' do + let(:account) { Fabricate(:account, last_webfingered_at: outdated_webfinger_at) } + + it 'schedules an account update' do + worker.perform(account.id) + + expect(service).to have_received(:call) + end + end + + def recent_webfinger_at + (Account::BACKGROUND_REFRESH_INTERVAL - 3.days).ago + end + + def outdated_webfinger_at + (Account::BACKGROUND_REFRESH_INTERVAL + 3.days).ago + end + end + end +end diff --git a/spec/workers/activitypub/post_upgrade_worker_spec.rb b/spec/workers/activitypub/post_upgrade_worker_spec.rb new file mode 100644 index 000000000..08de150ad --- /dev/null +++ b/spec/workers/activitypub/post_upgrade_worker_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ActivityPub::PostUpgradeWorker do + let(:worker) { described_class.new } + + describe '#perform' do + let(:domain) { 'host.example' } + + it 'updates relevant values' do + account = Fabricate(:account, domain: domain, last_webfingered_at: 1.day.ago, protocol: :ostatus) + worker.perform(domain) + + expect(account.reload.last_webfingered_at).to be_nil + end + end +end diff --git a/spec/workers/activitypub/synchronize_featured_tags_collection_worker_spec.rb b/spec/workers/activitypub/synchronize_featured_tags_collection_worker_spec.rb new file mode 100644 index 000000000..8cf13cb90 --- /dev/null +++ b/spec/workers/activitypub/synchronize_featured_tags_collection_worker_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ActivityPub::SynchronizeFeaturedTagsCollectionWorker do + let(:worker) { described_class.new } + let(:service) { instance_double(ActivityPub::FetchFeaturedTagsCollectionService, call: true) } + + describe '#perform' do + before do + allow(ActivityPub::FetchFeaturedTagsCollectionService).to receive(:new).and_return(service) + end + + let(:account) { Fabricate(:account) } + let(:url) { 'https://host.example' } + + it 'sends the account and url to the service' do + worker.perform(account.id, url) + + expect(service).to have_received(:call).with(account, url) + end + + it 'returns true for non-existent record' do + result = worker.perform(123_123_123, url) + + expect(result).to be(true) + end + end +end diff --git a/spec/workers/admin/suspension_worker_spec.rb b/spec/workers/admin/suspension_worker_spec.rb new file mode 100644 index 000000000..da12037ed --- /dev/null +++ b/spec/workers/admin/suspension_worker_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Admin::SuspensionWorker do + let(:worker) { described_class.new } + let(:service) { instance_double(SuspendAccountService, call: true) } + + describe '#perform' do + before do + allow(SuspendAccountService).to receive(:new).and_return(service) + end + + let(:account) { Fabricate(:account) } + + it 'sends the account to the service' do + worker.perform(account.id) + + expect(service).to have_received(:call).with(account) + end + + it 'returns true for non-existent record' do + result = worker.perform(123_123_123) + + expect(result).to be(true) + end + end +end diff --git a/spec/workers/after_account_domain_block_worker_spec.rb b/spec/workers/after_account_domain_block_worker_spec.rb new file mode 100644 index 000000000..54a113a2b --- /dev/null +++ b/spec/workers/after_account_domain_block_worker_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe AfterAccountDomainBlockWorker do + let(:worker) { described_class.new } + let(:service) { instance_double(AfterBlockDomainFromAccountService, call: true) } + + describe '#perform' do + before do + allow(AfterBlockDomainFromAccountService).to receive(:new).and_return(service) + end + + let(:account) { Fabricate(:account) } + let(:domain) { 'host.example' } + + it 'sends the account and domain to the service' do + worker.perform(account.id, domain) + + expect(service).to have_received(:call).with(account, domain) + end + + it 'returns true for non-existent record' do + result = worker.perform(123_123_123, domain) + + expect(result).to be(true) + end + end +end diff --git a/spec/workers/backup_worker_spec.rb b/spec/workers/backup_worker_spec.rb new file mode 100644 index 000000000..1a169513e --- /dev/null +++ b/spec/workers/backup_worker_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe BackupWorker do + let(:worker) { described_class.new } + let(:service) { instance_double(BackupService, call: true) } + + describe '#perform' do + before do + allow(BackupService).to receive(:new).and_return(service) + end + + let(:backup) { Fabricate(:backup) } + let!(:other_backup) { Fabricate(:backup, user: backup.user) } + + it 'sends the backup to the service and removes other backups' do + expect do + worker.perform(backup.id) + end.to change(UserMailer.deliveries, :size).by(1) + + expect(service).to have_received(:call).with(backup) + expect { other_backup.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + context 'when sidekiq retries are exhausted' do + it 'destroys the backup' do + described_class.within_sidekiq_retries_exhausted_block({ 'args' => [backup.id] }) do + worker.perform(backup.id) + end + + expect { backup.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end +end diff --git a/spec/workers/delete_mute_worker_spec.rb b/spec/workers/delete_mute_worker_spec.rb new file mode 100644 index 000000000..1fc84491c --- /dev/null +++ b/spec/workers/delete_mute_worker_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe DeleteMuteWorker do + let(:worker) { described_class.new } + let(:service) { instance_double(UnmuteService, call: true) } + + describe '#perform' do + before do + allow(UnmuteService).to receive(:new).and_return(service) + end + + context 'with an expired mute' do + let(:mute) { Fabricate(:mute, expires_at: 1.day.ago) } + + it 'sends the mute to the service' do + worker.perform(mute.id) + + expect(service).to have_received(:call).with(mute.account, mute.target_account) + end + end + + context 'with an unexpired mute' do + let(:mute) { Fabricate(:mute, expires_at: 1.day.from_now) } + + it 'does not send the mute to the service' do + worker.perform(mute.id) + + expect(service).to_not have_received(:call) + end + end + + context 'with a non-existent mute' do + it 'does not send the mute to the service' do + worker.perform(123_123_123) + + expect(service).to_not have_received(:call) + end + end + end +end diff --git a/spec/workers/feed_insert_worker_spec.rb b/spec/workers/feed_insert_worker_spec.rb index 97c73c599..e9484879f 100644 --- a/spec/workers/feed_insert_worker_spec.rb +++ b/spec/workers/feed_insert_worker_spec.rb @@ -8,6 +8,7 @@ describe FeedInsertWorker do describe 'perform' do let(:follower) { Fabricate(:account) } let(:status) { Fabricate(:status) } + let(:list) { Fabricate(:list) } context 'when there are no records' do it 'skips push with missing status' do @@ -42,11 +43,29 @@ describe FeedInsertWorker do it 'pushes the status onto the home timeline without filter' do instance = instance_double(FeedManager, push_to_home: nil, filter?: false) allow(FeedManager).to receive(:instance).and_return(instance) - result = subject.perform(status.id, follower.id) + result = subject.perform(status.id, follower.id, :home) expect(result).to be_nil expect(instance).to have_received(:push_to_home).with(follower, status, update: nil) end + + it 'pushes the status onto the tags timeline without filter' do + instance = instance_double(FeedManager, push_to_home: nil, filter?: false) + allow(FeedManager).to receive(:instance).and_return(instance) + result = subject.perform(status.id, follower.id, :tags) + + expect(result).to be_nil + expect(instance).to have_received(:push_to_home).with(follower, status, update: nil) + end + + it 'pushes the status onto the list timeline without filter' do + instance = instance_double(FeedManager, push_to_list: nil, filter?: false) + allow(FeedManager).to receive(:instance).and_return(instance) + result = subject.perform(status.id, list.id, :list) + + expect(result).to be_nil + expect(instance).to have_received(:push_to_list).with(list, status, update: nil) + end end end end diff --git a/spec/workers/import_worker_spec.rb b/spec/workers/import_worker_spec.rb new file mode 100644 index 000000000..4095a5d35 --- /dev/null +++ b/spec/workers/import_worker_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ImportWorker do + let(:worker) { described_class.new } + let(:service) { instance_double(ImportService, call: true) } + + describe '#perform' do + before do + allow(ImportService).to receive(:new).and_return(service) + end + + let(:import) { Fabricate(:import) } + + it 'sends the import to the service' do + worker.perform(import.id) + + expect(service).to have_received(:call).with(import) + expect { import.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end +end diff --git a/spec/workers/post_process_media_worker_spec.rb b/spec/workers/post_process_media_worker_spec.rb index 33072704b..828da5244 100644 --- a/spec/workers/post_process_media_worker_spec.rb +++ b/spec/workers/post_process_media_worker_spec.rb @@ -2,12 +2,38 @@ require 'rails_helper' -describe PostProcessMediaWorker do +describe PostProcessMediaWorker, :paperclip_processing do let(:worker) { described_class.new } - describe 'perform' do - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error + describe '#perform' do + let(:media_attachment) { Fabricate(:media_attachment) } + + it 'reprocesses and updates the media attachment' do + worker.perform(media_attachment.id) + + expect(media_attachment.processing).to eq('complete') + end + + it 'returns true for non-existent record' do + result = worker.perform(123_123_123) + + expect(result).to be(true) + end + + context 'when sidekiq retries are exhausted' do + it 'sets state to failed' do + described_class.within_sidekiq_retries_exhausted_block({ 'args' => [media_attachment.id] }) do + worker.perform(media_attachment.id) + end + + expect(media_attachment.reload.processing).to eq('failed') + end + + it 'returns true for non-existent record' do + described_class.within_sidekiq_retries_exhausted_block({ 'args' => [123_123_123] }) do + expect(worker.perform(123_123_123)).to be(true) + end + end end end end diff --git a/spec/workers/publish_announcement_reaction_worker_spec.rb b/spec/workers/publish_announcement_reaction_worker_spec.rb new file mode 100644 index 000000000..91668b5ad --- /dev/null +++ b/spec/workers/publish_announcement_reaction_worker_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe PublishAnnouncementReactionWorker do + let(:worker) { described_class.new } + + describe '#perform' do + before { Fabricate(:account, user: Fabricate(:user, current_sign_in_at: 1.hour.ago)) } + + let(:announcement) { Fabricate(:announcement) } + let(:name) { 'name value' } + + it 'sends the announcement and name to the service when subscribed' do + allow(redis).to receive(:exists?).and_return(true) + allow(redis).to receive(:publish) + + worker.perform(announcement.id, name) + + expect(redis).to have_received(:publish) + end + + it 'does not send the announcement and name to the service when not subscribed' do + allow(redis).to receive(:exists?).and_return(false) + allow(redis).to receive(:publish) + + worker.perform(announcement.id, name) + + expect(redis).to_not have_received(:publish) + end + + it 'returns true for non-existent record' do + result = worker.perform(123_123_123, name) + + expect(result).to be(true) + end + end +end diff --git a/spec/workers/removal_worker_spec.rb b/spec/workers/removal_worker_spec.rb new file mode 100644 index 000000000..5071e882b --- /dev/null +++ b/spec/workers/removal_worker_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe RemovalWorker do + let(:worker) { described_class.new } + let(:service) { instance_double(RemoveStatusService, call: true) } + + describe '#perform' do + before do + allow(RemoveStatusService).to receive(:new).and_return(service) + end + + let(:status) { Fabricate(:status) } + + it 'sends the status to the service' do + worker.perform(status.id) + + expect(service).to have_received(:call).with(status) + end + + it 'returns true for non-existent record' do + result = worker.perform(123_123_123) + + expect(result).to be(true) + end + end +end diff --git a/spec/workers/scheduler/self_destruct_scheduler_spec.rb b/spec/workers/scheduler/self_destruct_scheduler_spec.rb new file mode 100644 index 000000000..2bf578357 --- /dev/null +++ b/spec/workers/scheduler/self_destruct_scheduler_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Scheduler::SelfDestructScheduler do + let(:worker) { described_class.new } + + describe '#perform' do + let!(:account) { Fabricate(:account, domain: nil, suspended_at: nil) } + + context 'when not in self destruct mode' do + before do + allow(SelfDestructHelper).to receive(:self_destruct?).and_return(false) + end + + it 'returns without processing' do + worker.perform + + expect(account.reload.suspended_at).to be_nil + end + end + + context 'when in self-destruct mode' do + before do + allow(SelfDestructHelper).to receive(:self_destruct?).and_return(true) + end + + context 'when sidekiq is overwhelmed' do + before do + stats = instance_double(Sidekiq::Stats, enqueued: described_class::MAX_ENQUEUED**2) + allow(Sidekiq::Stats).to receive(:new).and_return(stats) + end + + it 'returns without processing' do + worker.perform + + expect(account.reload.suspended_at).to be_nil + end + end + + context 'when sidekiq is operational' do + it 'suspends local non-suspended accounts' do + worker.perform + + expect(account.reload.suspended_at).to_not be_nil + end + + it 'suspends local suspended accounts marked for deletion' do + account.update(suspended_at: 10.days.ago) + deletion_request = Fabricate(:account_deletion_request, account: account) + + worker.perform + + expect(account.reload.suspended_at).to be > 1.day.ago + expect { deletion_request.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end + end +end diff --git a/spec/workers/webhooks/delivery_worker_spec.rb b/spec/workers/webhooks/delivery_worker_spec.rb index daf8a3e28..6a5483d1d 100644 --- a/spec/workers/webhooks/delivery_worker_spec.rb +++ b/spec/workers/webhooks/delivery_worker_spec.rb @@ -5,9 +5,21 @@ require 'rails_helper' describe Webhooks::DeliveryWorker do let(:worker) { described_class.new } - describe 'perform' do - it 'runs without error' do - expect { worker.perform(nil, nil) }.to_not raise_error + describe '#perform' do + let(:webhook) { Fabricate(:webhook) } + + it 'reprocesses and updates the webhook' do + stub_request(:post, webhook.url).to_return(status: 200, body: '') + + worker.perform(webhook.id, 'body') + + expect(a_request(:post, webhook.url)).to have_been_made.at_least_once + end + + it 'returns true for non-existent record' do + result = worker.perform(123_123_123, '') + + expect(result).to be(true) end end end From cb1a4a8713499a0ca7d8e53ce5cfd32939247f0c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 16 Nov 2023 09:37:52 -0500 Subject: [PATCH 058/255] Reduce expectations for `RSpec/MultipleExpectations` cop in `spec/presenters` specs (#27881) --- .../account_relationships_presenter_spec.rb | 14 +++-- .../familiar_followers_presenter_spec.rb | 27 ++++++--- .../status_relationships_presenter_spec.rb | 60 +++++++++++++------ 3 files changed, 69 insertions(+), 32 deletions(-) diff --git a/spec/presenters/account_relationships_presenter_spec.rb b/spec/presenters/account_relationships_presenter_spec.rb index 5c2ba54e0..5b05ac800 100644 --- a/spec/presenters/account_relationships_presenter_spec.rb +++ b/spec/presenters/account_relationships_presenter_spec.rb @@ -23,12 +23,14 @@ RSpec.describe AccountRelationshipsPresenter do let(:options) { {} } it 'sets default maps' do - expect(presenter.following).to eq default_map - expect(presenter.followed_by).to eq default_map - expect(presenter.blocking).to eq default_map - expect(presenter.muting).to eq default_map - expect(presenter.requested).to eq default_map - expect(presenter.domain_blocking).to eq default_map + expect(presenter).to have_attributes( + following: default_map, + followed_by: default_map, + blocking: default_map, + muting: default_map, + requested: default_map, + domain_blocking: default_map + ) end end diff --git a/spec/presenters/familiar_followers_presenter_spec.rb b/spec/presenters/familiar_followers_presenter_spec.rb index c21ffd36e..853babb84 100644 --- a/spec/presenters/familiar_followers_presenter_spec.rb +++ b/spec/presenters/familiar_followers_presenter_spec.rb @@ -22,9 +22,12 @@ RSpec.describe FamiliarFollowersPresenter do it 'returns followers you follow' do result = subject.accounts.first - expect(result).to_not be_nil - expect(result.id).to eq requested_accounts.first.id - expect(result.accounts).to contain_exactly(familiar_follower) + expect(result) + .to be_present + .and have_attributes( + id: requested_accounts.first.id, + accounts: contain_exactly(familiar_follower) + ) end context 'when requested account hides followers' do @@ -35,9 +38,12 @@ RSpec.describe FamiliarFollowersPresenter do it 'does not return followers you follow' do result = subject.accounts.first - expect(result).to_not be_nil - expect(result.id).to eq requested_accounts.first.id - expect(result.accounts).to be_empty + expect(result) + .to be_present + .and have_attributes( + id: requested_accounts.first.id, + accounts: be_empty + ) end end @@ -49,9 +55,12 @@ RSpec.describe FamiliarFollowersPresenter do it 'does not return followers you follow' do result = subject.accounts.first - expect(result).to_not be_nil - expect(result.id).to eq requested_accounts.first.id - expect(result.accounts).to be_empty + expect(result) + .to be_present + .and have_attributes( + id: requested_accounts.first.id, + accounts: be_empty + ) end end end diff --git a/spec/presenters/status_relationships_presenter_spec.rb b/spec/presenters/status_relationships_presenter_spec.rb index 7746c8cd7..af6a93b82 100644 --- a/spec/presenters/status_relationships_presenter_spec.rb +++ b/spec/presenters/status_relationships_presenter_spec.rb @@ -22,11 +22,13 @@ RSpec.describe StatusRelationshipsPresenter do let(:options) { {} } it 'sets default maps' do - expect(presenter.reblogs_map).to eq default_map - expect(presenter.favourites_map).to eq default_map - expect(presenter.bookmarks_map).to eq default_map - expect(presenter.mutes_map).to eq default_map - expect(presenter.pins_map).to eq default_map + expect(presenter).to have_attributes( + reblogs_map: eq(default_map), + favourites_map: eq(default_map), + bookmarks_map: eq(default_map), + mutes_map: eq(default_map), + pins_map: eq(default_map) + ) end end @@ -80,18 +82,30 @@ RSpec.describe StatusRelationshipsPresenter do it 'sets @filters_map to filter top-level status' do matched_filters = presenter.filters_map[statuses[0].id] - expect(matched_filters.size).to eq 1 - expect(matched_filters[0].filter.title).to eq 'filter1' - expect(matched_filters[0].keyword_matches).to eq ['banned'] + expect(matched_filters) + .to be_an(Array) + .and have_attributes(size: 1) + .and contain_exactly( + have_attributes( + filter: have_attributes(title: 'filter1'), + keyword_matches: contain_exactly('banned') + ) + ) end it 'sets @filters_map to filter reblogged status' do matched_filters = presenter.filters_map[statuses[1].reblog_of_id] - expect(matched_filters.size).to eq 1 - expect(matched_filters[0].filter.title).to eq 'filter1' - expect(matched_filters[0].keyword_matches).to eq ['irrelevant'] + expect(matched_filters) + .to be_an(Array) + .and have_attributes(size: 1) + .and contain_exactly( + have_attributes( + filter: have_attributes(title: 'filter1'), + keyword_matches: contain_exactly('irrelevant') + ) + ) end end @@ -107,18 +121,30 @@ RSpec.describe StatusRelationshipsPresenter do it 'sets @filters_map to filter top-level status' do matched_filters = presenter.filters_map[statuses[0].id] - expect(matched_filters.size).to eq 1 - expect(matched_filters[0].filter.title).to eq 'filter1' - expect(matched_filters[0].status_matches).to eq [statuses[0].id] + expect(matched_filters) + .to be_an(Array) + .and have_attributes(size: 1) + .and contain_exactly( + have_attributes( + filter: have_attributes(title: 'filter1'), + status_matches: contain_exactly(statuses.first.id) + ) + ) end it 'sets @filters_map to filter reblogged status' do matched_filters = presenter.filters_map[statuses[1].reblog_of_id] - expect(matched_filters.size).to eq 1 - expect(matched_filters[0].filter.title).to eq 'filter1' - expect(matched_filters[0].status_matches).to eq [statuses[1].reblog_of_id] + expect(matched_filters) + .to be_an(Array) + .and have_attributes(size: 1) + .and contain_exactly( + have_attributes( + filter: have_attributes(title: 'filter1'), + status_matches: contain_exactly(statuses.second.reblog_of_id) + ) + ) end end end From 94178e2f68db9d23b1be1f3b39489564fcb9d50e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 09:56:23 +0100 Subject: [PATCH 059/255] Update dependency react-redux-loading-bar to v5.0.5 (#27916) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index 32c2546e7..b55bbde3e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13777,17 +13777,17 @@ __metadata: linkType: hard "react-redux-loading-bar@npm:^5.0.4": - version: 5.0.4 - resolution: "react-redux-loading-bar@npm:5.0.4" + version: 5.0.5 + resolution: "react-redux-loading-bar@npm:5.0.5" dependencies: prop-types: "npm:^15.7.2" react-lifecycles-compat: "npm:^3.0.4" peerDependencies: react: ^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-redux: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - redux: ^3.0.0 || ^4.0.0 - checksum: 11eea2ef6dfae232e278eceb83d07f9f57a2ece3ef23ce888dccf24964b669c9ee83a6db12b1f3c757b5b3410f7a7ccda96a4b4216c4ad9b42bf831ccea7a4a2 + react-redux: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + redux: ^3.0.0 || ^4.0.0 || ^5.0.0 + checksum: 0dbac046c5b8b6bd209ccfc25ccc55dc9158cd737b42b68fd1900dfe46a59c9c7e2b0082d8901b749e7cf2d7e23074590aae74f350a814f205105f47895a6214 languageName: node linkType: hard From 6c2e78f1b11874583ae9e6988cf6d2a2eb1e1b71 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 09:56:39 +0100 Subject: [PATCH 060/255] Update dependency @material-symbols/svg-600 to v0.14.1 (#27907) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index b55bbde3e..864ebfc87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2550,9 +2550,9 @@ __metadata: linkType: soft "@material-symbols/svg-600@npm:^0.14.0": - version: 0.14.0 - resolution: "@material-symbols/svg-600@npm:0.14.0" - checksum: e6547a9a0b2072f4109f2e4e0863367ea2507efce740c427a8544100db02ffff52f33608aac1a355f4977e2c0b2ce6cdd6bfee9177bb13cee0b28418f948b5a5 + version: 0.14.1 + resolution: "@material-symbols/svg-600@npm:0.14.1" + checksum: fb5252285bbeccc45a4b131e8b165470b5b57e146bc7ea586eb82e580037d1218f6dad5fee4e6822c357041ff547f34c9c7432cce0a811b14f7e41d8ae23009b languageName: node linkType: hard From 1526e54ac6f08431c8c833f20b4be8882355967c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 17 Nov 2023 04:03:46 -0500 Subject: [PATCH 061/255] Add spec coverage for `workers/redownload_*` worker classes (#27892) --- spec/workers/redownload_avatar_worker_spec.rb | 45 +++++++++++++++++-- spec/workers/redownload_header_worker_spec.rb | 45 +++++++++++++++++-- spec/workers/redownload_media_worker_spec.rb | 37 +++++++++++++++ 3 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 spec/workers/redownload_media_worker_spec.rb diff --git a/spec/workers/redownload_avatar_worker_spec.rb b/spec/workers/redownload_avatar_worker_spec.rb index b44ae9f03..4ab368e12 100644 --- a/spec/workers/redownload_avatar_worker_spec.rb +++ b/spec/workers/redownload_avatar_worker_spec.rb @@ -5,9 +5,48 @@ require 'rails_helper' describe RedownloadAvatarWorker do let(:worker) { described_class.new } - describe 'perform' do - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error + describe '#perform' do + it 'returns nil for non-existent record' do + result = worker.perform(123_123_123) + + expect(result).to be_nil + end + + it 'returns nil for suspended account' do + account = Fabricate(:account, suspended_at: 10.days.ago) + + expect(worker.perform(account.id)).to be_nil + end + + it 'returns nil with a domain block' do + account = Fabricate(:account, domain: 'host.example') + Fabricate(:domain_block, domain: account.domain, reject_media: true) + + expect(worker.perform(account.id)).to be_nil + end + + it 'returns nil without an avatar remote url' do + account = Fabricate(:account, avatar_remote_url: '') + + expect(worker.perform(account.id)).to be_nil + end + + it 'returns nil when avatar file name is present' do + stub_request(:get, 'https://example.host/file').to_return request_fixture('avatar.txt') + account = Fabricate(:account, avatar_remote_url: 'https://example.host/file', avatar_file_name: 'test.jpg') + + expect(worker.perform(account.id)).to be_nil + end + + it 'reprocesses a remote avatar' do + stub_request(:get, 'https://example.host/file').to_return request_fixture('avatar.txt') + account = Fabricate(:account, avatar_remote_url: 'https://example.host/file') + account.update_column(:avatar_file_name, nil) # rubocop:disable Rails/SkipsModelValidations + + result = worker.perform(account.id) + + expect(result).to be(true) + expect(account.reload.avatar_file_name).to_not be_nil end end end diff --git a/spec/workers/redownload_header_worker_spec.rb b/spec/workers/redownload_header_worker_spec.rb index 767ae7a5a..3b6f497bb 100644 --- a/spec/workers/redownload_header_worker_spec.rb +++ b/spec/workers/redownload_header_worker_spec.rb @@ -5,9 +5,48 @@ require 'rails_helper' describe RedownloadHeaderWorker do let(:worker) { described_class.new } - describe 'perform' do - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error + describe '#perform' do + it 'returns nil for non-existent record' do + result = worker.perform(123_123_123) + + expect(result).to be_nil + end + + it 'returns nil for suspended account' do + account = Fabricate(:account, suspended_at: 10.days.ago) + + expect(worker.perform(account.id)).to be_nil + end + + it 'returns nil with a domain block' do + account = Fabricate(:account, domain: 'host.example') + Fabricate(:domain_block, domain: account.domain, reject_media: true) + + expect(worker.perform(account.id)).to be_nil + end + + it 'returns nil without an header remote url' do + account = Fabricate(:account, header_remote_url: '') + + expect(worker.perform(account.id)).to be_nil + end + + it 'returns nil when header file name is present' do + stub_request(:get, 'https://example.host/file').to_return request_fixture('avatar.txt') + account = Fabricate(:account, header_remote_url: 'https://example.host/file', header_file_name: 'test.jpg') + + expect(worker.perform(account.id)).to be_nil + end + + it 'reprocesses a remote header' do + stub_request(:get, 'https://example.host/file').to_return request_fixture('avatar.txt') + account = Fabricate(:account, header_remote_url: 'https://example.host/file') + account.update_column(:header_file_name, nil) # rubocop:disable Rails/SkipsModelValidations + + result = worker.perform(account.id) + + expect(result).to be(true) + expect(account.reload.header_file_name).to_not be_nil end end end diff --git a/spec/workers/redownload_media_worker_spec.rb b/spec/workers/redownload_media_worker_spec.rb new file mode 100644 index 000000000..cd561d148 --- /dev/null +++ b/spec/workers/redownload_media_worker_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe RedownloadMediaWorker do + let(:worker) { described_class.new } + + describe '#perform' do + it 'returns nil for non-existent record' do + result = worker.perform(123_123_123) + + expect(result).to be_nil + end + + it 'returns nil without a remote_url' do + media_attachment = Fabricate(:media_attachment, remote_url: '') + + result = worker.perform(media_attachment.id) + + expect(result).to be_nil + end + + context 'with a valid remote url' do + let(:url) { 'https://example.host/file.txt' } + + before { stub_request(:get, url).to_return(status: 200) } + + it 'processes downloads for valid record' do + media_attachment = Fabricate(:media_attachment, remote_url: url) + + worker.perform(media_attachment.id) + + expect(a_request(:get, url)).to have_been_made + end + end + end +end From 9c68741f464b7cffa8b70a6be38cd333a795672b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 10:16:12 +0100 Subject: [PATCH 062/255] New Crowdin Translations (automated) (#27914) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/be.json | 2 ++ app/javascript/mastodon/locales/cs.json | 2 ++ app/javascript/mastodon/locales/cy.json | 7 ++++++ app/javascript/mastodon/locales/da.json | 2 ++ app/javascript/mastodon/locales/de.json | 2 ++ app/javascript/mastodon/locales/es-AR.json | 2 ++ app/javascript/mastodon/locales/es-MX.json | 2 ++ app/javascript/mastodon/locales/es.json | 12 ++++++++++ app/javascript/mastodon/locales/eu.json | 2 ++ app/javascript/mastodon/locales/fi.json | 2 ++ app/javascript/mastodon/locales/fr-QC.json | 4 ++++ app/javascript/mastodon/locales/fr.json | 6 ++++- app/javascript/mastodon/locales/gl.json | 12 ++++++++++ app/javascript/mastodon/locales/he.json | 2 ++ app/javascript/mastodon/locales/hu.json | 14 +++++++----- app/javascript/mastodon/locales/is.json | 2 ++ app/javascript/mastodon/locales/it.json | 2 ++ app/javascript/mastodon/locales/ko.json | 2 ++ app/javascript/mastodon/locales/lt.json | 26 +++++++++++++++++++--- app/javascript/mastodon/locales/nl.json | 2 ++ app/javascript/mastodon/locales/nn.json | 24 +++++++++++--------- app/javascript/mastodon/locales/no.json | 2 ++ app/javascript/mastodon/locales/pl.json | 2 ++ app/javascript/mastodon/locales/pt-PT.json | 2 ++ app/javascript/mastodon/locales/sq.json | 2 ++ app/javascript/mastodon/locales/sr.json | 3 +++ app/javascript/mastodon/locales/sv.json | 2 ++ app/javascript/mastodon/locales/th.json | 10 +++++---- app/javascript/mastodon/locales/uk.json | 2 ++ app/javascript/mastodon/locales/zh-CN.json | 2 ++ app/javascript/mastodon/locales/zh-HK.json | 2 ++ app/javascript/mastodon/locales/zh-TW.json | 2 ++ config/locales/es.yml | 1 + config/locales/eu.yml | 1 + config/locales/gl.yml | 3 ++- config/locales/hu.yml | 2 +- config/locales/ko.yml | 2 +- config/locales/nn.yml | 26 +++++++++++----------- config/locales/no.yml | 2 +- config/locales/sr.yml | 1 + config/locales/th.yml | 4 ++-- config/locales/tr.yml | 1 + config/locales/zh-CN.yml | 1 + 43 files changed, 162 insertions(+), 44 deletions(-) diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 4f5b247b6..59b1ca50b 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -21,6 +21,7 @@ "account.blocked": "Заблакіраваны", "account.browse_more_on_origin_server": "Глядзіце больш у арыгінальным профілі", "account.cancel_follow_request": "Скасаваць запыт на падпіску", + "account.copy": "Скапіраваць спасылку на профіль", "account.direct": "Згадаць асабіста @{name}", "account.disable_notifications": "Не паведамляць мне пра публікацыі @{name}", "account.domain_blocked": "Дамен заблакаваны", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Адзначыць прачытаным", "conversation.open": "Прагледзець размову", "conversation.with": "З {names}", + "copy_icon_button.copied": "Скапіявана ў буфер абмену", "copypaste.copied": "Скапіравана", "copypaste.copy_to_clipboard": "Капіраваць у буфер абмену", "directory.federated": "З вядомага федэсвету", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index 20ef43733..16bf5020c 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -21,6 +21,7 @@ "account.blocked": "Blokovaný", "account.browse_more_on_origin_server": "Více na původním profilu", "account.cancel_follow_request": "Zrušit žádost o sledování", + "account.copy": "Kopírovat odkaz na profil", "account.direct": "Soukromě zmínit @{name}", "account.disable_notifications": "Přestat mě upozorňovat, když @{name} zveřejní příspěvek", "account.domain_blocked": "Doména blokována", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Označit jako přečtené", "conversation.open": "Zobrazit konverzaci", "conversation.with": "S {names}", + "copy_icon_button.copied": "Zkopírováno do schránky", "copypaste.copied": "Zkopírováno", "copypaste.copy_to_clipboard": "Zkopírovat do schránky", "directory.federated": "Ze známého fedivesmíru", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index dcd5406d0..11d4de440 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -191,6 +191,7 @@ "conversation.mark_as_read": "Nodi fel wedi'i ddarllen", "conversation.open": "Gweld sgwrs", "conversation.with": "Gyda {names}", + "copy_icon_button.copied": "Copïwyd i'r clipfwrdd", "copypaste.copied": "Wedi ei gopïo", "copypaste.copy_to_clipboard": "Copïo i'r clipfwrdd", "directory.federated": "O'r ffedysawd cyfan", @@ -390,6 +391,7 @@ "lists.search": "Chwilio ymysg pobl rydych yn eu dilyn", "lists.subheading": "Eich rhestrau", "load_pending": "{count, plural, one {# eitem newydd} other {# eitem newydd}}", + "loading_indicator.label": "Yn llwytho…", "media_gallery.toggle_visible": "{number, plural, one {Cuddio delwedd} other {Cuddio delwedd}}", "moved_to_account_banner.text": "Ar hyn y bryd, mae eich cyfrif {disabledAccount} wedi ei analluogi am i chi symud i {movedToAccount}.", "mute_modal.duration": "Hyd", @@ -478,6 +480,11 @@ "onboarding.follows.empty": "Yn anffodus, nid oes modd dangos unrhyw ganlyniadau ar hyn o bryd. Gallwch geisio defnyddio chwilio neu bori'r dudalen archwilio i ddod o hyd i bobl i'w dilyn, neu ceisio eto yn nes ymlaen.", "onboarding.follows.lead": "Rydych chi'n curadu eich ffrwd gartref eich hun. Po fwyaf o bobl y byddwch chi'n eu dilyn, y mwyaf egnïol a diddorol fydd hi. Gall y proffiliau hyn fod yn fan cychwyn da - gallwch chi bob amser eu dad-ddilyn yn nes ymlaen:", "onboarding.follows.title": "Yn boblogaidd ar Mastodon", + "onboarding.profile.display_name_hint": "Eich enw llawn neu'ch enw hwyl…", + "onboarding.profile.note": "Bywgraffiad", + "onboarding.profile.note_hint": "Gallwch @grybwyll pobl eraill neu #hashnodau…", + "onboarding.profile.save_and_continue": "Cadw a pharhau", + "onboarding.profile.title": "Gosodiad proffil", "onboarding.share.lead": "Cofiwch ddweud wrth bobl sut y gallan nhw ddod o hyd i chi ar Mastodon!", "onboarding.share.message": "Fi yw {username} ar #Mastodon! Dewch i'm dilyn i yn {url}", "onboarding.share.next_steps": "Camau nesaf posib:", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index 33eda6f43..bde12a7ae 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -21,6 +21,7 @@ "account.blocked": "Blokeret", "account.browse_more_on_origin_server": "Se mere på den oprindelige profil", "account.cancel_follow_request": "Annullér anmodning om at følge", + "account.copy": "Kopiér link til profil", "account.direct": "Privat omtale @{name}", "account.disable_notifications": "Advisér mig ikke længere, når @{name} poster", "account.domain_blocked": "Domæne blokeret", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Markér som læst", "conversation.open": "Vis samtale", "conversation.with": "Med {names}", + "copy_icon_button.copied": "Kopieret til udklipsholderen", "copypaste.copied": "Kopieret", "copypaste.copy_to_clipboard": "Kopiér til udklipsholder", "directory.federated": "Fra kendt fedivers", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 5c1ccf46d..10fd9b4c5 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -21,6 +21,7 @@ "account.blocked": "Blockiert", "account.browse_more_on_origin_server": "Mehr auf dem Originalprofil durchsuchen", "account.cancel_follow_request": "Folgeanfrage zurückziehen", + "account.copy": "Link zum Profil kopieren", "account.direct": "@{name} privat erwähnen", "account.disable_notifications": "Höre auf mich zu benachrichtigen wenn @{name} etwas postet", "account.domain_blocked": "Domain versteckt", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Als gelesen markieren", "conversation.open": "Unterhaltung anzeigen", "conversation.with": "Mit {names}", + "copy_icon_button.copied": "In die Zwischenablage kopiert", "copypaste.copied": "Kopiert", "copypaste.copy_to_clipboard": "In die Zwischenablage kopieren", "directory.federated": "Aus bekanntem Fediverse", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 680336369..3c99334c3 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -21,6 +21,7 @@ "account.blocked": "Bloqueado", "account.browse_more_on_origin_server": "Explorar más en el perfil original", "account.cancel_follow_request": "Dejar de seguir", + "account.copy": "Copiar enlace al perfil", "account.direct": "Mención privada a @{name}", "account.disable_notifications": "Dejar de notificarme cuando @{name} envíe mensajes", "account.domain_blocked": "Dominio bloqueado", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marcar como leída", "conversation.open": "Ver conversación", "conversation.with": "Con {names}", + "copy_icon_button.copied": "Copiado en el portapapeles", "copypaste.copied": "Copiado", "copypaste.copy_to_clipboard": "Copiar al portapapeles", "directory.federated": "Desde fediverso conocido", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index aa8a21edb..70c4efcad 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -21,6 +21,7 @@ "account.blocked": "Bloqueado", "account.browse_more_on_origin_server": "Ver más en el perfil original", "account.cancel_follow_request": "Retirar solicitud de seguimiento", + "account.copy": "Copiar enlace al perfil", "account.direct": "Mención privada @{name}", "account.disable_notifications": "Dejar de notificarme cuando @{name} publique algo", "account.domain_blocked": "Dominio oculto", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marcar como leído", "conversation.open": "Ver conversación", "conversation.with": "Con {names}", + "copy_icon_button.copied": "Copiado al portapapeles", "copypaste.copied": "Copiado", "copypaste.copy_to_clipboard": "Copiar al portapapeles", "directory.federated": "Desde el fediverso conocido", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 5d1aa004b..3c0d8cd57 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -21,6 +21,7 @@ "account.blocked": "Bloqueado", "account.browse_more_on_origin_server": "Ver más en el perfil original", "account.cancel_follow_request": "Retirar solicitud de seguimiento", + "account.copy": "Copiar enlace al perfil", "account.direct": "Mención privada a @{name}", "account.disable_notifications": "Dejar de notificarme cuando @{name} publique algo", "account.domain_blocked": "Dominio bloqueado", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marcar como leído", "conversation.open": "Ver conversación", "conversation.with": "Con {names}", + "copy_icon_button.copied": "Copiado al portapapeles", "copypaste.copied": "Copiado", "copypaste.copy_to_clipboard": "Copiar al portapapeles", "directory.federated": "Desde el fediverso conocido", @@ -479,7 +481,17 @@ "onboarding.follows.empty": "Desafortunadamente, no se pueden mostrar resultados en este momento. Puedes intentar usar la búsqueda o navegar por la página de exploración para encontrar personas a las que seguir, o inténtalo de nuevo más tarde.", "onboarding.follows.lead": "Tu línea de inicio es la forma principal de experimentar Mastodon. Cuanta más personas sigas, más activa e interesante será. Para empezar, aquí hay algunas sugerencias:", "onboarding.follows.title": "Personaliza tu línea de inicio", + "onboarding.profile.discoverable": "Destacar perfil y publicaciones en algoritmos de descubrimiento", "onboarding.profile.display_name": "Nombre para mostrar", + "onboarding.profile.display_name_hint": "Tu nombre completo o tu apodo…", + "onboarding.profile.indexable": "Incluir publicaciones públicas en los resultados de búsqueda", + "onboarding.profile.lead": "Siempre puedes completar esto más tarde en los ajustes, donde hay aún más opciones de personalización disponibles.", + "onboarding.profile.note": "Biografía", + "onboarding.profile.note_hint": "Puedes @mencionar a otras personas o #etiquetas…", + "onboarding.profile.save_and_continue": "Guardar y continuar", + "onboarding.profile.title": "Configuración del perfil", + "onboarding.profile.upload_avatar": "Subir foto de perfil", + "onboarding.profile.upload_header": "Subir encabezado de perfil", "onboarding.share.lead": "¡Cuéntale a otras personas cómo te pueden encontrar en Mastodon!", "onboarding.share.message": "¡Soy {username} en #Mastodon! Ven a seguirme en {url}", "onboarding.share.next_steps": "Posibles siguientes pasos:", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index 88f70cffb..5bca1cfef 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -21,6 +21,7 @@ "account.blocked": "Blokeatuta", "account.browse_more_on_origin_server": "Arakatu gehiago jatorrizko profilean", "account.cancel_follow_request": "Baztertu jarraitzeko eskaera", + "account.copy": "Kopiatu profilerako esteka", "account.direct": "Aipatu pribatuki @{name}", "account.disable_notifications": "Utzi jakinarazteari @{name} erabiltzailearen bidalketetan", "account.domain_blocked": "Ezkutatutako domeinua", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Markatu irakurrita bezala", "conversation.open": "Ikusi elkarrizketa", "conversation.with": "Hauekin: {names}", + "copy_icon_button.copied": "Arbelera kopiatu da", "copypaste.copied": "Kopiatuta", "copypaste.copy_to_clipboard": "Kopiatu arbelera", "directory.federated": "Fedibertso ezagunekoak", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 849a7f463..344e37c97 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -21,6 +21,7 @@ "account.blocked": "Estetty", "account.browse_more_on_origin_server": "Selaile lisää alkuperäisellä palvelimella", "account.cancel_follow_request": "Peruuta seurantapyyntö", + "account.copy": "Kopioi profiilin linkki", "account.direct": "Mainitse @{name} yksityisesti", "account.disable_notifications": "Lopeta ilmoittamasta minulle, kun @{name} julkaisee", "account.domain_blocked": "Verkkotunnus estetty", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Merkitse luetuksi", "conversation.open": "Näytä keskustelu", "conversation.with": "{names} kanssa", + "copy_icon_button.copied": "Kopioitu leikepöydälle", "copypaste.copied": "Kopioitu", "copypaste.copy_to_clipboard": "Kopioi leikepöydälle", "directory.federated": "Koko tunnettu fediversumi", diff --git a/app/javascript/mastodon/locales/fr-QC.json b/app/javascript/mastodon/locales/fr-QC.json index e858882f8..d85a6d428 100644 --- a/app/javascript/mastodon/locales/fr-QC.json +++ b/app/javascript/mastodon/locales/fr-QC.json @@ -390,6 +390,7 @@ "lists.search": "Rechercher parmi les gens que vous suivez", "lists.subheading": "Vos listes", "load_pending": "{count, plural, one {# nouvel élément} other {# nouveaux éléments}}", + "loading_indicator.label": "Chargement…", "media_gallery.toggle_visible": "{number, plural, one {Cacher l’image} other {Cacher les images}}", "moved_to_account_banner.text": "Votre compte {disabledAccount} est actuellement désactivé parce que vous avez déménagé sur {movedToAccount}.", "mute_modal.duration": "Durée", @@ -478,6 +479,9 @@ "onboarding.follows.empty": "Malheureusement, aucun résultat ne peut être affiché pour le moment. Vous pouvez essayer de rechercher ou de parcourir la page \"Explorer\" pour trouver des personnes à suivre, ou réessayer plus tard.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.discoverable": "Autoriser des algorithmes de découverte à mettre en avant votre profil et vos messages", + "onboarding.profile.save_and_continue": "Enregistrer et continuer", + "onboarding.profile.upload_avatar": "Importer une photo de profil", "onboarding.share.lead": "Faites savoir aux gens comment vous trouver sur Mastodon!", "onboarding.share.message": "Je suis {username} sur #Mastodon! Suivez-moi sur {url}", "onboarding.share.next_steps": "Étapes suivantes possibles:", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index a7bb4a12f..14e0e13ba 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -107,7 +107,7 @@ "closed_registrations_modal.preamble": "Mastodon est décentralisé : peu importe où vous créez votre compte, vous serez en mesure de suivre et d'interagir avec quiconque sur ce serveur. Vous pouvez même l'héberger !", "closed_registrations_modal.title": "Inscription sur Mastodon", "column.about": "À propos", - "column.blocks": "Comptes bloqués", + "column.blocks": "Utilisateurs bloqués", "column.bookmarks": "Marque-pages", "column.community": "Fil public local", "column.direct": "Mentions privées", @@ -390,6 +390,7 @@ "lists.search": "Rechercher parmi les gens que vous suivez", "lists.subheading": "Vos listes", "load_pending": "{count, plural, one {# nouvel élément} other {# nouveaux éléments}}", + "loading_indicator.label": "Chargement…", "media_gallery.toggle_visible": "{number, plural, one {Cacher l’image} other {Cacher les images}}", "moved_to_account_banner.text": "Votre compte {disabledAccount} est actuellement désactivé parce que vous l'avez déplacé à {movedToAccount}.", "mute_modal.duration": "Durée", @@ -478,6 +479,9 @@ "onboarding.follows.empty": "Malheureusement, aucun résultat ne peut être affiché pour le moment. Vous pouvez essayer d'utiliser la recherche ou parcourir la page de découverte pour trouver des personnes à suivre, ou réessayez plus tard.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Personnaliser votre flux principal", + "onboarding.profile.discoverable": "Autoriser des algorithmes de découverte à mettre en avant votre profil et vos messages", + "onboarding.profile.save_and_continue": "Enregistrer et continuer", + "onboarding.profile.upload_avatar": "Importer une photo de profil", "onboarding.share.lead": "Faites savoir aux gens comment ils peuvent vous trouver sur Mastodon!", "onboarding.share.message": "Je suis {username} sur #Mastodon ! Suivez-moi sur {url}", "onboarding.share.next_steps": "Étapes suivantes possibles :", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 7d2c6dab9..1f199bc45 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -390,6 +390,7 @@ "lists.search": "Procurar entre as persoas que segues", "lists.subheading": "As túas listaxes", "load_pending": "{count, plural, one {# novo elemento} other {# novos elementos}}", + "loading_indicator.label": "Estase a cargar…", "media_gallery.toggle_visible": "Agochar {number, plural, one {imaxe} other {imaxes}}", "moved_to_account_banner.text": "A túa conta {disabledAccount} está actualmente desactivada porque movéchela a {movedToAccount}.", "mute_modal.duration": "Duración", @@ -478,6 +479,17 @@ "onboarding.follows.empty": "Desgraciadamente agora mesmo non hai nada que mostrar. Podes intentalo coa busca ou na páxina descubrir para atopar persoas ás que seguir, ou intentalo máis tarde.", "onboarding.follows.lead": "Podes facer que a túa cronoloxía de inicio sexa como ti a queres. Canta máis xente sigas máis interesante será. Estes perfís poderían axudarche a comezar —sempre poderás deixar de seguilos despois!", "onboarding.follows.title": "Popular en Mastodon", + "onboarding.profile.discoverable": "Perfil destacado e publicacións nos algoritmos de descubrimento", + "onboarding.profile.display_name": "Nome público", + "onboarding.profile.display_name_hint": "O teu nome completo ou un nome divertido…", + "onboarding.profile.indexable": "Incluír publicacións públicas nos resultados das buscas", + "onboarding.profile.lead": "Sempre poderás incluír esta información mais tarde nos axustes, onde terás máis opcións dispoñibles.", + "onboarding.profile.note": "Acerca de ti", + "onboarding.profile.note_hint": "Podes @mencionar a outras persoas ou usar #cancelos…", + "onboarding.profile.save_and_continue": "Gardar e continuar", + "onboarding.profile.title": "Configuración do perfil", + "onboarding.profile.upload_avatar": "Subir imaxe do perfil", + "onboarding.profile.upload_header": "Subir cabeceira para o perfil", "onboarding.share.lead": "Fai que as persoas saiban como atoparte en Mastodon!", "onboarding.share.message": "Son {username} en #Mastodon! Ségueme en {url}", "onboarding.share.next_steps": "Seguintes pasos:", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 2e0009170..b6716f796 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -21,6 +21,7 @@ "account.blocked": "לחסום", "account.browse_more_on_origin_server": "ראה יותר בפרופיל המקורי", "account.cancel_follow_request": "משיכת בקשת מעקב", + "account.copy": "להעתיק קישור לפרופיל", "account.direct": "הודעה פרטית אל @{name}", "account.disable_notifications": "הפסק לשלוח לי התראות כש@{name} מפרסמים", "account.domain_blocked": "הדומיין חסום", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "סמן כנקרא", "conversation.open": "צפו בשיחה", "conversation.with": "עם {names}", + "copy_icon_button.copied": "הועתק ללוח", "copypaste.copied": "הועתק", "copypaste.copy_to_clipboard": "העתקה ללוח הגזירים", "directory.federated": "מהפדרציה הידועה", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 96fc720a4..83948b178 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -21,6 +21,7 @@ "account.blocked": "Letiltva", "account.browse_more_on_origin_server": "További böngészés az eredeti profilon", "account.cancel_follow_request": "Követési kérés visszavonása", + "account.copy": "Hivatkozás másolása a profilba", "account.direct": "@{name} személyes említése", "account.disable_notifications": "Ne figyelmeztessen, ha @{name} bejegyzést tesz közzé", "account.domain_blocked": "Letiltott domain", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Megjelölés olvasottként", "conversation.open": "Beszélgetés megtekintése", "conversation.with": "Velük: {names}", + "copy_icon_button.copied": "A szöveg a vágólapra másolva", "copypaste.copied": "Másolva", "copypaste.copy_to_clipboard": "Másolás vágólapra", "directory.federated": "Az ismert fediverzumból", @@ -481,13 +483,13 @@ "onboarding.follows.title": "Népszerű a Mastodonon", "onboarding.profile.discoverable": "Profil és bejegyzések szerepeltetése a felfedezési algoritmusokban", "onboarding.profile.display_name": "Megjelenített név", - "onboarding.profile.display_name_hint": "Teljes név vagy becenév…", - "onboarding.profile.indexable": "Nyilvános bejegyzések is a keresési eredményekben", - "onboarding.profile.lead": "Ezt később bármikor elvégezhető a beállításoknál, ahol még több testreszabási lehetőség áll rendelkezésre.", - "onboarding.profile.note": "Biográfia", - "onboarding.profile.note_hint": "@említhetünk másokat vagy #hashtag elemeket…", + "onboarding.profile.display_name_hint": "Teljes neved vagy vicces neved…", + "onboarding.profile.indexable": "Nyilvános bejegyzések szerepeltetése a keresési eredményekben", + "onboarding.profile.lead": "Ezt később bármikor befejezheted a beállításokban, ahol még több testreszabási lehetőség áll rendelkezésre.", + "onboarding.profile.note": "Bemutatkozás", + "onboarding.profile.note_hint": "Megemlíthetsz @másokat vagy #hashtag-eket…", "onboarding.profile.save_and_continue": "Mentés és folytatás", - "onboarding.profile.title": "Profil beüzemelés", + "onboarding.profile.title": "Profilbeállítás", "onboarding.profile.upload_avatar": "Profilkép feltöltése", "onboarding.profile.upload_header": "Profil fejléc feltöltése", "onboarding.share.lead": "Tudassuk az emberekkel, hogyan találhatnak meg a Mastodonon!", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 54123ae4c..b3c55d4f6 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -21,6 +21,7 @@ "account.blocked": "Útilokaður", "account.browse_more_on_origin_server": "Skoða nánari upplýsingar á notandasniðinu", "account.cancel_follow_request": "Taka fylgjendabeiðni til baka", + "account.copy": "Afrita tengil í notandasnið", "account.direct": "Einkaspjall við @{name}", "account.disable_notifications": "Hætta að láta mig vita þegar @{name} sendir inn", "account.domain_blocked": "Lén útilokað", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Merkja sem lesið", "conversation.open": "Skoða samtal", "conversation.with": "Við {names}", + "copy_icon_button.copied": "Afritað á klippispjald", "copypaste.copied": "Afritað", "copypaste.copy_to_clipboard": "Afrita á klippispjald", "directory.federated": "Frá samtengdum vefþjónum", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 284d7739c..02e5991ab 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -21,6 +21,7 @@ "account.blocked": "Bloccato", "account.browse_more_on_origin_server": "Sfoglia di più sul profilo originale", "account.cancel_follow_request": "Annulla la richiesta di seguire", + "account.copy": "Copia link del profilo", "account.direct": "Menziona privatamente @{name}", "account.disable_notifications": "Smetti di avvisarmi quando @{name} pubblica un post", "account.domain_blocked": "Dominio bloccato", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Segna come letto", "conversation.open": "Visualizza conversazione", "conversation.with": "Con {names}", + "copy_icon_button.copied": "Copiato negli appunti", "copypaste.copied": "Copiato", "copypaste.copy_to_clipboard": "Copia negli Appunti", "directory.federated": "Da un fediverse noto", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 1420be8e0..de72e382c 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -21,6 +21,7 @@ "account.blocked": "차단함", "account.browse_more_on_origin_server": "원본 프로필에서 더 탐색하기", "account.cancel_follow_request": "팔로우 취소", + "account.copy": "프로필 링크 복사", "account.direct": "@{name} 님에게 개인적으로 멘션", "account.disable_notifications": "@{name} 의 게시물 알림 끄기", "account.domain_blocked": "도메인 차단함", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "읽은 상태로 표시", "conversation.open": "대화 보기", "conversation.with": "{names} 님과", + "copy_icon_button.copied": "클립보드에 복사함", "copypaste.copied": "복사됨", "copypaste.copy_to_clipboard": "클립보드에 복사", "directory.federated": "알려진 연합우주로부터", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 21aa797b4..af9a3eaa0 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -21,6 +21,7 @@ "account.blocked": "Užblokuota", "account.browse_more_on_origin_server": "Naršyti daugiau originaliame profilyje", "account.cancel_follow_request": "Atšaukti sekimą", + "account.copy": "Kopijuoti nuorodą į profilį", "account.direct": "Privačiai paminėti @{name}", "account.disable_notifications": "Nustoti man pranešti, kai @{name} paskelbia", "account.domain_blocked": "Užblokuotas domenas", @@ -91,11 +92,28 @@ "bundle_column_error.routing.body": "Prašyto puslapio nepavyko rasti. Ar esi tikras (-a), kad adreso juostoje nurodytas URL adresas yra teisingas?", "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Uždaryti", + "bundle_modal_error.retry": "Bandyti dar kartą", + "closed_registrations.other_server_instructions": "Kadangi Mastodon yra decentralizuotas, gali susikurti paskyrą kitame serveryje ir vis tiek bendrauti su šiuo serveriu.", + "closed_registrations_modal.description": "Sukurti paskyrą {domain} šiuo metu neįmanoma, tačiau nepamiršk, kad norint naudotis Mastodon nebūtina turėti paskyrą {domain}.", "closed_registrations_modal.find_another_server": "Rasti kitą serverį", - "column.domain_blocks": "Hidden domains", + "closed_registrations_modal.preamble": "Mastodon yra decentralizuotas, todėl nesvarbu, kur susikursi paskyrą, galėsi sekti ir bendrauti su bet kuriuo šiame serveryje esančiu asmeniu. Jį gali net savarankiškai talpinti!", + "closed_registrations_modal.title": "Užsiregistravimas į Mastodon", + "column.about": "Apie", + "column.blocks": "Užblokuoti naudotojai", + "column.bookmarks": "Žymės", + "column.community": "Vietinė laiko skalė", + "column.direct": "Privatūs paminėjimai", + "column.directory": "Naršyti profilius", + "column.domain_blocks": "Užblokuoti domenai", + "column.favourites": "Mėgstamiausi", + "column.firehose": "Tiesioginiai padavimai", + "column.follow_requests": "Sekti prašymus", + "column.home": "Pradžia", "column.lists": "Sąrašai", - "column.mutes": "Užtildyti vartotojai", - "column.pins": "Pinned toot", + "column.mutes": "Užtildyti naudotojai", + "column.notifications": "Pranešimai", + "column.pins": "Prisegti įrašai", + "column.public": "Federacinė laiko skalė", "column_back_button.label": "Atgal", "column_header.hide_settings": "Slėpti nustatymus", "column_header.pin": "Prisegti", @@ -106,6 +124,7 @@ "compose.language.change": "Keisti kalbą", "compose.language.search": "Ieškoti kalbų...", "compose.published.body": "Įrašas paskelbtas.", + "compose_form.direct_message_warning_learn_more": "Sužinoti daugiau", "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.", "compose_form.placeholder": "Kas tavo mintyse?", @@ -137,6 +156,7 @@ "confirmations.reply.confirm": "Atsakyti", "confirmations.reply.message": "Atsakydamas (-a) dabar perrašysi šiuo metu rašomą žinutę. Ar tikrai nori tęsti?", "confirmations.unfollow.confirm": "Nebesekti", + "copy_icon_button.copied": "Nukopijuota į iškarpinę", "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", "embed.instructions": "Embed this status on your website by copying the code below.", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 6f941999f..e0fa73ef6 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -21,6 +21,7 @@ "account.blocked": "Geblokkeerd", "account.browse_more_on_origin_server": "Zie meer op het originele profiel", "account.cancel_follow_request": "Ontvolgen", + "account.copy": "Link naar profiel kopiëren", "account.direct": "@{name} een privébericht sturen", "account.disable_notifications": "Geen melding meer geven wanneer @{name} een bericht plaatst", "account.domain_blocked": "Domein geblokkeerd", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Als gelezen markeren", "conversation.open": "Gesprek tonen", "conversation.with": "Met {names}", + "copy_icon_button.copied": "Gekopieerd naar klembord", "copypaste.copied": "Gekopieerd", "copypaste.copy_to_clipboard": "Naar klembord kopiëren", "directory.federated": "Fediverse (wat bekend is)", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index a3402d660..5e4459e43 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -21,6 +21,7 @@ "account.blocked": "Blokkert", "account.browse_more_on_origin_server": "Sjå gjennom meir på den opphavlege profilen", "account.cancel_follow_request": "Trekk attende fylgeførespurnad", + "account.copy": "Kopier lenka til profilen", "account.direct": "Nevn @{name} privat", "account.disable_notifications": "Slutt å varsle meg når @{name} skriv innlegg", "account.domain_blocked": "Domenet er sperra", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marker som lesen", "conversation.open": "Sjå samtale", "conversation.with": "Med {names}", + "copy_icon_button.copied": "Kopiert til utklyppstavla", "copypaste.copied": "Kopiert", "copypaste.copy_to_clipboard": "Kopier til utklyppstavla", "directory.federated": "Frå den kjende allheimen", @@ -390,7 +392,7 @@ "lists.search": "Søk blant folk du fylgjer", "lists.subheading": "Listene dine", "load_pending": "{count, plural, one {# nytt element} other {# nye element}}", - "loading_indicator.label": "Laster…", + "loading_indicator.label": "Lastar…", "media_gallery.toggle_visible": "{number, plural, one {Skjul bilete} other {Skjul bilete}}", "moved_to_account_banner.text": "Kontoen din, {disabledAccount} er for tida deaktivert fordi du har flytta til {movedToAccount}.", "mute_modal.duration": "Varigheit", @@ -479,17 +481,17 @@ "onboarding.follows.empty": "Me kan ikkje visa deg nokon resultat no. Du kan prøva å søkja eller bla gjennom utforsk-sida for å finna folk å fylgja, eller du kan prøva att seinare.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", - "onboarding.profile.discoverable": "Fremhevede profiler og innlegg i oppdagelsealgoritmer", - "onboarding.profile.display_name": "Visningsnavn", - "onboarding.profile.display_name_hint": "Ditt fulle navn eller ditt morsomme navn…", - "onboarding.profile.indexable": "Inkluder offentlige innlegg i søkeresultatene", - "onboarding.profile.lead": "Du kan alltid fullføre dette senere i innstillingene, der enda flere tilpasningsalternativer er tilgjengelige.", + "onboarding.profile.discoverable": "Ta med profilen og innlegga i oppdagingsalgoritmar", + "onboarding.profile.display_name": "Synleg namn", + "onboarding.profile.display_name_hint": "Det fulle namnet eller kallenamnet ditt…", + "onboarding.profile.indexable": "Ta med offentlege innlegg i søkjeresultat", + "onboarding.profile.lead": "Du kan alltid fullføra dette seinare i innstillingane, og der er det endå fleire tilpassingsalternativ.", "onboarding.profile.note": "Om meg", - "onboarding.profile.note_hint": "Du kan @nevne andre eller #emneknagger…", - "onboarding.profile.save_and_continue": "Lagre og fortsett", - "onboarding.profile.title": "Konfigurering av profil", - "onboarding.profile.upload_avatar": "Last opp profilbilde", - "onboarding.profile.upload_header": "Last opp profiltoppbilde", + "onboarding.profile.note_hint": "Du kan @nemna folk eller #emneknaggar…", + "onboarding.profile.save_and_continue": "Lagre og hald fram", + "onboarding.profile.title": "Profiloppsett", + "onboarding.profile.upload_avatar": "Last opp profilbilete", + "onboarding.profile.upload_header": "Last opp profiltoppbilete", "onboarding.share.lead": "La folk vita korleis dei kan finna deg på Mastodon!", "onboarding.share.message": "Eg er {username} på #Mastodon! Du kan fylgja meg på {url}", "onboarding.share.next_steps": "Dette kan du gjera no:", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index fe3979f0f..0dce1e666 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -21,6 +21,7 @@ "account.blocked": "Blokkert", "account.browse_more_on_origin_server": "Bla mer på den opprinnelige profilen", "account.cancel_follow_request": "Avbryt følgeforespørselen", + "account.copy": "Kopier lenke til profil", "account.direct": "Nevn @{name} privat", "account.disable_notifications": "Slutt å varsle meg når @{name} legger ut innlegg", "account.domain_blocked": "Domene blokkert", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marker som lest", "conversation.open": "Vis samtale", "conversation.with": "Med {names}", + "copy_icon_button.copied": "Kopiert til utklippstavlen", "copypaste.copied": "Kopiert", "copypaste.copy_to_clipboard": "Kopier til utklippstavle", "directory.federated": "Fra det kjente strømiverset", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index a1cc0e26e..d316143e1 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -21,6 +21,7 @@ "account.blocked": "Zablokowany(-a)", "account.browse_more_on_origin_server": "Zobacz więcej na oryginalnym profilu", "account.cancel_follow_request": "Wycofaj żądanie obserwowania", + "account.copy": "Skopiuj odnośnik do profilu", "account.direct": "Prywatna wzmianka @{name}", "account.disable_notifications": "Przestań powiadamiać mnie o wpisach @{name}", "account.domain_blocked": "Ukryto domenę", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Oznacz jako przeczytane", "conversation.open": "Zobacz konwersację", "conversation.with": "Z {names}", + "copy_icon_button.copied": "Skopiowano do schowka", "copypaste.copied": "Skopiowano", "copypaste.copy_to_clipboard": "Skopiuj do schowka", "directory.federated": "Ze znanego fediwersum", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index 69e804878..0ad315152 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -21,6 +21,7 @@ "account.blocked": "Bloqueado(a)", "account.browse_more_on_origin_server": "Encontrar mais no perfil original", "account.cancel_follow_request": "Retirar pedido para seguir", + "account.copy": "Copiar hiperligação para o perfil", "account.direct": "Mencionar @{name} em privado", "account.disable_notifications": "Parar de me notificar das publicações de @{name}", "account.domain_blocked": "Domínio bloqueado", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marcar como lida", "conversation.open": "Ver conversa", "conversation.with": "Com {names}", + "copy_icon_button.copied": "Copiado para a área de transferência", "copypaste.copied": "Copiado", "copypaste.copy_to_clipboard": "Copiar para a área de transferência", "directory.federated": "Do fediverso conhecido", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 1417bed5f..c3110aa56 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -21,6 +21,7 @@ "account.blocked": "E bllokuar", "account.browse_more_on_origin_server": "Shfletoni më tepër rreth profilit origjinal", "account.cancel_follow_request": "Tërhiq mbrapsht kërkesë për ndjekje", + "account.copy": "Kopjoje lidhjen te profili", "account.direct": "Përmendje private për @{name}", "account.disable_notifications": "Resht së njoftuari mua, kur poston @{name}", "account.domain_blocked": "Përkatësia u bllokua", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Vëri shenjë si të lexuar", "conversation.open": "Shfaq bisedën", "conversation.with": "Me {names}", + "copy_icon_button.copied": "U kopjua në të papastër", "copypaste.copied": "U kopjua", "copypaste.copy_to_clipboard": "Kopjoje në të papastër", "directory.federated": "Nga fedivers i njohur", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index b0a76b32a..c614215aa 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -21,6 +21,7 @@ "account.blocked": "Блокиран", "account.browse_more_on_origin_server": "Прегледајте још на оригиналном профилу", "account.cancel_follow_request": "Откажи праћење", + "account.copy": "Копирај везу у профил", "account.direct": "Приватно помени @{name}", "account.disable_notifications": "Заустави обавештавање за објаве корисника @{name}", "account.domain_blocked": "Домен је блокиран", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Означи као прочитано", "conversation.open": "Прикажи разговор", "conversation.with": "Са {names}", + "copy_icon_button.copied": "Копирано", "copypaste.copied": "Копирано", "copypaste.copy_to_clipboard": "Копирај", "directory.federated": "Са знаног федиверзума", @@ -390,6 +392,7 @@ "lists.search": "Претражи међу људима које пратите", "lists.subheading": "Ваше листе", "load_pending": "{count, plural, one {# нова ставка} few {# нове ставке} other {# нових ставки}}", + "loading_indicator.label": "Учитавање…", "media_gallery.toggle_visible": "{number, plural, one {Сакриј слику} few {Сакриј слике} other {Сакриј слике}}", "moved_to_account_banner.text": "Ваш налог {disabledAccount} је тренутно онемогућен јер сте прешли на {movedToAccount}.", "mute_modal.duration": "Трајање", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 6f9f37ea1..0b1a7f6ad 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -21,6 +21,7 @@ "account.blocked": "Blockerad", "account.browse_more_on_origin_server": "Läs mer på den ursprungliga profilen", "account.cancel_follow_request": "Återkalla din begäran om att få följa", + "account.copy": "Kopiera länk till profil", "account.direct": "Nämn @{name} privat", "account.disable_notifications": "Sluta notifiera mig när @{name} gör inlägg", "account.domain_blocked": "Domän blockerad", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Markera som läst", "conversation.open": "Visa konversation", "conversation.with": "Med {names}", + "copy_icon_button.copied": "Kopierad till urklipp", "copypaste.copied": "Kopierad", "copypaste.copy_to_clipboard": "Kopiera till urklipp", "directory.federated": "Från känt fediversum", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 2166cd2dd..c86b7c379 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -21,6 +21,7 @@ "account.blocked": "ปิดกั้นอยู่", "account.browse_more_on_origin_server": "เรียกดูเพิ่มเติมในโปรไฟล์ดั้งเดิม", "account.cancel_follow_request": "ยกเลิกการติดตาม", + "account.copy": "คัดลอกลิงก์ไปยังโปรไฟล์", "account.direct": "กล่าวถึง @{name} แบบส่วนตัว", "account.disable_notifications": "หยุดแจ้งเตือนฉันเมื่อ @{name} โพสต์", "account.domain_blocked": "ปิดกั้นโดเมนอยู่", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "ทำเครื่องหมายว่าอ่านแล้ว", "conversation.open": "ดูการสนทนา", "conversation.with": "กับ {names}", + "copy_icon_button.copied": "คัดลอกไปยังคลิปบอร์ดแล้ว", "copypaste.copied": "คัดลอกแล้ว", "copypaste.copy_to_clipboard": "คัดลอกไปยังคลิปบอร์ด", "directory.federated": "จากจักรวาลสหพันธ์ที่รู้จัก", @@ -481,15 +483,15 @@ "onboarding.follows.title": "ปรับแต่งฟีดหน้าแรกของคุณ", "onboarding.profile.discoverable": "แสดงโปรไฟล์และโพสต์ในอัลกอริทึมการค้นพบ", "onboarding.profile.display_name": "ชื่อที่แสดง", - "onboarding.profile.display_name_hint": "ชื่อเต็มหรือชื่อแบบสนุกสนานของคุณ", + "onboarding.profile.display_name_hint": "ชื่อเต็มของคุณหรือชื่อแบบสนุกสนานของคุณ…", "onboarding.profile.indexable": "รวมโพสต์สาธารณะในผลลัพธ์การค้นหา", "onboarding.profile.lead": "คุณสามารถกลับมาทำต่อได้เสมอในการตั้งค่า ซึ่งจะมีตัวเลือกในการปรับแต่งมากกว่า", "onboarding.profile.note": "ชีวประวัติ", - "onboarding.profile.note_hint": "คุณสามารถ @กล่าวถึง ผู้คนอื่น ๆ หรือ #แฮชแท็ก", + "onboarding.profile.note_hint": "คุณสามารถ @กล่าวถึง ผู้คนอื่น ๆ หรือ #แฮชแท็ก…", "onboarding.profile.save_and_continue": "บันทึกและดำเนินการต่อ", "onboarding.profile.title": "การตั้งค่าโปรไฟล์", - "onboarding.profile.upload_avatar": "อัปโหลดรูปโปรไฟล์", - "onboarding.profile.upload_header": "อัปโหลดรูปส่วนหัวโปรไฟล์", + "onboarding.profile.upload_avatar": "อัปโหลดรูปภาพโปรไฟล์", + "onboarding.profile.upload_header": "อัปโหลดส่วนหัวโปรไฟล์", "onboarding.share.lead": "แจ้งให้ผู้คนทราบวิธีที่เขาสามารถค้นหาคุณใน Mastodon!", "onboarding.share.message": "ฉันคือ {username} ใน #Mastodon! มาติดตามฉันที่ {url}", "onboarding.share.next_steps": "ขั้นตอนถัดไปที่เป็นไปได้:", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 8649d9310..1307d7ea5 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -21,6 +21,7 @@ "account.blocked": "Заблоковані", "account.browse_more_on_origin_server": "Переглянути більше в оригінальному профілі", "account.cancel_follow_request": "Відкликати запит на стеження", + "account.copy": "Копіювати посилання на профіль", "account.direct": "Особиста згадка @{name}", "account.disable_notifications": "Не повідомляти мене про дописи @{name}", "account.domain_blocked": "Домен заблоковано", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Позначити як прочитане", "conversation.open": "Переглянути бесіду", "conversation.with": "З {names}", + "copy_icon_button.copied": "Скопійовано до буфера обміну", "copypaste.copied": "Скопійовано", "copypaste.copy_to_clipboard": "Копіювати до буфера обміну", "directory.federated": "З відомого федесвіту", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index cc6d8994d..79f463772 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -21,6 +21,7 @@ "account.blocked": "已屏蔽", "account.browse_more_on_origin_server": "在原始个人资料页面上浏览详情", "account.cancel_follow_request": "撤回关注请求", + "account.copy": "复制资料卡链接", "account.direct": "私下提及 @{name}", "account.disable_notifications": "当 @{name} 发布嘟文时不要通知我", "account.domain_blocked": "域名已屏蔽", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "标记为已读", "conversation.open": "查看对话", "conversation.with": "与 {names}", + "copy_icon_button.copied": "已复制到剪贴板", "copypaste.copied": "已复制", "copypaste.copy_to_clipboard": "复制到剪贴板", "directory.federated": "来自已知的联邦宇宙", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index ea932bc5a..e7af27c5f 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -21,6 +21,7 @@ "account.blocked": "已封鎖", "account.browse_more_on_origin_server": "前往原始的個人檔案頁瀏覽更多", "account.cancel_follow_request": "撤回追蹤請求", + "account.copy": "複製個人檔案連結", "account.direct": "私下提及 @{name}", "account.disable_notifications": "當 @{name} 發文時不要再通知我", "account.domain_blocked": "網域被封鎖", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "標為已讀", "conversation.open": "檢視對話", "conversation.with": "與 {names}", + "copy_icon_button.copied": "已複製到剪貼簿", "copypaste.copied": "已複製", "copypaste.copy_to_clipboard": "複製到剪貼簿", "directory.federated": "來自已知的聯盟網絡", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 4c52693cc..d4f3010c9 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -21,6 +21,7 @@ "account.blocked": "已封鎖", "account.browse_more_on_origin_server": "在該伺服器上的個人檔案頁面瀏覽更多", "account.cancel_follow_request": "收回跟隨請求", + "account.copy": "複製個人檔案連結", "account.direct": "私訊 @{name}", "account.disable_notifications": "取消來自 @{name} 嘟文的通知", "account.domain_blocked": "已封鎖網域", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "標記為已讀", "conversation.open": "檢視對話", "conversation.with": "與 {names}", + "copy_icon_button.copied": "已複製到剪貼簿", "copypaste.copied": "已複製", "copypaste.copy_to_clipboard": "複製到剪貼簿", "directory.federated": "來自已知聯邦宇宙", diff --git a/config/locales/es.yml b/config/locales/es.yml index 34d1c85dc..72a36250f 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -611,6 +611,7 @@ es: created_at: Denunciado delete_and_resolve: Eliminar publicaciones forwarded: Reenviado + forwarded_replies_explanation: Este informe es de un usuario remoto y sobre contenido remoto. Se le ha enviado porque el contenido reportado es en respuesta a uno de sus usuarios. forwarded_to: Reenviado a %{domain} mark_as_resolved: Marcar como resuelto mark_as_sensitive: Marcar como sensible diff --git a/config/locales/eu.yml b/config/locales/eu.yml index dd7575c57..6aa92c2d1 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -613,6 +613,7 @@ eu: created_at: Salatua delete_and_resolve: Ezabatu bidalketak forwarded: Birbidalia + forwarded_replies_explanation: Salaketa hau beste instantzia bateko erabiltzaile baten edukiari buruzkoa da, eta zure instantziako erabiltzaile bati egidako erantzuna delako bidali dizugu mezu hau. forwarded_to: 'Hona birbidalia: %{domain}' mark_as_resolved: Markatu konpondutako gisa mark_as_sensitive: Markatu hunkigarri gisa diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 0075c6592..955ec50e7 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -384,7 +384,7 @@ gl: domain_blocks: add_new: Engadir novo bloqueo de dominio confirm_suspension: - cancel: Cancelar + cancel: Desbotar confirm: Suspender permanent_action: Ao retirar a suspensión non restableces os datos ou a relación. preamble_html: Vas suspender a <strong>%{domain}</strong> e os seus subdominios. @@ -611,6 +611,7 @@ gl: created_at: Denunciado delete_and_resolve: Eliminar publicacións forwarded: Reenviado + forwarded_replies_explanation: Esta denuncia procede dunha usuaria remota e acerca de contido remoto. Enviouseche unha copia porque o contido denunciado é unha resposta a unha das túas usuarias. forwarded_to: Reenviado a %{domain} mark_as_resolved: Marcar como resolto mark_as_sensitive: Marcar como sensible diff --git a/config/locales/hu.yml b/config/locales/hu.yml index a0ff3061f..60016c935 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -611,7 +611,7 @@ hu: created_at: Jelentve delete_and_resolve: Bejegyzések törlése forwarded: Továbbítva - forwarded_replies_explanation: Ez a jelentés egy távoli felhasználótól származik, és távoli tartalomról szól. Azért lett neked továbbítva, mert a jelentett tartalom az egyik felhasználódnak küldött válasz. + forwarded_replies_explanation: Ez a jelentés egy távoli flehasználótól származik, és távoli tartalomról szól. Azért lett neked továbbítva, mert a jelentett tartalom az egyik felhasználódnak küldött válasz. forwarded_to: 'Továbbítva ide: %{domain}' mark_as_resolved: Megjelölés megoldottként mark_as_sensitive: Érzékenynek jelölés diff --git a/config/locales/ko.yml b/config/locales/ko.yml index e11081fcd..7dcb5d632 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -763,7 +763,7 @@ ko: open: 누구나 가입 할 수 있음 security: authorized_fetch: 연합된 서버들에게서 인증 필수 - authorized_fetch_hint: 연합된 서버들에게서 인증을 요구하는 것은 사용자 레벨과 서버 레벨의 차단은 좀 더 확실하게 해줍니다. 한편으로는 성능적인 페널티, 답글의 전달 범위 감소, 몇몇 연합된 서비스들과의 호환성 문제가 있을 가능성이 있습니다. 추가적으로 이 기능은 전용 액터가 공개돤 게시물이나 계정을 페치하는 것은 막지 않습니다. + authorized_fetch_hint: 연합된 서버들에게서 인증을 요구하는 것은 사용자 레벨과 서버 레벨의 차단을 좀 더 확실하게 해줍니다. 한편으로는 성능적인 페널티, 답글의 전달 범위 감소, 몇몇 연합된 서비스들과의 호환성 문제가 있을 가능성이 있습니다. 추가적으로 이 기능은 전용 액터가 공개돤 게시물이나 계정을 페치하는 것은 막지 않습니다. authorized_fetch_overridden_hint: 현재 이 값은 환경변수에 의해 설정되어 있기에 설정을 변경할 수 없습니다. federation_authentication: 연합 인증 필수 title: 서버 설정 diff --git a/config/locales/nn.yml b/config/locales/nn.yml index 09de24a67..ad2acdda8 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -534,7 +534,7 @@ nn: total_reported: Rapportar om dei total_storage: Medievedlegg totals_time_period_hint_html: Totalsum vist nedanfor gjeld data for alle tidsperiodar. - unknown_instance: Dette domenet er ukjent for denne serveren. + unknown_instance: Domenet er ukjent for denne tenaren. invites: deactivate_all: Slå av alle filter: @@ -611,7 +611,7 @@ nn: created_at: Rapportert delete_and_resolve: Slett innlegg forwarded: Videresendt - forwarded_replies_explanation: Denne rapporten er fra en ekstern bruker og handler om eksternt innhold. Den er videresendt til deg fordi det rapporterte innholdet svarer til en av brukerne dine. + forwarded_replies_explanation: Denne rapporten gjeld innhald på ein annan nettstad. Rapporten er vidaresend til deg fordi det rapporterte innhaldet er eit svar på noko ein av brukarane på nettstaden din har skrive. forwarded_to: Videresendt til %{domain} mark_as_resolved: Merk som løyst mark_as_sensitive: Marker som ømtolig @@ -1042,14 +1042,14 @@ nn: hint_html: Berre ein ting til! Vi må bekrefte at du er et menneske (så vi kan halde spam ute!). Løys CAPTCHA-en nedanfor og klikk "Fortsett". title: Sikkerheitssjekk confirmations: - awaiting_review: Din e-post adresse er bekreftet! %{domain} ansatte gjennomgår nå registreringen din. Du vil motta en e-post hvis de godkjenner din konto! - awaiting_review_title: Din registrering blir vurdert - clicking_this_link: klikke på denne lenken - login_link: logg inn - proceed_to_login_html: Du kan nå fortsette til %{login_link}. - redirect_to_app_html: Du burde bli omdirigert til <strong>%{app_name}</strong> -appen. Hvis det ikke skjedde, kan du prøve %{clicking_this_link} eller manuelt gå tilbake til appen. - registration_complete: Registreringen på %{domain} er nå fullført! - welcome_title: Velkommen, %{name}! + awaiting_review: Epostadressa di er stadfesta! Styrarane på %{domain} ser gjennom registreringa di. Du får ein epost frå dei om dei godkjenner brukarkontoen din. + awaiting_review_title: Me går gjennom registreringa di + clicking_this_link: klikka på denne lenka + login_link: logga inn + proceed_to_login_html: No kan du %{login_link}. + redirect_to_app_html: Du skulle vorte vidaresend til <strong>%{app_name}</strong>-appen. Viss det ikkje skjedde, kan du prøva å %{clicking_this_link} eller manuelt gå tilbake til appen. + registration_complete: Du har registrert deg som brukar på %{domain}. + welcome_title: Velkomen, %{name}! wrong_email_hint: Viss epostadressa er feil, kan du endra ho i kontoinnstillingane. delete_account: Slett konto delete_account_html: Om du vil sletta kontoen din, kan du <a href="%{path}">gå hit</a>. Du vert spurd etter stadfesting. @@ -1111,7 +1111,7 @@ nn: functional: Kontoen din er fullt operativt. pending: Søknaden din ventar på gjennomgang frå personalet vårt. Dette kan taka litt tid. Du får ein e-post om søknaden din vert godkjend. redirecting_to: Kontoen din er inaktiv fordi den for øyeblikket omdirigerer til %{acct}. - self_destruct: Siden %{domain} stenger, vil du kun ha begrenset tilgang til kontoen din. + self_destruct: Av di %{domain} er i ferd med å stenga, vil du berre få avgrensa tilgang til brukarkontoen din. view_strikes: Vis tidligere advarsler mot kontoen din too_fast: Skjemaet ble sendt inn for raskt, prøv på nytt. use_security_key: Bruk sikkerhetsnøkkel @@ -1583,8 +1583,8 @@ nn: over_total_limit: Du har overskredet grensen på %{limit} planlagte tuter too_soon: Den planlagte datoen må være i fremtiden self_destruct: - lead_html: Dessverre stenger <strong>%{domain}</strong> for alltid. Hvis du hadde en konto der vil du ikke kunne fortsette å bruke den, men du kan fremdeles be om en sikkerhetskopi av dataene dine. - title: Denne serveren stenger + lead_html: Diverre stengjer <strong>%{domain}</strong> dørene for godt. Viss du hadde ein brukarkonto der, vil du ikkje kunna halda fram å bruka han, men du kan få ut ein tryggingskopi av dataa dine. + title: Denne tenaren stengjer sessions: activity: Siste aktivitet browser: Nettlesar diff --git a/config/locales/no.yml b/config/locales/no.yml index 3cf2df3a1..42bd6193c 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -1533,7 +1533,7 @@ posting_defaults: Innleggsstandarder public_timelines: Offentlige tidslinjer privacy: - hint_html: "<strong>Tilpass hvordan du vil at din profil og dine innlegg skal bli funnet.</strong> En rekke funksjoner i Mastodon kan hjelpe deg med å nå et bredere publikum når de aktiverte. Ta deg et øyeblikk til å vurdere disse innstillingene for å forsikre deg om at de passer deg og ditt bruk." + hint_html: "<strong>Tilpass hvordan du vil at din profil og dine innlegg skal bli funnet.</strong> En rekke funksjoner i Mastodon kan hjelpe deg med å nå et bredere publikum når det er aktivert. Ta deg et øyeblikk til å vurdere disse innstillingene for å forsikre deg om at de passer deg og ditt bruk." privacy: Personvern privacy_hint_html: Kontrollér hvor mye du ønsker å dele til fordel for andre. Folk oppdager interessante profiler og kule app'er ved å bla gjennom andres følgere og ved å se hvilke app'er de bruker, men du kan velge å holde det skjult. reach: Rekkevidde diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 407908517..b271b15f1 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -623,6 +623,7 @@ sr: created_at: Пријављена delete_and_resolve: Обриши објаве forwarded: Прослеђено + forwarded_replies_explanation: Овај извештај је од удаљеног корисника и о удаљеном садржају. Прослеђен вам је јер је пријављени садржај у одговору једном од ваших корисника. forwarded_to: Прослеђено ка %{domain} mark_as_resolved: Означи као решену mark_as_sensitive: Обележи као осетљиво diff --git a/config/locales/th.yml b/config/locales/th.yml index 79d668d3e..0b7498e7d 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -560,7 +560,7 @@ th: enabled: เปิดใช้งานอยู่ inbox_url: URL ของรีเลย์ pending: กำลังรอการอนุมัติของรีเลย์ - save_and_enable: บันทึกแล้วเปิดใช้งาน + save_and_enable: บันทึกและเปิดใช้งาน setup: ตั้งค่าการเชื่อมต่อรีเลย์ signatures_not_enabled: รีเลย์อาจทำงานไม่ถูกต้องขณะที่มีการเปิดใช้งานโหมดปลอดภัยหรือโหมดการติดต่อกับภายนอกแบบจำกัด status: สถานะ @@ -599,7 +599,7 @@ th: created_at: รายงานเมื่อ delete_and_resolve: ลบโพสต์ forwarded: ส่งต่อแล้ว - forwarded_replies_explanation: รายงานนี้มาจากผู้ใช้ระยะไกล และเป็นรายงานเกี่ยวกับเนื้อหาระยะไกล ซึ่งถูกส่งต่อมาหาคุณเนื่องจากเนื้อหาที่ถูกรายงานอยู่ในการตอบกลับไปยังหนึ่งในผู้ใช้ของคุณ + forwarded_replies_explanation: รายงานนี้มาจากผู้ใช้ระยะไกลและเกี่ยวกับเนื้อหาระยะไกล มีการส่งต่อรายงานไปยังคุณเนื่องจากเนื้อหาที่รายงานอยู่ในการตอบกลับหนึ่งในผู้ใช้ของคุณ forwarded_to: ส่งต่อไปยัง %{domain} แล้ว mark_as_resolved: ทำเครื่องหมายว่าแก้ปัญหาแล้ว mark_as_sensitive: ทำเครื่องหมายว่าละเอียดอ่อน diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 9d4d95a83..5882eae31 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -611,6 +611,7 @@ tr: created_at: Şikayet edildi delete_and_resolve: Gönderileri sil forwarded: İletildi + forwarded_replies_explanation: Bu bildirim başka bir sunucudaki kullanıcı ve içerik ile ilgili. Bildirilen içerik kullanıcılarınızdan birine yanıt şeklinde olduğu için size yönlendirildi. forwarded_to: "%{domain}'e iletildi" mark_as_resolved: Giderildi olarak işaretle mark_as_sensitive: Hassas olarak işaretle diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index b98193065..b788b53e1 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -599,6 +599,7 @@ zh-CN: created_at: 举报时间 delete_and_resolve: 删除嘟文 forwarded: 已转发 + forwarded_replies_explanation: 该举报来自外站用户,涉及外站内容。之所以转发给您,是因为被举报的内容是对您站点一位用户的回复。 forwarded_to: 转发举报至 %{domain} mark_as_resolved: 标记为已处理 mark_as_sensitive: 标记为敏感内容 From 549e8e7baf62eb4ecb4dd039e301e6280889218d Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 17 Nov 2023 04:50:19 -0500 Subject: [PATCH 063/255] Add `email_spec` and speedup/cleanup to `spec/mailers` (#27902) --- Gemfile | 3 + Gemfile.lock | 5 + spec/mailers/admin_mailer_spec.rb | 97 +++++++------- spec/mailers/notification_mailer_spec.rb | 109 ++++++++-------- spec/mailers/user_mailer_spec.rb | 119 ++++++++++++------ spec/rails_helper.rb | 1 + .../api/v1/admin/account_actions_spec.rb | 12 +- 7 files changed, 194 insertions(+), 152 deletions(-) diff --git a/Gemfile b/Gemfile index add7b3606..74672ad06 100644 --- a/Gemfile +++ b/Gemfile @@ -109,6 +109,9 @@ group :test do # RSpec progress bar formatter gem 'fuubar', '~> 2.5' + # RSpec helpers for email specs + gem 'email_spec' + # Extra RSpec extenion methods and helpers for sidekiq gem 'rspec-sidekiq', '~> 4.0' diff --git a/Gemfile.lock b/Gemfile.lock index 20c958e2e..beec8b39c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -260,6 +260,10 @@ GEM elasticsearch-transport (7.13.3) faraday (~> 1) multi_json + email_spec (2.2.2) + htmlentities (~> 4.3.3) + launchy (~> 2.1) + mail (~> 2.7) encryptor (3.0.0) erubi (1.12.0) et-orbi (1.2.7) @@ -853,6 +857,7 @@ DEPENDENCIES doorkeeper (~> 5.6) dotenv-rails (~> 2.8) ed25519 (~> 1.3) + email_spec fabrication (~> 2.30) faker (~> 3.2) fast_blank (~> 1.0) diff --git a/spec/mailers/admin_mailer_spec.rb b/spec/mailers/admin_mailer_spec.rb index 423dce88a..9f0d89996 100644 --- a/spec/mailers/admin_mailer_spec.rb +++ b/spec/mailers/admin_mailer_spec.rb @@ -13,14 +13,13 @@ RSpec.describe AdminMailer do recipient.user.update(locale: :en) end - it 'renders the headers' do - expect(mail.subject).to eq("New report for cb6e6126.ngrok.io (##{report.id})") - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - end - - it 'renders the body' do - expect(mail.body.encoded).to eq("Mike,\r\n\r\nJohn has reported Mike\r\n\r\nView: https://cb6e6126.ngrok.io/admin/reports/#{report.id}\r\n") + it 'renders the email' do + expect(mail) + .to be_present + .and(deliver_to(recipient.user_email)) + .and(deliver_from('notifications@localhost')) + .and(have_subject("New report for cb6e6126.ngrok.io (##{report.id})")) + .and(have_body_text("Mike,\r\n\r\nJohn has reported Mike\r\n\r\nView: https://cb6e6126.ngrok.io/admin/reports/#{report.id}\r\n")) end end @@ -33,14 +32,13 @@ RSpec.describe AdminMailer do recipient.user.update(locale: :en) end - it 'renders the headers' do - expect(mail.subject).to eq("#{appeal.account.username} is appealing a moderation decision on cb6e6126.ngrok.io") - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - end - - it 'renders the body' do - expect(mail.body.encoded).to match "#{appeal.account.username} is appealing a moderation decision by #{appeal.strike.account.username}" + it 'renders the email' do + expect(mail) + .to be_present + .and(deliver_to(recipient.user_email)) + .and(deliver_from('notifications@localhost')) + .and(have_subject("#{appeal.account.username} is appealing a moderation decision on cb6e6126.ngrok.io")) + .and(have_body_text("#{appeal.account.username} is appealing a moderation decision by #{appeal.strike.account.username}")) end end @@ -53,14 +51,13 @@ RSpec.describe AdminMailer do recipient.user.update(locale: :en) end - it 'renders the headers' do - expect(mail.subject).to eq("New account up for review on cb6e6126.ngrok.io (#{user.account.username})") - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - end - - it 'renders the body' do - expect(mail.body.encoded).to match 'The details of the new account are below. You can approve or reject this application.' + it 'renders the email' do + expect(mail) + .to be_present + .and(deliver_to(recipient.user_email)) + .and(deliver_from('notifications@localhost')) + .and(have_subject("New account up for review on cb6e6126.ngrok.io (#{user.account.username})")) + .and(have_body_text('The details of the new account are below. You can approve or reject this application.')) end end @@ -75,14 +72,13 @@ RSpec.describe AdminMailer do recipient.user.update(locale: :en) end - it 'renders the headers' do - expect(mail.subject).to eq('New trends up for review on cb6e6126.ngrok.io') - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - end - - it 'renders the body' do - expect(mail.body.encoded).to match 'The following items need a review before they can be displayed publicly' + it 'renders the email' do + expect(mail) + .to be_present + .and(deliver_to(recipient.user_email)) + .and(deliver_from('notifications@localhost')) + .and(have_subject('New trends up for review on cb6e6126.ngrok.io')) + .and(have_body_text('The following items need a review before they can be displayed publicly')) end end @@ -94,14 +90,13 @@ RSpec.describe AdminMailer do recipient.user.update(locale: :en) end - it 'renders the headers' do - expect(mail.subject).to eq('New Mastodon versions are available for cb6e6126.ngrok.io!') - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - end - - it 'renders the body' do - expect(mail.body.encoded).to match 'New Mastodon versions have been released, you may want to update!' + it 'renders the email' do + expect(mail) + .to be_present + .and(deliver_to(recipient.user_email)) + .and(deliver_from('notifications@localhost')) + .and(have_subject('New Mastodon versions are available for cb6e6126.ngrok.io!')) + .and(have_body_text('New Mastodon versions have been released, you may want to update!')) end end @@ -113,18 +108,16 @@ RSpec.describe AdminMailer do recipient.user.update(locale: :en) end - it 'renders the headers', :aggregate_failures do - expect(mail.subject).to eq('Critical Mastodon updates are available for cb6e6126.ngrok.io!') - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - - expect(mail['Importance'].value).to eq 'high' - expect(mail['Priority'].value).to eq 'urgent' - expect(mail['X-Priority'].value).to eq '1' - end - - it 'renders the body' do - expect(mail.body.encoded).to match 'New critical versions of Mastodon have been released, you may want to update as soon as possible!' + it 'renders the email' do + expect(mail) + .to be_present + .and(deliver_to(recipient.user_email)) + .and(deliver_from('notifications@localhost')) + .and(have_subject('Critical Mastodon updates are available for cb6e6126.ngrok.io!')) + .and(have_body_text('New critical versions of Mastodon have been released, you may want to update as soon as possible!')) + .and(have_header('Importance', 'high')) + .and(have_header('Priority', 'urgent')) + .and(have_header('X-Priority', '1')) end end end diff --git a/spec/mailers/notification_mailer_spec.rb b/spec/mailers/notification_mailer_spec.rb index 78a497c06..eab196166 100644 --- a/spec/mailers/notification_mailer_spec.rb +++ b/spec/mailers/notification_mailer_spec.rb @@ -8,24 +8,27 @@ RSpec.describe NotificationMailer do let(:foreign_status) { Fabricate(:status, account: sender, text: 'The body of the foreign status') } let(:own_status) { Fabricate(:status, account: receiver.account, text: 'The body of the own status') } - shared_examples 'headers' do |type, thread| - it 'renders the to and from headers' do - expect(mail[:to].value).to eq "#{receiver.account.username} <#{receiver.email}>" - expect(mail.from).to eq ['notifications@localhost'] + shared_examples 'standard headers' do |type| + it 'renders the email' do + expect(mail) + .to be_present + .and(have_header('To', "#{receiver.account.username} <#{receiver.email}>")) + .and(have_header('List-ID', "<#{type}.alice.cb6e6126.ngrok.io>")) + .and(have_header('List-Unsubscribe', %r{<https://cb6e6126.ngrok.io/unsubscribe\?token=.+>})) + .and(have_header('List-Unsubscribe', /&type=#{type}/)) + .and(have_header('List-Unsubscribe-Post', 'List-Unsubscribe=One-Click')) + .and(deliver_to("#{receiver.account.username} <#{receiver.email}>")) + .and(deliver_from('notifications@localhost')) end + end - it 'renders the list headers' do - expect(mail['List-ID'].value).to eq "<#{type}.alice.cb6e6126.ngrok.io>" - expect(mail['List-Unsubscribe'].value).to match(%r{<https://cb6e6126.ngrok.io/unsubscribe\?token=.+>}) - expect(mail['List-Unsubscribe'].value).to match("&type=#{type}") - expect(mail['List-Unsubscribe-Post'].value).to eq 'List-Unsubscribe=One-Click' - end - - if thread - it 'renders the thread headers' do - expect(mail['In-Reply-To'].value).to match(/<conversation-\d+.\d\d\d\d-\d\d-\d\d@cb6e6126.ngrok.io>/) - expect(mail['References'].value).to match(/<conversation-\d+.\d\d\d\d-\d\d-\d\d@cb6e6126.ngrok.io>/) - end + shared_examples 'thread headers' do + it 'renders the email with conversation thread headers' do + conversation_header_regex = /<conversation-\d+.\d\d\d\d-\d\d-\d\d@cb6e6126.ngrok.io>/ + expect(mail) + .to be_present + .and(have_header('In-Reply-To', conversation_header_regex)) + .and(have_header('References', conversation_header_regex)) end end @@ -35,15 +38,15 @@ RSpec.describe NotificationMailer do let(:mail) { prepared_mailer_for(receiver.account).mention } include_examples 'localized subject', 'notification_mailer.mention.subject', name: 'bob' - include_examples 'headers', 'mention', true + include_examples 'standard headers', 'mention' + include_examples 'thread headers' - it 'renders the subject' do - expect(mail.subject).to eq('You were mentioned by bob') - end - - it 'renders the body' do - expect(mail.body.encoded).to match('You were mentioned by bob') - expect(mail.body.encoded).to include 'The body of the foreign status' + it 'renders the email' do + expect(mail) + .to be_present + .and(have_subject('You were mentioned by bob')) + .and(have_body_text('You were mentioned by bob')) + .and(have_body_text('The body of the foreign status')) end end @@ -53,14 +56,13 @@ RSpec.describe NotificationMailer do let(:mail) { prepared_mailer_for(receiver.account).follow } include_examples 'localized subject', 'notification_mailer.follow.subject', name: 'bob' - include_examples 'headers', 'follow', false + include_examples 'standard headers', 'follow' - it 'renders the subject' do - expect(mail.subject).to eq('bob is now following you') - end - - it 'renders the body' do - expect(mail.body.encoded).to match('bob is now following you') + it 'renders the email' do + expect(mail) + .to be_present + .and(have_subject('bob is now following you')) + .and(have_body_text('bob is now following you')) end end @@ -70,15 +72,15 @@ RSpec.describe NotificationMailer do let(:mail) { prepared_mailer_for(own_status.account).favourite } include_examples 'localized subject', 'notification_mailer.favourite.subject', name: 'bob' - include_examples 'headers', 'favourite', true + include_examples 'standard headers', 'favourite' + include_examples 'thread headers' - it 'renders the subject' do - expect(mail.subject).to eq('bob favorited your post') - end - - it 'renders the body' do - expect(mail.body.encoded).to match('Your post was favorited by bob') - expect(mail.body.encoded).to include 'The body of the own status' + it 'renders the email' do + expect(mail) + .to be_present + .and(have_subject('bob favorited your post')) + .and(have_body_text('Your post was favorited by bob')) + .and(have_body_text('The body of the own status')) end end @@ -88,15 +90,15 @@ RSpec.describe NotificationMailer do let(:mail) { prepared_mailer_for(own_status.account).reblog } include_examples 'localized subject', 'notification_mailer.reblog.subject', name: 'bob' - include_examples 'headers', 'reblog', true + include_examples 'standard headers', 'reblog' + include_examples 'thread headers' - it 'renders the subject' do - expect(mail.subject).to eq('bob boosted your post') - end - - it 'renders the body' do - expect(mail.body.encoded).to match('Your post was boosted by bob') - expect(mail.body.encoded).to include 'The body of the own status' + it 'renders the email' do + expect(mail) + .to be_present + .and(have_subject('bob boosted your post')) + .and(have_body_text('Your post was boosted by bob')) + .and(have_body_text('The body of the own status')) end end @@ -106,14 +108,13 @@ RSpec.describe NotificationMailer do let(:mail) { prepared_mailer_for(receiver.account).follow_request } include_examples 'localized subject', 'notification_mailer.follow_request.subject', name: 'bob' - include_examples 'headers', 'follow_request', false + include_examples 'standard headers', 'follow_request' - it 'renders the subject' do - expect(mail.subject).to eq('Pending follower: bob') - end - - it 'renders the body' do - expect(mail.body.encoded).to match('bob has requested to follow you') + it 'renders the email' do + expect(mail) + .to be_present + .and(have_subject('Pending follower: bob')) + .and(have_body_text('bob has requested to follow you')) end end diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index c661f5bbd..4a4392824 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -10,9 +10,12 @@ describe UserMailer do it 'renders confirmation instructions' do receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.confirmation_instructions.title') - expect(mail.body.encoded).to include 'spec' - expect(mail.body.encoded).to include Rails.configuration.x.local_domain + + expect(mail) + .to be_present + .and(have_body_text(I18n.t('devise.mailer.confirmation_instructions.title'))) + .and(have_body_text('spec')) + .and(have_body_text(Rails.configuration.x.local_domain)) end include_examples 'localized subject', @@ -25,13 +28,17 @@ describe UserMailer do it 'renders reconfirmation instructions' do receiver.update!(email: 'new-email@example.com', locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.reconfirmation_instructions.title') - expect(mail.body.encoded).to include 'spec' - expect(mail.body.encoded).to include Rails.configuration.x.local_domain - expect(mail.subject).to eq I18n.t('devise.mailer.reconfirmation_instructions.subject', - instance: Rails.configuration.x.local_domain, - locale: I18n.default_locale) + + expect(mail) + .to be_present + .and(have_body_text(I18n.t('devise.mailer.reconfirmation_instructions.title'))) + .and(have_body_text('spec')) + .and(have_body_text(Rails.configuration.x.local_domain)) end + + include_examples 'localized subject', + 'devise.mailer.confirmation_instructions.subject', + instance: Rails.configuration.x.local_domain end describe '#reset_password_instructions' do @@ -39,8 +46,11 @@ describe UserMailer do it 'renders reset password instructions' do receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.reset_password_instructions.title') - expect(mail.body.encoded).to include 'spec' + + expect(mail) + .to be_present + .and(have_body_text(I18n.t('devise.mailer.reset_password_instructions.title'))) + .and(have_body_text('spec')) end include_examples 'localized subject', @@ -52,7 +62,10 @@ describe UserMailer do it 'renders password change notification' do receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.password_change.title') + + expect(mail) + .to be_present + .and(have_body_text(I18n.t('devise.mailer.password_change.title'))) end include_examples 'localized subject', @@ -64,7 +77,10 @@ describe UserMailer do it 'renders email change notification' do receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.email_changed.title') + + expect(mail) + .to be_present + .and(have_body_text(I18n.t('devise.mailer.email_changed.title'))) end include_examples 'localized subject', @@ -77,8 +93,11 @@ describe UserMailer do it 'renders warning notification' do receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('user_mailer.warning.title.suspend', acct: receiver.account.acct) - expect(mail.body.encoded).to include strike.text + + expect(mail) + .to be_present + .and(have_body_text(I18n.t('user_mailer.warning.title.suspend', acct: receiver.account.acct))) + .and(have_body_text(strike.text)) end end @@ -88,7 +107,10 @@ describe UserMailer do it 'renders webauthn credential deleted notification' do receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_credential.deleted.title') + + expect(mail) + .to be_present + .and(have_body_text(I18n.t('devise.mailer.webauthn_credential.deleted.title'))) end include_examples 'localized subject', @@ -103,7 +125,10 @@ describe UserMailer do it 'renders suspicious sign in notification' do receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('user_mailer.suspicious_sign_in.explanation') + + expect(mail) + .to be_present + .and(have_body_text(I18n.t('user_mailer.suspicious_sign_in.explanation'))) end include_examples 'localized subject', @@ -115,8 +140,10 @@ describe UserMailer do let(:mail) { described_class.appeal_approved(receiver, appeal) } it 'renders appeal_approved notification' do - expect(mail.subject).to eq I18n.t('user_mailer.appeal_approved.subject', date: I18n.l(appeal.created_at)) - expect(mail.body.encoded).to include I18n.t('user_mailer.appeal_approved.title') + expect(mail) + .to be_present + .and(have_subject(I18n.t('user_mailer.appeal_approved.subject', date: I18n.l(appeal.created_at)))) + .and(have_body_text(I18n.t('user_mailer.appeal_approved.title'))) end end @@ -125,8 +152,10 @@ describe UserMailer do let(:mail) { described_class.appeal_rejected(receiver, appeal) } it 'renders appeal_rejected notification' do - expect(mail.subject).to eq I18n.t('user_mailer.appeal_rejected.subject', date: I18n.l(appeal.created_at)) - expect(mail.body.encoded).to include I18n.t('user_mailer.appeal_rejected.title') + expect(mail) + .to be_present + .and(have_subject(I18n.t('user_mailer.appeal_rejected.subject', date: I18n.l(appeal.created_at)))) + .and(have_body_text(I18n.t('user_mailer.appeal_rejected.title'))) end end @@ -134,8 +163,10 @@ describe UserMailer do let(:mail) { described_class.two_factor_enabled(receiver) } it 'renders two_factor_enabled mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.two_factor_enabled.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.two_factor_enabled.explanation') + expect(mail) + .to be_present + .and(have_subject(I18n.t('devise.mailer.two_factor_enabled.subject'))) + .and(have_body_text(I18n.t('devise.mailer.two_factor_enabled.explanation'))) end end @@ -143,8 +174,10 @@ describe UserMailer do let(:mail) { described_class.two_factor_disabled(receiver) } it 'renders two_factor_disabled mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.two_factor_disabled.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.two_factor_disabled.explanation') + expect(mail) + .to be_present + .and(have_subject(I18n.t('devise.mailer.two_factor_disabled.subject'))) + .and(have_body_text(I18n.t('devise.mailer.two_factor_disabled.explanation'))) end end @@ -152,8 +185,10 @@ describe UserMailer do let(:mail) { described_class.webauthn_enabled(receiver) } it 'renders webauthn_enabled mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.webauthn_enabled.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_enabled.explanation') + expect(mail) + .to be_present + .and(have_subject(I18n.t('devise.mailer.webauthn_enabled.subject'))) + .and(have_body_text(I18n.t('devise.mailer.webauthn_enabled.explanation'))) end end @@ -161,8 +196,10 @@ describe UserMailer do let(:mail) { described_class.webauthn_disabled(receiver) } it 'renders webauthn_disabled mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.webauthn_disabled.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_disabled.explanation') + expect(mail) + .to be_present + .and(have_subject(I18n.t('devise.mailer.webauthn_disabled.subject'))) + .and(have_body_text(I18n.t('devise.mailer.webauthn_disabled.explanation'))) end end @@ -170,8 +207,10 @@ describe UserMailer do let(:mail) { described_class.two_factor_recovery_codes_changed(receiver) } it 'renders two_factor_recovery_codes_changed mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.two_factor_recovery_codes_changed.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.two_factor_recovery_codes_changed.explanation') + expect(mail) + .to be_present + .and(have_subject(I18n.t('devise.mailer.two_factor_recovery_codes_changed.subject'))) + .and(have_body_text(I18n.t('devise.mailer.two_factor_recovery_codes_changed.explanation'))) end end @@ -180,8 +219,10 @@ describe UserMailer do let(:mail) { described_class.webauthn_credential_added(receiver, credential) } it 'renders webauthn_credential_added mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.webauthn_credential.added.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_credential.added.explanation') + expect(mail) + .to be_present + .and(have_subject(I18n.t('devise.mailer.webauthn_credential.added.subject'))) + .and(have_body_text(I18n.t('devise.mailer.webauthn_credential.added.explanation'))) end end @@ -189,8 +230,10 @@ describe UserMailer do let(:mail) { described_class.welcome(receiver) } it 'renders welcome mail' do - expect(mail.subject).to eq I18n.t('user_mailer.welcome.subject') - expect(mail.body.encoded).to include I18n.t('user_mailer.welcome.explanation') + expect(mail) + .to be_present + .and(have_subject(I18n.t('user_mailer.welcome.subject'))) + .and(have_body_text(I18n.t('user_mailer.welcome.explanation'))) end end @@ -199,8 +242,10 @@ describe UserMailer do let(:mail) { described_class.backup_ready(receiver, backup) } it 'renders backup_ready mail' do - expect(mail.subject).to eq I18n.t('user_mailer.backup_ready.subject') - expect(mail.body.encoded).to include I18n.t('user_mailer.backup_ready.explanation') + expect(mail) + .to be_present + .and(have_subject(I18n.t('user_mailer.backup_ready.subject'))) + .and(have_body_text(I18n.t('user_mailer.backup_ready.explanation'))) end end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 79f98f2e2..68023b70d 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -21,6 +21,7 @@ require 'webmock/rspec' require 'paperclip/matchers' require 'capybara/rspec' require 'chewy/rspec' +require 'email_spec/rspec' Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f } diff --git a/spec/requests/api/v1/admin/account_actions_spec.rb b/spec/requests/api/v1/admin/account_actions_spec.rb index bdf1f08e4..c14e08c21 100644 --- a/spec/requests/api/v1/admin/account_actions_spec.rb +++ b/spec/requests/api/v1/admin/account_actions_spec.rb @@ -8,18 +8,12 @@ RSpec.describe 'Account actions' do let(:scopes) { 'admin:write admin:write:accounts' } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - let(:mailer) { instance_double(ActionMailer::MessageDelivery, deliver_later!: nil) } - - before do - allow(UserMailer).to receive(:warning).with(target_account.user, anything).and_return(mailer) - end shared_examples 'a successful notification delivery' do it 'notifies the user about the action taken' do - subject - - expect(UserMailer).to have_received(:warning).with(target_account.user, anything).once - expect(mailer).to have_received(:deliver_later!).once + expect { subject } + .to have_enqueued_job(ActionMailer::MailDeliveryJob) + .with('UserMailer', 'warning', 'deliver_now!', args: [User, AccountWarning]) end end From 0e9801443f8f91ff49b47f82151ee5984c9bd6c1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko <eugen@zeonfederated.com> Date: Fri, 17 Nov 2023 11:37:04 +0100 Subject: [PATCH 064/255] Change to single opt-in during profile setup in onboarding in web UI (#27876) --- .../mastodon/features/onboarding/profile.jsx | 34 ++++++------- app/javascript/mastodon/locales/en.json | 5 +- app/javascript/styles/mastodon/forms.scss | 49 +++++++++++++++++-- 3 files changed, 64 insertions(+), 24 deletions(-) diff --git a/app/javascript/mastodon/features/onboarding/profile.jsx b/app/javascript/mastodon/features/onboarding/profile.jsx index 19ba0bcb9..09e6b2c6c 100644 --- a/app/javascript/mastodon/features/onboarding/profile.jsx +++ b/app/javascript/mastodon/features/onboarding/profile.jsx @@ -5,8 +5,8 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl'; import classNames from 'classnames'; import { useHistory } from 'react-router-dom'; -import { useDispatch } from 'react-redux'; +import { useDispatch } from 'react-redux'; import { ReactComponent as AddPhotoAlternateIcon } from '@material-symbols/svg-600/outlined/add_photo_alternate.svg'; import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.svg'; @@ -33,7 +33,6 @@ export const Profile = () => { const [avatar, setAvatar] = useState(null); const [header, setHeader] = useState(null); const [discoverable, setDiscoverable] = useState(account.get('discoverable')); - const [indexable, setIndexable] = useState(account.get('indexable')); const [isSaving, setIsSaving] = useState(false); const [errors, setErrors] = useState(); const avatarFileRef = createRef(); @@ -54,10 +53,6 @@ export const Profile = () => { setDiscoverable(e.target.checked); }, [setDiscoverable]); - const handleIndexableChange = useCallback(e => { - setIndexable(e.target.checked); - }, [setIndexable]); - const handleAvatarChange = useCallback(e => { setAvatar(e.target?.files?.[0]); }, [setAvatar]); @@ -78,12 +73,12 @@ export const Profile = () => { avatar, header, discoverable, - indexable, + indexable: discoverable, })).then(() => history.push('/start/follows')).catch(err => { setIsSaving(false); setErrors(err.response.data.details); }); - }, [dispatch, displayName, note, avatar, header, discoverable, indexable, history]); + }, [dispatch, displayName, note, avatar, header, discoverable, history]); return ( <> @@ -141,18 +136,21 @@ export const Profile = () => { <textarea id='note' value={note} onChange={handleNoteChange} maxLength={500} /> </div> </div> + + <label className='app-form__toggle'> + <div className='app-form__toggle__label'> + <strong><FormattedMessage id='onboarding.profile.discoverable' defaultMessage='Make my profile discoverable' /></strong> <span className='recommended'><FormattedMessage id='recommended' defaultMessage='Recommended' /></span> + <span className='hint'><FormattedMessage id='onboarding.profile.discoverable_hint' defaultMessage='When you opt in to discoverability on Mastodon, your posts may appear in search results and trending, and your profile may be suggested to people with similar interests to you.' /></span> + </div> + + <div className='app-form__toggle__toggle'> + <div> + <Toggle checked={discoverable} onChange={handleDiscoverableChange} /> + </div> + </div> + </label> </div> - <label className='report-dialog-modal__toggle'> - <Toggle checked={discoverable} onChange={handleDiscoverableChange} /> - <FormattedMessage id='onboarding.profile.discoverable' defaultMessage='Feature profile and posts in discovery algorithms' /> - </label> - - <label className='report-dialog-modal__toggle'> - <Toggle checked={indexable} onChange={handleIndexableChange} /> - <FormattedMessage id='onboarding.profile.indexable' defaultMessage='Include public posts in search results' /> - </label> - <div className='onboarding__footer'> <Button block onClick={handleSubmit} disabled={isSaving}>{isSaving ? <LoadingIndicator /> : <FormattedMessage id='onboarding.profile.save_and_continue' defaultMessage='Save and continue' />}</Button> </div> diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 16941e2ca..ed8bfe166 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Unfortunately, no results can be shown right now. You can try using search or browsing the explore page to find people to follow, or try again later.", "onboarding.follows.lead": "Your home feed is the primary way to experience Mastodon. The more people you follow, the more active and interesting it will be. To get you started, here are some suggestions:", "onboarding.follows.title": "Personalize your home feed", - "onboarding.profile.discoverable": "Feature profile and posts in discovery algorithms", + "onboarding.profile.discoverable": "Make my profile discoverable", + "onboarding.profile.discoverable_hint": "When you opt in to discoverability on Mastodon, your posts may appear in search results and trending, and your profile may be suggested to people with similar interests to you.", "onboarding.profile.display_name": "Display name", "onboarding.profile.display_name_hint": "Your full name or your fun name…", - "onboarding.profile.indexable": "Include public posts in search results", "onboarding.profile.lead": "You can always complete this later in the settings, where even more customization options are available.", "onboarding.profile.note": "Bio", "onboarding.profile.note_hint": "You can @mention other people or #hashtags…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Unlisted", "privacy_policy.last_updated": "Last updated {date}", "privacy_policy.title": "Privacy Policy", + "recommended": "Recommended", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index e72a01936..555d43cc1 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -1222,10 +1222,6 @@ code { } .app-form { - & > * { - margin-bottom: 16px; - } - &__avatar-input, &__header-input { display: block; @@ -1290,4 +1286,49 @@ code { &__header-input { aspect-ratio: 580/193; } + + &__toggle { + display: flex; + align-items: center; + gap: 16px; + color: $darker-text-color; + font-size: 14px; + line-height: 20px; + + .icon { + flex: 0 0 auto; + } + + .icon { + width: 24px; + height: 24px; + } + + &__label { + flex: 1 1 auto; + + strong { + color: $primary-text-color; + font-weight: 600; + } + + .recommended { + position: absolute; + margin: 0 4px; + margin-top: -2px; + } + } + + &__toggle { + flex: 0 0 auto; + display: flex; + align-items: center; + } + + &__toggle > div { + display: flex; + border-inline-start: 1px solid lighten($ui-base-color, 8%); + padding-inline-start: 16px; + } + } } From 92577376750f560064593bff10206da0080340b2 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Fri, 17 Nov 2023 12:34:49 +0100 Subject: [PATCH 065/255] Rewrite `/api/v1/accounts` tests as request specs (#27888) --- spec/requests/api/v1/accounts_show_spec.rb | 53 ----- .../api/v1/accounts_spec.rb} | 189 +++++++++++++----- 2 files changed, 136 insertions(+), 106 deletions(-) delete mode 100644 spec/requests/api/v1/accounts_show_spec.rb rename spec/{controllers/api/v1/accounts_controller_spec.rb => requests/api/v1/accounts_spec.rb} (59%) diff --git a/spec/requests/api/v1/accounts_show_spec.rb b/spec/requests/api/v1/accounts_show_spec.rb deleted file mode 100644 index ee6e925aa..000000000 --- a/spec/requests/api/v1/accounts_show_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'GET /api/v1/accounts/{account_id}' do - it 'returns account entity as 200 OK' do - account = Fabricate(:account) - - get "/api/v1/accounts/#{account.id}" - - aggregate_failures do - expect(response).to have_http_status(200) - expect(body_as_json[:id]).to eq(account.id.to_s) - end - end - - it 'returns 404 if account not found' do - get '/api/v1/accounts/1' - - aggregate_failures do - expect(response).to have_http_status(404) - expect(body_as_json[:error]).to eq('Record not found') - end - end - - context 'when with token' do - it 'returns account entity as 200 OK if token is valid' do - account = Fabricate(:account) - user = Fabricate(:user, account: account) - token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts').token - - get "/api/v1/accounts/#{account.id}", headers: { Authorization: "Bearer #{token}" } - - aggregate_failures do - expect(response).to have_http_status(200) - expect(body_as_json[:id]).to eq(account.id.to_s) - end - end - - it 'returns 403 if scope of token is invalid' do - account = Fabricate(:account) - user = Fabricate(:user, account: account) - token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:statuses').token - - get "/api/v1/accounts/#{account.id}", headers: { Authorization: "Bearer #{token}" } - - aggregate_failures do - expect(response).to have_http_status(403) - expect(body_as_json[:error]).to eq('This action is outside the authorized scopes') - end - end - end -end diff --git a/spec/controllers/api/v1/accounts_controller_spec.rb b/spec/requests/api/v1/accounts_spec.rb similarity index 59% rename from spec/controllers/api/v1/accounts_controller_spec.rb rename to spec/requests/api/v1/accounts_spec.rb index 9d0bb73c7..e543c4136 100644 --- a/spec/controllers/api/v1/accounts_controller_spec.rb +++ b/spec/requests/api/v1/accounts_spec.rb @@ -2,59 +2,100 @@ require 'rails_helper' -RSpec.describe Api::V1::AccountsController do - render_views +describe '/api/v1/accounts' do + let(:user) { Fabricate(:user) } + let(:scopes) { '' } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - let(:user) { Fabricate(:user) } - let(:scopes) { '' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + describe 'GET /api/v1/accounts/:id' do + context 'when logged out' do + let(:account) { Fabricate(:account) } - before do - allow(controller).to receive(:doorkeeper_token) { token } + it 'returns account entity as 200 OK', :aggregate_failures do + get "/api/v1/accounts/#{account.id}" + + expect(response).to have_http_status(200) + expect(body_as_json[:id]).to eq(account.id.to_s) + end + end + + context 'when the account does not exist' do + it 'returns http not found' do + get '/api/v1/accounts/1' + + expect(response).to have_http_status(404) + expect(body_as_json[:error]).to eq('Record not found') + end + end + + context 'when logged in' do + subject do + get "/api/v1/accounts/#{account.id}", headers: headers + end + + let(:account) { Fabricate(:account) } + let(:scopes) { 'read:accounts' } + + it 'returns account entity as 200 OK', :aggregate_failures do + subject + + expect(response).to have_http_status(200) + expect(body_as_json[:id]).to eq(account.id.to_s) + end + + it_behaves_like 'forbidden for wrong scope', 'write:statuses' + end end - describe 'POST #create' do - let(:app) { Fabricate(:application) } - let(:token) { Doorkeeper::AccessToken.find_or_create_for(application: app, resource_owner: nil, scopes: 'read write', use_refresh_token: false) } - let(:agreement) { nil } - - before do - post :create, params: { username: 'test', password: '12345678', email: 'hello@world.tld', agreement: agreement } + describe 'POST /api/v1/accounts' do + subject do + post '/api/v1/accounts', headers: headers, params: { username: 'test', password: '12345678', email: 'hello@world.tld', agreement: agreement } end + let(:client_app) { Fabricate(:application) } + let(:token) { Doorkeeper::AccessToken.find_or_create_for(application: client_app, resource_owner: nil, scopes: 'read write', use_refresh_token: false) } + let(:agreement) { nil } + context 'when given truthy agreement' do let(:agreement) { 'true' } it 'creates a user', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(body_as_json[:access_token]).to_not be_blank user = User.find_by(email: 'hello@world.tld') expect(user).to_not be_nil - expect(user.created_by_application_id).to eq app.id + expect(user.created_by_application_id).to eq client_app.id end end context 'when given no agreement' do it 'returns http unprocessable entity' do + subject + expect(response).to have_http_status(422) end end end - describe 'POST #follow' do + describe 'POST /api/v1/accounts/:id/follow' do let(:scopes) { 'write:follows' } let(:other_account) { Fabricate(:account, username: 'bob', locked: locked) } context 'when posting to an other account' do - before do - post :follow, params: { id: other_account.id } + subject do + post "/api/v1/accounts/#{other_account.id}/follow", headers: headers end context 'with unlocked account' do let(:locked) { false } it 'creates a following relation between user and target user', :aggregate_failures do + subject + expect(response).to have_http_status(200) json = body_as_json @@ -72,6 +113,8 @@ RSpec.describe Api::V1::AccountsController do let(:locked) { true } it 'creates a follow request relation between user and target user', :aggregate_failures do + subject + expect(response).to have_http_status(200) json = body_as_json @@ -94,48 +137,53 @@ RSpec.describe Api::V1::AccountsController do end it 'changes reblogs option' do - post :follow, params: { id: other_account.id, reblogs: true } + post "/api/v1/accounts/#{other_account.id}/follow", headers: headers, params: { reblogs: true } - json = body_as_json - - expect(json[:following]).to be true - expect(json[:showing_reblogs]).to be true - expect(json[:notifying]).to be false + expect(body_as_json).to include({ + following: true, + showing_reblogs: true, + notifying: false, + }) end it 'changes notify option' do - post :follow, params: { id: other_account.id, notify: true } + post "/api/v1/accounts/#{other_account.id}/follow", headers: headers, params: { notify: true } - json = body_as_json - - expect(json[:following]).to be true - expect(json[:showing_reblogs]).to be false - expect(json[:notifying]).to be true + expect(body_as_json).to include({ + following: true, + showing_reblogs: false, + notifying: true, + }) end it 'changes languages option' do - post :follow, params: { id: other_account.id, languages: %w(en es) } + post "/api/v1/accounts/#{other_account.id}/follow", headers: headers, params: { languages: %w(en es) } - json = body_as_json - - expect(json[:following]).to be true - expect(json[:showing_reblogs]).to be false - expect(json[:notifying]).to be false - expect(json[:languages]).to match_array %w(en es) + expect(body_as_json).to include({ + following: true, + showing_reblogs: false, + notifying: false, + languages: match_array(%w(en es)), + }) end end end - describe 'POST #unfollow' do + describe 'POST /api/v1/accounts/:id/unfollow' do + subject do + post "/api/v1/accounts/#{other_account.id}/unfollow", headers: headers + end + let(:scopes) { 'write:follows' } let(:other_account) { Fabricate(:account, username: 'bob') } before do user.account.follow!(other_account) - post :unfollow, params: { id: other_account.id } end it 'removes the following relation between user and target user', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(user.account.following?(other_account)).to be false end @@ -143,16 +191,21 @@ RSpec.describe Api::V1::AccountsController do it_behaves_like 'forbidden for wrong scope', 'read:accounts' end - describe 'POST #remove_from_followers' do + describe 'POST /api/v1/accounts/:id/remove_from_followers' do + subject do + post "/api/v1/accounts/#{other_account.id}/remove_from_followers", headers: headers + end + let(:scopes) { 'write:follows' } let(:other_account) { Fabricate(:account, username: 'bob') } before do other_account.follow!(user.account) - post :remove_from_followers, params: { id: other_account.id } end it 'removes the followed relation between user and target user', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(user.account.followed_by?(other_account)).to be false end @@ -160,16 +213,21 @@ RSpec.describe Api::V1::AccountsController do it_behaves_like 'forbidden for wrong scope', 'read:accounts' end - describe 'POST #block' do + describe 'POST /api/v1/accounts/:id/block' do + subject do + post "/api/v1/accounts/#{other_account.id}/block", headers: headers + end + let(:scopes) { 'write:blocks' } let(:other_account) { Fabricate(:account, username: 'bob') } before do user.account.follow!(other_account) - post :block, params: { id: other_account.id } end it 'creates a blocking relation', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(user.account.following?(other_account)).to be false expect(user.account.blocking?(other_account)).to be true @@ -178,16 +236,21 @@ RSpec.describe Api::V1::AccountsController do it_behaves_like 'forbidden for wrong scope', 'read:accounts' end - describe 'POST #unblock' do + describe 'POST /api/v1/accounts/:id/unblock' do + subject do + post "/api/v1/accounts/#{other_account.id}/unblock", headers: headers + end + let(:scopes) { 'write:blocks' } let(:other_account) { Fabricate(:account, username: 'bob') } before do user.account.block!(other_account) - post :unblock, params: { id: other_account.id } end it 'removes the blocking relation between user and target user', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(user.account.blocking?(other_account)).to be false end @@ -195,16 +258,21 @@ RSpec.describe Api::V1::AccountsController do it_behaves_like 'forbidden for wrong scope', 'read:accounts' end - describe 'POST #mute' do + describe 'POST /api/v1/accounts/:id/mute' do + subject do + post "/api/v1/accounts/#{other_account.id}/mute", headers: headers + end + let(:scopes) { 'write:mutes' } let(:other_account) { Fabricate(:account, username: 'bob') } before do user.account.follow!(other_account) - post :mute, params: { id: other_account.id } end it 'mutes notifications', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(user.account.following?(other_account)).to be true expect(user.account.muting?(other_account)).to be true @@ -214,16 +282,21 @@ RSpec.describe Api::V1::AccountsController do it_behaves_like 'forbidden for wrong scope', 'read:accounts' end - describe 'POST #mute with notifications set to false' do + describe 'POST /api/v1/accounts/:id/mute with notifications set to false' do + subject do + post "/api/v1/accounts/#{other_account.id}/mute", headers: headers, params: { notifications: false } + end + let(:scopes) { 'write:mutes' } let(:other_account) { Fabricate(:account, username: 'bob') } before do user.account.follow!(other_account) - post :mute, params: { id: other_account.id, notifications: false } end it 'does not mute notifications', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(user.account.following?(other_account)).to be true expect(user.account.muting?(other_account)).to be true @@ -233,16 +306,21 @@ RSpec.describe Api::V1::AccountsController do it_behaves_like 'forbidden for wrong scope', 'read:accounts' end - describe 'POST #mute with nonzero duration set' do + describe 'POST /api/v1/accounts/:id/mute with nonzero duration set' do + subject do + post "/api/v1/accounts/#{other_account.id}/mute", headers: headers, params: { duration: 300 } + end + let(:scopes) { 'write:mutes' } let(:other_account) { Fabricate(:account, username: 'bob') } before do user.account.follow!(other_account) - post :mute, params: { id: other_account.id, duration: 300 } end it 'mutes notifications', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(user.account.following?(other_account)).to be true expect(user.account.muting?(other_account)).to be true @@ -252,16 +330,21 @@ RSpec.describe Api::V1::AccountsController do it_behaves_like 'forbidden for wrong scope', 'read:accounts' end - describe 'POST #unmute' do + describe 'POST /api/v1/accounts/:id/unmute' do + subject do + post "/api/v1/accounts/#{other_account.id}/unmute", headers: headers + end + let(:scopes) { 'write:mutes' } let(:other_account) { Fabricate(:account, username: 'bob') } before do user.account.mute!(other_account) - post :unmute, params: { id: other_account.id } end it 'removes the muting relation between user and target user', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(user.account.muting?(other_account)).to be false end From 297839c10c121505dcce421f19d41146171193c7 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Fri, 17 Nov 2023 12:36:04 +0100 Subject: [PATCH 066/255] Rewrite `/api/v1/statuses` tests as request specs (#27891) --- .../api/v1/statuses_spec.rb} | 132 ++++++++++-------- 1 file changed, 73 insertions(+), 59 deletions(-) rename spec/{controllers/api/v1/statuses_controller_spec.rb => requests/api/v1/statuses_spec.rb} (69%) diff --git a/spec/controllers/api/v1/statuses_controller_spec.rb b/spec/requests/api/v1/statuses_spec.rb similarity index 69% rename from spec/controllers/api/v1/statuses_controller_spec.rb rename to spec/requests/api/v1/statuses_spec.rb index 30bafe19a..1b2dd2b5d 100644 --- a/spec/controllers/api/v1/statuses_controller_spec.rb +++ b/spec/requests/api/v1/statuses_spec.rb @@ -2,24 +2,26 @@ require 'rails_helper' -RSpec.describe Api::V1::StatusesController do - render_views - - let(:user) { Fabricate(:user) } - let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: scopes) } - +describe '/api/v1/statuses' do context 'with an oauth token' do - before do - allow(controller).to receive(:doorkeeper_token) { token } - end + let(:user) { Fabricate(:user) } + let(:client_app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: client_app, scopes: scopes) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + describe 'GET /api/v1/statuses/:id' do + subject do + get "/api/v1/statuses/#{status.id}", headers: headers + end - describe 'GET #show' do let(:scopes) { 'read:statuses' } let(:status) { Fabricate(:status, account: user.account) } + it_behaves_like 'forbidden for wrong scope', 'write write:statuses' + it 'returns http success' do - get :show, params: { id: status.id } + subject + expect(response).to have_http_status(200) end @@ -31,11 +33,10 @@ RSpec.describe Api::V1::StatusesController do end it 'returns filter information', :aggregate_failures do - get :show, params: { id: status.id } - json = body_as_json + subject expect(response).to have_http_status(200) - expect(json[:filtered][0]).to include({ + expect(body_as_json[:filtered][0]).to include({ filter: a_hash_including({ id: user.account.custom_filters.first.id.to_s, title: 'filter1', @@ -55,11 +56,10 @@ RSpec.describe Api::V1::StatusesController do end it 'returns filter information', :aggregate_failures do - get :show, params: { id: status.id } - json = body_as_json + subject expect(response).to have_http_status(200) - expect(json[:filtered][0]).to include({ + expect(body_as_json[:filtered][0]).to include({ filter: a_hash_including({ id: user.account.custom_filters.first.id.to_s, title: 'filter1', @@ -78,11 +78,10 @@ RSpec.describe Api::V1::StatusesController do end it 'returns filter information', :aggregate_failures do - get :show, params: { id: status.id } - json = body_as_json + subject expect(response).to have_http_status(200) - expect(json[:reblog][:filtered][0]).to include({ + expect(body_as_json[:reblog][:filtered][0]).to include({ filter: a_hash_including({ id: user.account.custom_filters.first.id.to_s, title: 'filter1', @@ -94,7 +93,7 @@ RSpec.describe Api::V1::StatusesController do end end - describe 'GET #context' do + describe 'GET /api/v1/statuses/:id/context' do let(:scopes) { 'read:statuses' } let(:status) { Fabricate(:status, account: user.account) } @@ -103,20 +102,26 @@ RSpec.describe Api::V1::StatusesController do end it 'returns http success' do - get :context, params: { id: status.id } + get "/api/v1/statuses/#{status.id}/context", headers: headers + expect(response).to have_http_status(200) end end - describe 'POST #create' do + describe 'POST /api/v1/statuses' do + subject do + post '/api/v1/statuses', headers: headers, params: params + end + let(:scopes) { 'write:statuses' } + let(:params) { { status: 'Hello world' } } + + it_behaves_like 'forbidden for wrong scope', 'read read:statuses' context 'with a basic status body' do - before do - post :create, params: { status: 'Hello world' } - end - it 'returns rate limit headers', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s expect(response.headers['X-RateLimit-Remaining']).to eq (RateLimiter::FAMILIES[:statuses][:limit] - 1).to_s @@ -127,22 +132,22 @@ RSpec.describe Api::V1::StatusesController do let!(:alice) { Fabricate(:account, username: 'alice') } let!(:bob) { Fabricate(:account, username: 'bob') } - before do - post :create, params: { status: '@alice hm, @bob is really annoying lately', allowed_mentions: [alice.id] } - end + let(:params) { { status: '@alice hm, @bob is really annoying lately', allowed_mentions: [alice.id] } } it 'returns serialized extra accounts in body', :aggregate_failures do + subject + expect(response).to have_http_status(422) expect(body_as_json[:unexpected_accounts].map { |a| a.slice(:id, :acct) }).to eq [{ id: bob.id.to_s, acct: bob.acct }] end end context 'with missing parameters' do - before do - post :create, params: {} - end + let(:params) { {} } it 'returns rate limit headers', :aggregate_failures do + subject + expect(response).to have_http_status(422) expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s end @@ -152,10 +157,11 @@ RSpec.describe Api::V1::StatusesController do before do rate_limiter = RateLimiter.new(user.account, family: :statuses) 300.times { rate_limiter.record! } - post :create, params: { status: 'Hello world' } end it 'returns rate limit headers', :aggregate_failures do + subject + expect(response).to have_http_status(429) expect(response.headers['X-RateLimit-Limit']).to eq RateLimiter::FAMILIES[:statuses][:limit].to_s expect(response.headers['X-RateLimit-Remaining']).to eq '0' @@ -163,29 +169,37 @@ RSpec.describe Api::V1::StatusesController do end end - describe 'DELETE #destroy' do + describe 'DELETE /api/v1/statuses/:id' do + subject do + delete "/api/v1/statuses/#{status.id}", headers: headers + end + let(:scopes) { 'write:statuses' } let(:status) { Fabricate(:status, account: user.account) } - before do - post :destroy, params: { id: status.id } - end + it_behaves_like 'forbidden for wrong scope', 'read read:statuses' it 'removes the status', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(Status.find_by(id: status.id)).to be_nil end end - describe 'PUT #update' do + describe 'PUT /api/v1/statuses/:id' do + subject do + put "/api/v1/statuses/#{status.id}", headers: headers, params: { status: 'I am updated' } + end + let(:scopes) { 'write:statuses' } let(:status) { Fabricate(:status, account: user.account) } - before do - put :update, params: { id: status.id, status: 'I am updated' } - end + it_behaves_like 'forbidden for wrong scope', 'read read:statuses' it 'updates the status', :aggregate_failures do + subject + expect(response).to have_http_status(200) expect(status.reload.text).to eq 'I am updated' end @@ -193,49 +207,49 @@ RSpec.describe Api::V1::StatusesController do end context 'without an oauth token' do - before do - allow(controller).to receive(:doorkeeper_token).and_return(nil) - end - context 'with a private status' do - let(:status) { Fabricate(:status, account: user.account, visibility: :private) } + let(:status) { Fabricate(:status, visibility: :private) } - describe 'GET #show' do + describe 'GET /api/v1/statuses/:id' do it 'returns http unauthorized' do - get :show, params: { id: status.id } + get "/api/v1/statuses/#{status.id}" + expect(response).to have_http_status(404) end end - describe 'GET #context' do + describe 'GET /api/v1/statuses/:id/context' do before do - Fabricate(:status, account: user.account, thread: status) + Fabricate(:status, thread: status) end it 'returns http unauthorized' do - get :context, params: { id: status.id } + get "/api/v1/statuses/#{status.id}/context" + expect(response).to have_http_status(404) end end end context 'with a public status' do - let(:status) { Fabricate(:status, account: user.account, visibility: :public) } + let(:status) { Fabricate(:status, visibility: :public) } - describe 'GET #show' do + describe 'GET /api/v1/statuses/:id' do it 'returns http success' do - get :show, params: { id: status.id } + get "/api/v1/statuses/#{status.id}" + expect(response).to have_http_status(200) end end - describe 'GET #context' do + describe 'GET /api/v1/statuses/:id/context' do before do - Fabricate(:status, account: user.account, thread: status) + Fabricate(:status, thread: status) end it 'returns http success' do - get :context, params: { id: status.id } + get "/api/v1/statuses/#{status.id}/context" + expect(response).to have_http_status(200) end end From e892efbc4081129fbe807d3b6d8dec024e2175ed Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 17 Nov 2023 06:52:20 -0500 Subject: [PATCH 067/255] Configure elastic search integration with rspec tag (#27882) --- .github/workflows/test-ruby.yml | 4 ++-- lib/tasks/spec.rake | 10 ---------- spec/rails_helper.rb | 13 ++++++++++--- spec/support/search_data_manager.rb | 4 ++-- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 101de66ac..ae25648a0 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -227,7 +227,7 @@ jobs: path: tmp/screenshots/ test-search: - name: Testing search + name: Elastic Search integration testing runs-on: ubuntu-latest needs: @@ -314,7 +314,7 @@ jobs: - name: Load database schema run: './bin/rails db:create db:schema:load db:seed' - - run: bundle exec rake spec:search + - run: bin/rspec --tag search - name: Archive logs uses: actions/upload-artifact@v3 diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake index ec4cd39bf..8f2cbeea3 100644 --- a/lib/tasks/spec.rake +++ b/lib/tasks/spec.rake @@ -9,13 +9,3 @@ if Rake::Task.task_defined?('spec:system') Rake::Task['spec:system'].enhance ['spec:enable_system_specs'] end - -if Rake::Task.task_defined?('spec:search') - namespace :spec do - task :enable_search_specs do # rubocop:disable Rails/RakeEnvironment - ENV['RUN_SEARCH_SPECS'] = 'true' - end - end - - Rake::Task['spec:search'].enhance ['spec:enable_search_specs'] -end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 68023b70d..7deab6c7f 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -4,7 +4,6 @@ ENV['RAILS_ENV'] ||= 'test' # This needs to be defined before Rails is initialized RUN_SYSTEM_SPECS = ENV.fetch('RUN_SYSTEM_SPECS', false) -RUN_SEARCH_SPECS = ENV.fetch('RUN_SEARCH_SPECS', false) if RUN_SYSTEM_SPECS STREAMING_PORT = ENV.fetch('TEST_STREAMING_PORT', '4020') @@ -55,20 +54,28 @@ RSpec.configure do |config| case type when :system !RUN_SYSTEM_SPECS - when :search - !RUN_SEARCH_SPECS end } + + # By default, skip the elastic search integration specs + config.filter_run_excluding search: true + config.fixture_path = Rails.root.join('spec', 'fixtures') config.use_transactional_fixtures = true config.order = 'random' config.infer_spec_type_from_file_location! config.filter_rails_from_backtrace! + # Set type to `cli` for all CLI specs config.define_derived_metadata(file_path: Regexp.new('spec/lib/mastodon/cli')) do |metadata| metadata[:type] = :cli end + # Set `search` metadata true for all specs in spec/search/ + config.define_derived_metadata(file_path: Regexp.new('spec/search/*')) do |metadata| + metadata[:search] = true + end + config.include Devise::Test::ControllerHelpers, type: :controller config.include Devise::Test::ControllerHelpers, type: :helper config.include Devise::Test::ControllerHelpers, type: :view diff --git a/spec/support/search_data_manager.rb b/spec/support/search_data_manager.rb index 176a674ad..3c7140b48 100644 --- a/spec/support/search_data_manager.rb +++ b/spec/support/search_data_manager.rb @@ -60,7 +60,7 @@ RSpec.configure do |config| end end - config.around :each, type: :search do |example| + config.around :each, :search do |example| search_data_manager.populate_indexes example.run search_data_manager.remove_indexes @@ -73,6 +73,6 @@ RSpec.configure do |config| end def search_examples_present? - RUN_SEARCH_SPECS + RSpec.world.filtered_examples.values.flatten.any? { |example| example.metadata[:search] == true } end end From 60f143e41f4b5d8157a54042c29af08a612249a2 Mon Sep 17 00:00:00 2001 From: Tim Campbell <timetinytim@gmail.com> Date: Sat, 18 Nov 2023 02:14:51 -0800 Subject: [PATCH 068/255] Fixed yarn not installing node packages for streaming (#27967) --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 2b23ea6e4..7e032073b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,6 +38,7 @@ RUN apt-get update && \ corepack enable COPY Gemfile* package.json yarn.lock .yarnrc.yml /opt/mastodon/ +COPY streaming/package.json /opt/mastodon/streaming/ COPY .yarn /opt/mastodon/.yarn RUN bundle install -j"$(nproc)" From 6d60b936adaf61f548e09fe01590ab7a8554da92 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:44:36 +0100 Subject: [PATCH 069/255] Update devDependencies (non-major) (#27992) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 864ebfc87..2db721073 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1777,8 +1777,8 @@ __metadata: linkType: hard "@formatjs/cli@npm:^6.1.1": - version: 6.2.3 - resolution: "@formatjs/cli@npm:6.2.3" + version: 6.2.4 + resolution: "@formatjs/cli@npm:6.2.4" peerDependencies: vue: ^3.3.4 peerDependenciesMeta: @@ -1786,7 +1786,7 @@ __metadata: optional: true bin: formatjs: bin/formatjs - checksum: 91eada7676333e2e647cbfbf9c0da88e4ca52e7b486dca73a7299594b0b0dea99de00e1b4110fac993633feb4bf5f26c97885b1a870dfd0ef95688d7f3234a03 + checksum: 3f6bbbc633a3a6ebd4e6fcfc3a9f889bc044043452cbc8f81abcaee97aaef991a778ae785d3b9d21ecc5f55b147eb0009b44520bb895fe244b4c14a36d9b05bd languageName: node linkType: hard @@ -2978,8 +2978,8 @@ __metadata: linkType: hard "@testing-library/react@npm:^14.0.0": - version: 14.1.0 - resolution: "@testing-library/react@npm:14.1.0" + version: 14.1.2 + resolution: "@testing-library/react@npm:14.1.2" dependencies: "@babel/runtime": "npm:^7.12.5" "@testing-library/dom": "npm:^9.0.0" @@ -2987,7 +2987,7 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 357ad80b11bdd4b6d10d2fb1bf86d5b39fb457cf09293033cf42bcc7a95738a86a2b12b760ae15bad326da0b9c074ca015d2bbf0baae7da38fdbc7c808925820 + checksum: b5b0990d3aa0ea8b37c55804e0d5d584fc638a5c7d4df90da9a0fdb00bc981b27b6991468b2dc719982a5d0b0107a41596063ce51ad519eeab47b22bc04d6779 languageName: node linkType: hard From d75c7ac5a806765364dd83d0e61ddb00b13590da Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 08:46:00 +0000 Subject: [PATCH 070/255] Update dependency core-js to v3.33.3 (#27980) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 2db721073..20af86e1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5999,9 +5999,9 @@ __metadata: linkType: hard "core-js@npm:^3.30.2": - version: 3.33.2 - resolution: "core-js@npm:3.33.2" - checksum: d6a56ad3e134846c805ce936788dd58cb51e861f173ed1f830979735d7865ea6f6a5a437076c36c8d8b842ba0384d052998f160774a8da7712f0f51df60167fe + version: 3.33.3 + resolution: "core-js@npm:3.33.3" + checksum: 08abdc9470c8228b9d09f61e62ab312738681202c4c34e9638889125b304b235f34c4fe22e9d41c20906ac0fcc807dca57c5ff7d6b90021bf64e8fe23461d9ab languageName: node linkType: hard From 135c4d8250d661439b6a8dd3fc51d30d00bacdf4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 08:46:18 +0000 Subject: [PATCH 071/255] Update dependency rubocop-rails to v2.22.2 (#27975) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index beec8b39c..06088de54 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -673,10 +673,11 @@ GEM rubocop-performance (1.19.1) rubocop (>= 1.7.0, < 2.0) rubocop-ast (>= 0.4.0) - rubocop-rails (2.22.1) + rubocop-rails (2.22.2) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) + rubocop-ast (>= 1.30.0, < 2.0) rubocop-rspec (2.25.0) rubocop (~> 1.40) rubocop-capybara (~> 2.17) From 8ceae2bce6b85494f37506bd36127925e70e1279 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:47:34 +0100 Subject: [PATCH 072/255] New Crowdin Translations (automated) (#27966) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/ast.json | 11 + app/javascript/mastodon/locales/be.json | 5 +- app/javascript/mastodon/locales/bg.json | 2 - app/javascript/mastodon/locales/cy.json | 1 + app/javascript/mastodon/locales/da.json | 5 +- app/javascript/mastodon/locales/de.json | 5 +- app/javascript/mastodon/locales/el.json | 13 +- app/javascript/mastodon/locales/en-GB.json | 2 - app/javascript/mastodon/locales/eo.json | 2 + app/javascript/mastodon/locales/es-AR.json | 5 +- app/javascript/mastodon/locales/es-MX.json | 5 +- app/javascript/mastodon/locales/es.json | 7 +- app/javascript/mastodon/locales/eu.json | 5 +- app/javascript/mastodon/locales/fa.json | 3 +- app/javascript/mastodon/locales/fi.json | 11 +- app/javascript/mastodon/locales/fo.json | 5 + app/javascript/mastodon/locales/fr-QC.json | 5 +- app/javascript/mastodon/locales/fr.json | 5 +- app/javascript/mastodon/locales/gl.json | 7 +- app/javascript/mastodon/locales/he.json | 13 +- app/javascript/mastodon/locales/hi.json | 3 + app/javascript/mastodon/locales/hr.json | 5 + app/javascript/mastodon/locales/hu.json | 5 +- app/javascript/mastodon/locales/is.json | 5 +- app/javascript/mastodon/locales/it.json | 5 +- app/javascript/mastodon/locales/ja.json | 14 ++ app/javascript/mastodon/locales/ko.json | 6 +- app/javascript/mastodon/locales/lt.json | 259 +++++++++++++++++++-- app/javascript/mastodon/locales/nl.json | 5 +- app/javascript/mastodon/locales/nn.json | 2 - app/javascript/mastodon/locales/no.json | 2 - app/javascript/mastodon/locales/pl.json | 5 +- app/javascript/mastodon/locales/pt-BR.json | 15 ++ app/javascript/mastodon/locales/pt-PT.json | 5 +- app/javascript/mastodon/locales/sk.json | 4 + app/javascript/mastodon/locales/sl.json | 15 ++ app/javascript/mastodon/locales/sq.json | 5 +- app/javascript/mastodon/locales/sr.json | 12 + app/javascript/mastodon/locales/sv.json | 4 +- app/javascript/mastodon/locales/th.json | 9 +- app/javascript/mastodon/locales/tr.json | 7 +- app/javascript/mastodon/locales/uk.json | 5 +- app/javascript/mastodon/locales/vi.json | 15 ++ app/javascript/mastodon/locales/zh-CN.json | 5 +- app/javascript/mastodon/locales/zh-HK.json | 5 +- app/javascript/mastodon/locales/zh-TW.json | 5 +- config/locales/bg.yml | 1 + config/locales/devise.lt.yml | 34 +++ config/locales/eo.yml | 4 + config/locales/gl.yml | 4 +- config/locales/he.yml | 12 +- config/locales/hr.yml | 33 +++ config/locales/ja.yml | 2 + config/locales/pt-BR.yml | 1 + config/locales/simple_form.gl.yml | 8 +- config/locales/simple_form.he.yml | 4 +- config/locales/simple_form.hr.yml | 6 + config/locales/sl.yml | 1 + config/locales/sr-Latn.yml | 1 + config/locales/th.yml | 2 +- config/locales/vi.yml | 1 + 61 files changed, 552 insertions(+), 106 deletions(-) diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json index 0d49d9a19..98f622c29 100644 --- a/app/javascript/mastodon/locales/ast.json +++ b/app/javascript/mastodon/locales/ast.json @@ -13,27 +13,38 @@ "about.rules": "Normes del sirvidor", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Amestar o quitar de les llistes", + "account.badges.bot": "Automatizáu", "account.badges.group": "Grupu", "account.block": "Bloquiar a @{name}", "account.block_domain": "Bloquiar el dominiu {domain}", + "account.block_short": "Bloquiar", "account.blocked": "Perfil bloquiáu", "account.browse_more_on_origin_server": "Restolar más nel perfil orixinal", + "account.cancel_follow_request": "Atayar siguimientu", + "account.copy": "Copiar I'enllaz al perfil", "account.direct": "Mentar a @{name} per privao", "account.disable_notifications": "Dexar d'avisame cuando @{name} espublice artículos", "account.domain_blocked": "Dominiu bloquiáu", "account.edit_profile": "Editar el perfil", "account.enable_notifications": "Avisame cuando @{name} espublice artículos", "account.endorse": "Destacar nel perfil", + "account.featured_tags.last_status_at": "Últimu estáu en {date}", + "account.featured_tags.last_status_never": "Sin estaos", "account.featured_tags.title": "Etiquetes destacaes de: {name}", "account.follow": "Siguir", "account.followers": "Siguidores", "account.followers.empty": "Naide sigue a esti perfil.", + "account.followers_counter": "{count, plural, one {{counter} Siguíu} other {{counter} Siguíos}}", + "account.following": "Siguiendo", "account.following_counter": "{count, plural,one {Sigue a {counter}} other {Sigue a {counter}}}", "account.follows.empty": "Esti perfil nun sigue a naide.", "account.follows_you": "Síguete", + "account.go_to_profile": "Dir al perfil", "account.hide_reblogs": "Anubrir los artículos compartíos de @{name}", "account.in_memoriam": "N'alcordanza.", "account.joined_short": "Data de xunión", + "account.languages": "Camudar llingües suscrites", + "account.link_verified_on": "La propiedá d'esti enllaz foi comprobada'l {date}", "account.media": "Multimedia", "account.mention": "Mentar a @{name}", "account.moved_to": "{name} indicó qu'agora la so cuenta nueva ye:", diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 59b1ca50b..06a329a8b 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "На жаль, зараз немагчыма паказаць вынікі. Вы можаце паспрабаваць выкарыстоўваць пошук і праглядзець старонку агляду, каб знайсці людзей, на якіх можна падпісацца, або паўтарыце спробу пазней.", "onboarding.follows.lead": "Вы самі ствараеце свой хатні канал. Чым больш людзей вы падпішаце, тым больш актыўна і цікавей гэта будзе. Гэтыя профілі могуць стаць добрай адпраўной кропкай — вы заўсёды можаце адмяніць падпіску на іх пазней!", "onboarding.follows.title": "Папулярна на Mastodon", - "onboarding.profile.discoverable": "Уключыць профіль і допісы ў алгарытмы рэкамендацый", + "onboarding.profile.discoverable": "Зрабіць мой профіль бачным", + "onboarding.profile.discoverable_hint": "Калі вы звяртаецеся да адкрытасці на Mastodon, вашы паведамленні могуць з'яўляцца ў выніках пошуку і тэндэнцый, а ваш профіль можа быць прапанаваны людзям з такімі ж інтарэсамі.", "onboarding.profile.display_name": "Бачнае імя", "onboarding.profile.display_name_hint": "Ваша поўнае імя або ваш псеўданім…", - "onboarding.profile.indexable": "Індэксаваць публічныя допісы ў пошукавых сістэмах", "onboarding.profile.lead": "Вы заўсёды можаце выканаць гэта пазней у Наладах, дзе даступна яшчэ больш параметраў.", "onboarding.profile.note": "Біяграфія", "onboarding.profile.note_hint": "Вы можаце @згадаць іншых людзей або выкарыстоўваць #хэштэгі…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Не ў стужках", "privacy_policy.last_updated": "Адноўлена {date}", "privacy_policy.title": "Палітыка канфідэнцыйнасці", + "recommended": "Рэкамендуем", "refresh": "Абнавiць", "regeneration_indicator.label": "Загрузка…", "regeneration_indicator.sublabel": "Пачакайце, рыхтуем вашу стужку!", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index b30dfecaa..339ba6011 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -479,10 +479,8 @@ "onboarding.follows.empty": "За съжаление, в момента не могат да се показват резултати. Може да опитате да употребявате търсене или да прегледате страницата за изследване, за да намерите страница за последване, или да опитате пак по-късно.", "onboarding.follows.lead": "Може да бъдете куратор на началния си инфоканал. Последвайки повече хора, по-деен и по-интересен ще става. Тези профили може да са добра начална точка, от която винаги по-късно да спрете да следвате!", "onboarding.follows.title": "Популярно в Mastodon", - "onboarding.profile.discoverable": "Включване на профила и публикации в алгоритмите за откриване", "onboarding.profile.display_name": "Името на показ", "onboarding.profile.display_name_hint": "Вашето пълно име или псевдоним…", - "onboarding.profile.indexable": "Включване на обществени публикации в резултатите от търсене", "onboarding.profile.lead": "Винаги може да завършите това по-късно в настройките, където дори има повече възможности за настройване.", "onboarding.profile.note": "Биогр.", "onboarding.profile.note_hint": "Може да @споменавате други хора или #хаштагове…", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 11d4de440..6b7fb1b86 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -485,6 +485,7 @@ "onboarding.profile.note_hint": "Gallwch @grybwyll pobl eraill neu #hashnodau…", "onboarding.profile.save_and_continue": "Cadw a pharhau", "onboarding.profile.title": "Gosodiad proffil", + "onboarding.profile.upload_avatar": "Llwytho llun proffil", "onboarding.share.lead": "Cofiwch ddweud wrth bobl sut y gallan nhw ddod o hyd i chi ar Mastodon!", "onboarding.share.message": "Fi yw {username} ar #Mastodon! Dewch i'm dilyn i yn {url}", "onboarding.share.next_steps": "Camau nesaf posib:", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index bde12a7ae..577d77782 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Ingen resultater tilgængelige pt. Prøv at bruge søgning eller gennemse siden for at finde personer at følge, eller forsøg igen senere.", "onboarding.follows.lead": "Man kurerer sin eget hjemme-feed. Jo flere personer man følger, des mere aktiv og interessant vil det være. Disse profiler kan være et godt udgangspunkt – de kan altid fjernes senere!", "onboarding.follows.title": "Populært på Mastodon", - "onboarding.profile.discoverable": "Fremhæv profil og indlæg i detekteringsalgoritmer", + "onboarding.profile.discoverable": "Gør min profil synlig", + "onboarding.profile.discoverable_hint": "Når man vælger at være synlig på Mastodon, kan ens indlæg fremgå i søgeresultater og tendenser, og profilen kan blive foreslået til andre med tilsvarende interesse.", "onboarding.profile.display_name": "Visningsnavn", "onboarding.profile.display_name_hint": "Fulde navn eller dit sjove navn…", - "onboarding.profile.indexable": "Medtag offentlige indlæg i søgeresultater", "onboarding.profile.lead": "Dette kan altid færdiggøres senere i indstillingerne, hvor endnu flere tilpasningsmuligheder forefindes.", "onboarding.profile.note": "Bio", "onboarding.profile.note_hint": "Man kan @omtale andre personer eller #hashtags…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Diskret", "privacy_policy.last_updated": "Senest opdateret {date}", "privacy_policy.title": "Privatlivspolitik", + "recommended": "Anbefalet", "refresh": "Genindlæs", "regeneration_indicator.label": "Indlæser…", "regeneration_indicator.sublabel": "Din hjemmetidslinje klargøres!", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 10fd9b4c5..7c0710efc 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Bedauerlicherweise können aktuell keine Ergebnisse angezeigt werden. Du kannst die Suche verwenden oder den Reiter „Entdecken“ auswählen, um neue Leute zum Folgen zu finden – oder du versuchst es später erneut.", "onboarding.follows.lead": "Deine Startseite ist der primäre Anlaufpunkt, um Mastodon zu erleben. Je mehr Profilen du folgst, umso aktiver und interessanter wird sie. Damit du direkt loslegen kannst, gibt es hier ein paar Vorschläge:", "onboarding.follows.title": "Personalisiere deine Startseite", - "onboarding.profile.discoverable": "Profil und Beiträge in Suchalgorithmen berücksichtigen", + "onboarding.profile.discoverable": "Mein Profil auffindbar machen", + "onboarding.profile.discoverable_hint": "Wenn du entdeckt werden möchtest, dann können deine Beiträge in Suchergebnissen und Trends erscheinen. Dein Profil kann ebenfalls anderen mit ähnlichen Interessen vorgeschlagen werden.", "onboarding.profile.display_name": "Anzeigename", "onboarding.profile.display_name_hint": "Dein richtiger Name oder dein Fantasiename …", - "onboarding.profile.indexable": "Öffentliche Beiträge in die Suchergebnisse einbeziehen", "onboarding.profile.lead": "Du kannst das später in den Einstellungen vervollständigen, wo noch mehr Anpassungsmöglichkeiten zur Verfügung stehen.", "onboarding.profile.note": "Über mich", "onboarding.profile.note_hint": "Du kannst andere @Profile erwähnen oder #Hashtags verwenden …", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Nicht gelistet", "privacy_policy.last_updated": "Stand: {date}", "privacy_policy.title": "Datenschutzerklärung", + "recommended": "Empfohlen", "refresh": "Aktualisieren", "regeneration_indicator.label": "Wird geladen …", "regeneration_indicator.sublabel": "Deine Startseite wird gerade vorbereitet!", diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index 31806bcfb..02ce7120a 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -168,6 +168,7 @@ "confirmations.mute.explanation": "Αυτό θα κρύψει τις δημοσιεύσεις τους και τις δημοσιεύσεις που τους αναφέρουν, αλλά θα συνεχίσουν να μπορούν να βλέπουν τις δημοσιεύσεις σου και να σε ακολουθούν.", "confirmations.mute.message": "Σίγουρα θες να αποσιωπήσεις {name};", "confirmations.redraft.confirm": "Διαγραφή & ξαναγράψιμο", + "confirmations.redraft.message": "Σίγουρα θέλεις να σβήσεις αυτή την ανάρτηση και να την ξαναγράψεις; Οι προτιμήσεις και προωθήσεις θα χαθούν και οι απαντήσεις στην αρχική ανάρτηση θα μείνουν ορφανές.", "confirmations.reply.confirm": "Απάντησε", "confirmations.reply.message": "Απαντώντας τώρα θα αντικαταστήσεις το κείμενο που ήδη γράφεις. Σίγουρα θέλεις να συνεχίσεις;", "confirmations.unfollow.confirm": "Άρση ακολούθησης", @@ -187,6 +188,7 @@ "dismissable_banner.community_timeline": "Αυτές είναι οι πιο πρόσφατες δημόσιες αναρτήσεις ατόμων των οποίων οι λογαριασμοί φιλοξενούνται στο {domain}.", "dismissable_banner.dismiss": "Παράβλεψη", "dismissable_banner.explore_links": "Αυτές οι ειδήσεις συζητούνται σε αυτόν και άλλους διακομιστές του αποκεντρωμένου δικτύου αυτή τη στιγμή.", + "dismissable_banner.explore_statuses": "Αυτές είναι οι αναρτήσεις που έχουν απήχηση στο κοινωνικό δίκτυο σήμερα. Οι νεώτερες αναρτήσεις με περισσότερες προωθήσεις και προτιμήσεις κατατάσσονται ψηλότερα.", "dismissable_banner.explore_tags": "Αυτές οι ετικέτες αποκτούν απήχηση σε αυτόν και άλλους διακομιστές του αποκεντρωμένου δικτύου αυτή τη στιγμή.", "embed.instructions": "Ενσωμάτωσε αυτή την ανάρτηση στην ιστοσελίδα σου αντιγράφοντας τον παρακάτω κώδικα.", "embed.preview": "Ορίστε πως θα φαίνεται:", @@ -279,13 +281,17 @@ "home.column_settings.basic": "Βασικές ρυθμίσεις", "home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων", "home.column_settings.show_replies": "Εμφάνιση απαντήσεων", + "home.explore_prompt.body": "Your home feed will have a mix of posts from the hashtags you've chosen to follow, the people you've chosen to follow, and the posts they boost. If that feels too quiet, you may want to:\nΗ τροφοδοσία της αρχικής σελίδας σας είναι ένα μίγμα από αναρτήσεις με τις ετικέτες και τα άτομα που επιλέξατε να ακολουθείτε, και τις αναρτήσεις που προωθούν. Εάν αυτό σας φαίνεται πολύ ήσυχο, μπορεί να θέλετε:", "home.hide_announcements": "Απόκρυψη ανακοινώσεων", "home.show_announcements": "Εμφάνιση ανακοινώσεων", "interaction_modal.description.follow": "Με έναν λογαριασμό Mastodon, μπορείς να ακολουθήσεις τον/την {name} ώστε να λαμβάνεις τις αναρτήσεις του/της στη δική σου ροή.", "interaction_modal.description.reblog": "Με ένα λογαριασμό Mastodon, μπορείς να ενισχύσεις αυτή την ανάρτηση για να τη μοιραστείς με τους δικούς σου ακολούθους.", "interaction_modal.description.reply": "Με ένα λογαριασμό Mastodon, μπορείς να απαντήσεις σε αυτή την ανάρτηση.", + "interaction_modal.login.action": "Take me home\nΠήγαινέ με στην αρχική σελίδα", + "interaction_modal.no_account_yet": "Not on Mastodon?\nΔεν είστε στο Mastodon;", "interaction_modal.on_another_server": "Σε διαφορετικό διακομιστή", "interaction_modal.on_this_server": "Σε αυτόν τον διακομιστή", + "interaction_modal.title.favourite": "Favorite {name}'s post\nΠροτίμησε την ανάρτηση της/του {name}", "interaction_modal.title.follow": "Ακολούθησε {name}", "interaction_modal.title.reblog": "Ενίσχυσε την ανάρτηση του {name}", "interaction_modal.title.reply": "Απάντηση στην ανάρτηση του {name}", @@ -376,6 +382,7 @@ "not_signed_in_indicator.not_signed_in": "Πρέπει να συνδεθείς για να αποκτήσεις πρόσβαση σε αυτόν τον πόρο.", "notification.admin.report": "Ο/Η {name} ανέφερε τον {target}", "notification.admin.sign_up": "{name} έχει εγγραφεί", + "notification.favourite": "{name} favorited your post\n{name} προτίμησε την ανάρτηση σου", "notification.follow": "Ο/Η {name} σε ακολούθησε", "notification.follow_request": "Ο/H {name} ζήτησε να σε ακολουθήσει", "notification.mention": "Ο/Η {name} σε επισήμανε", @@ -405,7 +412,7 @@ "notifications.column_settings.unread_notifications.highlight": "Επισήμανση μη αναγνωσμένων ειδοποιήσεων", "notifications.column_settings.update": "Επεξεργασίες:", "notifications.filter.all": "Όλες", - "notifications.filter.boosts": "Ενισχύσεις", + "notifications.filter.boosts": "Προωθήσεις", "notifications.filter.follows": "Ακολουθείς", "notifications.filter.mentions": "Επισημάνσεις", "notifications.filter.polls": "Αποτελέσματα δημοσκόπησης", @@ -425,9 +432,11 @@ "onboarding.actions.go_to_home": "Πηγαίνετε στην αρχική σας ροή", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Δημοφιλή στο Mastodon", + "onboarding.share.lead": "Let people know how they can find you on Mastodon!\nΕνημερώστε άλλα άτομα πώς μπορούν να σας βρουν στο Mastodon!", "onboarding.share.next_steps": "Πιθανά επόμενα βήματα:", "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", "onboarding.start.skip": "Want to skip right ahead?", + "onboarding.start.title": "You've made it!\nΤα καταφέρατε!", "onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.", "onboarding.steps.follow_people.title": "Follow {count, plural, one {one person} other {# people}}", "onboarding.steps.publish_status.body": "Say hello to the world.", @@ -572,7 +581,7 @@ "status.read_more": "Διάβασε περισότερα", "status.reblog": "Ενίσχυση", "status.reblog_private": "Ενίσχυση με αρχική ορατότητα", - "status.reblogged_by": "{name} ενισχύθηκε", + "status.reblogged_by": "{name} προώθησε", "status.reblogs.empty": "Κανείς δεν ενίσχυσε αυτή την ανάρτηση ακόμα. Μόλις το κάνει κάποιος, θα εμφανιστεί εδώ.", "status.redraft": "Σβήσε & ξαναγράψε", "status.remove_bookmark": "Αφαίρεση σελιδοδείκτη", diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index d00782592..7745311be 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -478,10 +478,8 @@ "onboarding.follows.empty": "Unfortunately, no results can be shown right now. You can try using search or browsing the explore page to find people to follow, or try again later.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Personalize your home feed", - "onboarding.profile.discoverable": "Feature profile and posts in discovery algorithms", "onboarding.profile.display_name": "Display name", "onboarding.profile.display_name_hint": "Your full name or your fun name…", - "onboarding.profile.indexable": "Include public posts in search results", "onboarding.profile.lead": "You can always complete this later in the settings, where even more customisation options are available.", "onboarding.profile.note": "Bio", "onboarding.profile.note_hint": "You can @mention other people or #hashtags…", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 5679d5e41..537b8d0af 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -350,6 +350,7 @@ "lightbox.previous": "Malantaŭen", "limited_account_hint.action": "Montru profilon ĉiukaze", "limited_account_hint.title": "La profilo estas kaŝita de la moderigantoj de {domain}.", + "link_preview.author": "De {name}", "lists.account.add": "Aldoni al la listo", "lists.account.remove": "Forigi de la listo", "lists.delete": "Forigi la liston", @@ -446,6 +447,7 @@ "onboarding.follows.empty": "Bedaŭrinde, neniu rezulto estas montrebla nuntempe. Vi povas provi serĉi aŭ foliumi la esploran paĝon por trovi kontojn por sekvi, aŭ retrovi baldaŭ.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.save_and_continue": "Konservi kaj daŭrigi", "onboarding.share.message": "Mi estas {username} en #Mastodon! Sekvu min ĉe {url}", "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", "onboarding.start.skip": "Want to skip right ahead?", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 3c99334c3..dfc00f1d8 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Desafortunadamente, no se pueden mostrar resultados en este momento. Podés intentar usar la búsqueda o navegar por la página de exploración para encontrar cuentas a las que seguir, o intentarlo de nuevo más tarde.", "onboarding.follows.lead": "Tu línea temporal de inicio es la forma principal de experimentar Mastodon. Cuanta más cuentas sigás, más activa e interesante será. Para empezar, acá tenés algunas sugerencias:", "onboarding.follows.title": "Personalizá tu línea de tiempo principal", - "onboarding.profile.discoverable": "Destacar perfil y mensajes en algoritmos de descubrimiento", + "onboarding.profile.discoverable": "Hacer que mi perfil sea detectable", + "onboarding.profile.discoverable_hint": "Cuando optás por ser detectable en Mastodon, tus mensajes pueden aparecer en los resultados de búsqueda y de tendencia, y tu perfil puede ser sugerido a personas con intereses similares a los tuyos.", "onboarding.profile.display_name": "Nombre para mostrar", "onboarding.profile.display_name_hint": "Tu nombre completo o tu pseudónimo…", - "onboarding.profile.indexable": "Incluir mensajes públicos en resultados de búsqueda", "onboarding.profile.lead": "Siempre podés completar esto más tarde en la configuración, donde hay disponibles más opciones de personalización.", "onboarding.profile.note": "Biografía", "onboarding.profile.note_hint": "Podés @mencionar otras cuentas o usar #etiquetas…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "No listado", "privacy_policy.last_updated": "Última actualización: {date}", "privacy_policy.title": "Política de privacidad", + "recommended": "Opción recomendada", "refresh": "Refrescar", "regeneration_indicator.label": "Cargando…", "regeneration_indicator.sublabel": "¡Se está preparando tu línea temporal principal!", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 70c4efcad..448a3ae91 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Desafortunadamente, no se pueden mostrar resultados en este momento. Puedes intentar usar la búsqueda o navegar por la página de exploración para encontrar gente a la que seguir, o inténtalo de nuevo más tarde.", "onboarding.follows.lead": "Tienes que personalizar tu inicio. Cuantas más personas sigas, más activo e interesante será. Estos perfiles pueden ser un buen punto de partida, ¡pero siempre puedes dejar de seguirlos más adelante!", "onboarding.follows.title": "Popular en Mastodon", - "onboarding.profile.discoverable": "Destacar el perfil y las publicaciones en el algoritmo de descubrimiento", + "onboarding.profile.discoverable": "Hacer que mi perfil aparezca en búsquedas", + "onboarding.profile.discoverable_hint": "Cuando permites que tu perfil aparezca en búsquedas en Mastodon, tus publicaciones podrán aparecer en los resultados de búsqueda y en tendencias, y tu perfil podrá recomendarse a gente con intereses similares a los tuyos.", "onboarding.profile.display_name": "Nombre a mostrar", "onboarding.profile.display_name_hint": "Tu nombre completo o tu apodo…", - "onboarding.profile.indexable": "Incluir publicaciones públicas en los resultados de búsqueda", "onboarding.profile.lead": "Siempre puedes completar esto más tarde en los ajustes, donde hay aún más opciones de personalización disponibles.", "onboarding.profile.note": "Biografía", "onboarding.profile.note_hint": "Puedes @mencionar a otras personas o #hashtags…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "No listado", "privacy_policy.last_updated": "Actualizado por última vez {date}", "privacy_policy.title": "Política de Privacidad", + "recommended": "Recomendado", "refresh": "Actualizar", "regeneration_indicator.label": "Cargando…", "regeneration_indicator.sublabel": "¡Tu historia de inicio se está preparando!", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 3c0d8cd57..9850bf039 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -66,7 +66,7 @@ "account.unblock": "Desbloquear a @{name}", "account.unblock_domain": "Desbloquear dominio {domain}", "account.unblock_short": "Desbloquear", - "account.unendorse": "No destacar en el perfil", + "account.unendorse": "No mostrar en el perfil", "account.unfollow": "Dejar de seguir", "account.unmute": "Dejar de silenciar a @{name}", "account.unmute_notifications_short": "Dejar de silenciar notificaciones", @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Desafortunadamente, no se pueden mostrar resultados en este momento. Puedes intentar usar la búsqueda o navegar por la página de exploración para encontrar personas a las que seguir, o inténtalo de nuevo más tarde.", "onboarding.follows.lead": "Tu línea de inicio es la forma principal de experimentar Mastodon. Cuanta más personas sigas, más activa e interesante será. Para empezar, aquí hay algunas sugerencias:", "onboarding.follows.title": "Personaliza tu línea de inicio", - "onboarding.profile.discoverable": "Destacar perfil y publicaciones en algoritmos de descubrimiento", + "onboarding.profile.discoverable": "Hacer que mi perfil aparezca en búsquedas", + "onboarding.profile.discoverable_hint": "Cuando permites que tu perfil aparezca en búsquedas en Mastodon, tus publicaciones podrán aparecer en los resultados de búsqueda y en tendencias, y tu perfil podrá recomendarse a gente con intereses similares a los tuyos.", "onboarding.profile.display_name": "Nombre para mostrar", "onboarding.profile.display_name_hint": "Tu nombre completo o tu apodo…", - "onboarding.profile.indexable": "Incluir publicaciones públicas en los resultados de búsqueda", "onboarding.profile.lead": "Siempre puedes completar esto más tarde en los ajustes, donde hay aún más opciones de personalización disponibles.", "onboarding.profile.note": "Biografía", "onboarding.profile.note_hint": "Puedes @mencionar a otras personas o #etiquetas…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "No listado", "privacy_policy.last_updated": "Actualizado por última vez {date}", "privacy_policy.title": "Política de Privacidad", + "recommended": "Recomendado", "refresh": "Actualizar", "regeneration_indicator.label": "Cargando…", "regeneration_indicator.sublabel": "¡Tu historia de inicio se está preparando!", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index 5bca1cfef..eb666a0ee 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Zoritxarrez, ezin da emaitzik erakutsi orain. Bilaketa erabil dezakezu edo Arakatu orrian jendea bilatu jarraitzeko, edo saiatu geroago.", "onboarding.follows.lead": "Hasierako orria zuk pertsonalizatzen duzu. Gero eta jende gehiagori jarraitu, orduan eta aktibo eta interesgarriago izango da. Profil hauek egokiak izan daitezke hasteko, beti ere, geroago jarraitzeari utz diezazkiekezu!", "onboarding.follows.title": "Mastodonen pil-pilean", - "onboarding.profile.discoverable": "Ezagutarazi profila eta bidalketak bilaketa algoritmoetan", + "onboarding.profile.discoverable": "Profila aurkitzeko moduan jarri", + "onboarding.profile.discoverable_hint": "Mastodon zure profila aurkitzeko moduan duzunean, zure mezuak bilaketa-emaitzetan eta jarraipenetan ager daitezke, eta zure profila antzeko interesa duen jendeari iradoki ahal zaio.", "onboarding.profile.display_name": "Bistaratzeko izena", "onboarding.profile.display_name_hint": "Zure izena edo ezizena…", - "onboarding.profile.indexable": "Gehitu argitalpen publikoak bilaketa-emaitzetan", "onboarding.profile.lead": "Geroagoago bete daiteke konfigurazioan, non pertsonalizatzeko aukera gehiago dauden.", "onboarding.profile.note": "Biografia", "onboarding.profile.note_hint": "Beste pertsona batzuk @aipa ditzakezu edo #traolak erabili…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Zerrendatu gabea", "privacy_policy.last_updated": "Azkenengo eguneraketa {date}", "privacy_policy.title": "Pribatutasun politika", + "recommended": "Gomendatua", "refresh": "Berritu", "regeneration_indicator.label": "Kargatzen…", "regeneration_indicator.sublabel": "Zure hasiera-jarioa prestatzen ari da!", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 97dae30d4..6951d5cb0 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -479,7 +479,7 @@ "onboarding.follows.empty": "متأسفانه هماکنون نتیجهای قابل نمایش نیست. میتوانید استفاده از جستوجو یا مرور صفحهٔ کاوش را برای یافتن افرادی برای پیگیری آزموده یا دوباره تلاش کنید.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", - "onboarding.profile.discoverable": "معرفی نمایه و فرستهها در الگوریتمهای کشف", + "onboarding.profile.discoverable": "نمایه خود را قابل نمایش کنید", "onboarding.profile.display_name": "نام نمایشی", "onboarding.profile.display_name_hint": "نام کامل یا نام باحالتان…", "onboarding.profile.note": "درباره شما", @@ -529,6 +529,7 @@ "privacy.unlisted.short": "فهرست نشده", "privacy_policy.last_updated": "آخرین بهروز رسانی در {date}", "privacy_policy.title": "سیاست محرمانگی", + "recommended": "پیشنهادشده", "refresh": "نوسازی", "regeneration_indicator.label": "در حال بار شدن…", "regeneration_indicator.sublabel": "خوراک خانگیتان دارد آماده میشود!", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 344e37c97..7a07913f8 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -21,7 +21,7 @@ "account.blocked": "Estetty", "account.browse_more_on_origin_server": "Selaile lisää alkuperäisellä palvelimella", "account.cancel_follow_request": "Peruuta seurantapyyntö", - "account.copy": "Kopioi profiilin linkki", + "account.copy": "Kopioi profiililinkki", "account.direct": "Mainitse @{name} yksityisesti", "account.disable_notifications": "Lopeta ilmoittamasta minulle, kun @{name} julkaisee", "account.domain_blocked": "Verkkotunnus estetty", @@ -192,7 +192,7 @@ "conversation.mark_as_read": "Merkitse luetuksi", "conversation.open": "Näytä keskustelu", "conversation.with": "{names} kanssa", - "copy_icon_button.copied": "Kopioitu leikepöydälle", + "copy_icon_button.copied": "Kopioitiin leikepöydälle", "copypaste.copied": "Kopioitu", "copypaste.copy_to_clipboard": "Kopioi leikepöydälle", "directory.federated": "Koko tunnettu fediversumi", @@ -481,11 +481,11 @@ "onboarding.follows.empty": "Valitettavasti tuloksia ei voida näyttää juuri nyt. Voit kokeilla hakua tai selata tutustumissivua löytääksesi seurattavaa tai yrittää myöhemmin uudelleen.", "onboarding.follows.lead": "Kokoat oman kotisyötteesi itse. Mitä enemmän ihmisiä seuraat, sitä aktiivisempi ja kiinnostavampi syöte on. Nämä profiilit voivat olla alkuun hyvä lähtökohta — voit aina lopettaa niiden seuraamisen myöhemmin!", "onboarding.follows.title": "Mukauta kotisyötettäsi", - "onboarding.profile.discoverable": "Pidä profiilia ja julkaisuja esillä löytämisalgoritmeissa", + "onboarding.profile.discoverable": "Aseta profiilini löydettäväksi", + "onboarding.profile.discoverable_hint": "Kun olet määrittänyt itsesi löydettäväksi Mastodonista, voivat julkaisusi näkyä hakutuloksissa ja suosituissa kohteissa, ja profiiliasi voidaan ehdottaa käyttäjille, jotka ovat kiinnostuneet samoista aiheista kuin sinä.", "onboarding.profile.display_name": "Näyttönimi", "onboarding.profile.display_name_hint": "Koko nimesi tai lempinimesi…", - "onboarding.profile.indexable": "Sisällytä julkiset julkaisut hakutuloksiin", - "onboarding.profile.lead": "Voit viimeistellä tämän milloin tahansa asetuksissa, jossa on saatavilla vielä enemmän mukautusvalintoja.", + "onboarding.profile.lead": "Voit viimeistellä tämän milloin tahansa asetuksista, jotka tarjoavat vielä enemmän mukautusvalintoja.", "onboarding.profile.note": "Elämäkerta", "onboarding.profile.note_hint": "Voit @mainita muita käyttäjiä tai #aihetunnisteita…", "onboarding.profile.save_and_continue": "Tallenna ja jatka", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Listaamaton", "privacy_policy.last_updated": "Viimeksi päivitetty {date}", "privacy_policy.title": "Tietosuojakäytäntö", + "recommended": "Suositeltu", "refresh": "Päivitä", "regeneration_indicator.label": "Ladataan…", "regeneration_indicator.sublabel": "Kotisyötettäsi valmistellaan!", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index 61c1287ea..aa99a0c30 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -21,6 +21,7 @@ "account.blocked": "Bannað/ur", "account.browse_more_on_origin_server": "Kaga meira á upprunaligu vangamyndina", "account.cancel_follow_request": "Strika fylgjaraumbøn", + "account.copy": "Avrita leinki til vangan", "account.direct": "Umrøð @{name} privat", "account.disable_notifications": "Ikki boða mær frá, tá @{name} skrivar", "account.domain_blocked": "Økisnavn bannað", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Merk sum lisið", "conversation.open": "Vís samrøðu", "conversation.with": "Við {names}", + "copy_icon_button.copied": "Avritað til setiborðið", "copypaste.copied": "Avritað", "copypaste.copy_to_clipboard": "Avrita til setiborðið", "directory.federated": "Frá tí kenda fediversinum", @@ -478,6 +480,8 @@ "onboarding.follows.empty": "Tíverri kunnu eingi úrslit vísast beint nú. Tú kanst royna at brúka leiting ella at kaga gjøgnum Rannsaka síðuna fyri at finna fólk at fylgja - ella royna aftur seinni.", "onboarding.follows.lead": "Tú snikkar sjálv/ur tína heimarás til. Jú fleiri fólk, tú fylgir, jú virknari og áhugaverdari verður tað. Hesir vangar kunnu vera ein góð byrjan — tú kanst altíð gevast at fylgja teimum seinni!", "onboarding.follows.title": "Vælumtókt á Mastodon", + "onboarding.profile.discoverable": "Ger tað møguligt hjá øðrum at finna vangan hjá mær", + "onboarding.profile.discoverable_hint": "Tá tú játtar at onnur skulu kunna finna teg á Mastodon, so kann henda, at postar tínir síggjast í leitiúrslitum og rákum, og vangin hjá tær kann vera skotin upp fyri fólki við áhugamálum sum minna um tíni.", "onboarding.share.lead": "Lat fólk vita, hvussu tey kunnu finna teg á Mastodon!", "onboarding.share.message": "Eg eri {username} á #Mastodon! Kom og fylg mær á {url}", "onboarding.share.next_steps": "Møgulig næstu stig:", @@ -521,6 +525,7 @@ "privacy.unlisted.short": "Ikki listað", "privacy_policy.last_updated": "Seinast dagført {date}", "privacy_policy.title": "Privatlívspolitikkur", + "recommended": "Viðmælt", "refresh": "Endurles", "regeneration_indicator.label": "Innlesur…", "regeneration_indicator.sublabel": "Tín heimarás verður gjørd klár!", diff --git a/app/javascript/mastodon/locales/fr-QC.json b/app/javascript/mastodon/locales/fr-QC.json index d85a6d428..aeb1bf6b0 100644 --- a/app/javascript/mastodon/locales/fr-QC.json +++ b/app/javascript/mastodon/locales/fr-QC.json @@ -479,9 +479,12 @@ "onboarding.follows.empty": "Malheureusement, aucun résultat ne peut être affiché pour le moment. Vous pouvez essayer de rechercher ou de parcourir la page \"Explorer\" pour trouver des personnes à suivre, ou réessayer plus tard.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", - "onboarding.profile.discoverable": "Autoriser des algorithmes de découverte à mettre en avant votre profil et vos messages", + "onboarding.profile.display_name": "Nom affiché", + "onboarding.profile.note": "Biographie", "onboarding.profile.save_and_continue": "Enregistrer et continuer", + "onboarding.profile.title": "Configuration du profil", "onboarding.profile.upload_avatar": "Importer une photo de profil", + "onboarding.profile.upload_header": "Envoyer une image de profil", "onboarding.share.lead": "Faites savoir aux gens comment vous trouver sur Mastodon!", "onboarding.share.message": "Je suis {username} sur #Mastodon! Suivez-moi sur {url}", "onboarding.share.next_steps": "Étapes suivantes possibles:", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 14e0e13ba..95026531e 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -479,9 +479,12 @@ "onboarding.follows.empty": "Malheureusement, aucun résultat ne peut être affiché pour le moment. Vous pouvez essayer d'utiliser la recherche ou parcourir la page de découverte pour trouver des personnes à suivre, ou réessayez plus tard.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Personnaliser votre flux principal", - "onboarding.profile.discoverable": "Autoriser des algorithmes de découverte à mettre en avant votre profil et vos messages", + "onboarding.profile.display_name": "Nom affiché", + "onboarding.profile.note": "Biographie", "onboarding.profile.save_and_continue": "Enregistrer et continuer", + "onboarding.profile.title": "Configuration du profil", "onboarding.profile.upload_avatar": "Importer une photo de profil", + "onboarding.profile.upload_header": "Envoyer une image de profil", "onboarding.share.lead": "Faites savoir aux gens comment ils peuvent vous trouver sur Mastodon!", "onboarding.share.message": "Je suis {username} sur #Mastodon ! Suivez-moi sur {url}", "onboarding.share.next_steps": "Étapes suivantes possibles :", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 1f199bc45..03f0318f3 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -21,6 +21,7 @@ "account.blocked": "Bloqueada", "account.browse_more_on_origin_server": "Busca máis no perfil orixinal", "account.cancel_follow_request": "Cancelar a solicitude de seguimento", + "account.copy": "Copiar ligazón ao perfil", "account.direct": "Mencionar de xeito privado a @{name}", "account.disable_notifications": "Deixar de notificarme cando @{name} publica", "account.domain_blocked": "Dominio agochado", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marcar como lido", "conversation.open": "Ver conversa", "conversation.with": "Con {names}", + "copy_icon_button.copied": "Copiada ao portapapeis", "copypaste.copied": "Copiado", "copypaste.copy_to_clipboard": "Copiar ao portapapeis", "directory.federated": "Do fediverso coñecido", @@ -479,10 +481,10 @@ "onboarding.follows.empty": "Desgraciadamente agora mesmo non hai nada que mostrar. Podes intentalo coa busca ou na páxina descubrir para atopar persoas ás que seguir, ou intentalo máis tarde.", "onboarding.follows.lead": "Podes facer que a túa cronoloxía de inicio sexa como ti a queres. Canta máis xente sigas máis interesante será. Estes perfís poderían axudarche a comezar —sempre poderás deixar de seguilos despois!", "onboarding.follows.title": "Popular en Mastodon", - "onboarding.profile.discoverable": "Perfil destacado e publicacións nos algoritmos de descubrimento", + "onboarding.profile.discoverable": "Que o meu perfil sexa atopable", + "onboarding.profile.discoverable_hint": "Cando elixes que poidan atoparte en Mastodon as túas publicacións aparecerán nos resultados das buscas e nos temas en voga, e o teu perfil podería ser suxerido para seguimento a persoas con intereses semellantes aos teus.", "onboarding.profile.display_name": "Nome público", "onboarding.profile.display_name_hint": "O teu nome completo ou un nome divertido…", - "onboarding.profile.indexable": "Incluír publicacións públicas nos resultados das buscas", "onboarding.profile.lead": "Sempre poderás incluír esta información mais tarde nos axustes, onde terás máis opcións dispoñibles.", "onboarding.profile.note": "Acerca de ti", "onboarding.profile.note_hint": "Podes @mencionar a outras persoas ou usar #cancelos…", @@ -533,6 +535,7 @@ "privacy.unlisted.short": "Sen listar", "privacy_policy.last_updated": "Actualizado por última vez no {date}", "privacy_policy.title": "Política de Privacidade", + "recommended": "Aconsellable", "refresh": "Actualizar", "regeneration_indicator.label": "Estase a cargar…", "regeneration_indicator.sublabel": "Estase a preparar a túa cronoloxía de inicio!", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index b6716f796..4ab516fae 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -31,7 +31,7 @@ "account.featured_tags.last_status_at": "חצרוץ אחרון בתאריך {date}", "account.featured_tags.last_status_never": "אין חצרוצים", "account.featured_tags.title": "התגיות המועדפות של {name}", - "account.follow": "עקוב", + "account.follow": "לעקוב", "account.followers": "עוקבים", "account.followers.empty": "אף אחד לא עוקב אחר המשתמש הזה עדיין.", "account.followers_counter": "{count, plural,one {עוקב אחד} other {{counter} עוקבים}}", @@ -302,15 +302,15 @@ "hashtag.counter_by_accounts": "{count, plural,one{{count} משתתף.ת}other{{count} משתתפיםות}}", "hashtag.counter_by_uses": "{count, plural, one {הודעה אחת} two {הודעותיים} many {{count} הודעות} other {{count} הודעות}}", "hashtag.counter_by_uses_today": "{count, plural, one {הודעה אחת} two {הודעותיים} many {{count} הודעות} other {{count} הודעות}} היום", - "hashtag.follow": "מעקב אחר תגית", - "hashtag.unfollow": "ביטול מעקב אחר תגית", + "hashtag.follow": "לעקוב אחרי תגית", + "hashtag.unfollow": "להפסיק לעקוב אחרי תגית", "hashtags.and_other": "…{count, plural,other {ועוד #}}", "home.actions.go_to_explore": "הצגת מגמות", "home.actions.go_to_suggestions": "למצוא א.נשים לעקוב אחריהן.ם", "home.column_settings.basic": "למתחילים", "home.column_settings.show_reblogs": "הצגת הדהודים", "home.column_settings.show_replies": "הצגת תגובות", - "home.explore_prompt.body": "זרם הבית שלך יכיל תערובת של הודעות מהתגיות והאנשים שבחרת לעקיבה, וההודעות שהנעקבים בוחרים להדהד. אם זה נראה שקט מדי כרגע אז מה לגבי:", + "home.explore_prompt.body": "פיד הבית שלך יכיל תערובת של הודעות מהתגיות והאנשים שבחרת למעקב, וההודעות שהנעקבים בוחרים להדהד. אם זה נראה שקט מדי כרגע אז מה לגבי:", "home.explore_prompt.title": "זהו בסיס הבית שלך בתוך מסטודון.", "home.hide_announcements": "הסתר הכרזות", "home.pending_critical_update.body": "יש לעדכן את תוכנת מסטודון בהקדם האפשרי!", @@ -481,10 +481,10 @@ "onboarding.follows.empty": "למצער, תוצאות לחיפושך אינן בנמצא. ניתן להשתמש בחיפוש או בדף החקירות לשם מציאת אנשים ולעקבם. אפשר גם לנסות שוב אחר כך.", "onboarding.follows.lead": "אתם אוצרים את הזרם הבייתי שלכם. ככל שתעקבו אחרי יותר אנשים, הוא יהיה עשיר ופעיל יותר. הנה כמה פרופילים להתחיל בהם - תמיד ניתן להפסיק מעקב אחריהם בהמשך!", "onboarding.follows.title": "פופולארי על מסטודון", - "onboarding.profile.discoverable": "הצגת פרופיל והודעות במסך התגליות", + "onboarding.profile.discoverable": "כלול את הפרופיל שלי בעמודת התגליות", + "onboarding.profile.discoverable_hint": "כשתבחרו להכלל ב\"תגליות\" על מסטודון, ההודעות שלכם עשויות להופיע בתוצאות חיפוש ועמודות \"נושאים חמים\", והפרופיל יוצע לאחרים עם תחומי עניין משותפים לכם.", "onboarding.profile.display_name": "שם להצגה", "onboarding.profile.display_name_hint": "שמך המלא או כינוי הכיף שלך…", - "onboarding.profile.indexable": "הכללת הודעות ציבוריות בתוצאות החיפוש", "onboarding.profile.lead": "תמיד ניתן להשלים זאת אחר כך בהגדרות, שם יש אפילו עוד אפשרויות להתאמה אישית.", "onboarding.profile.note": "אודות", "onboarding.profile.note_hint": "ניתן @לאזכר משתמשים אחרים או #תגיות…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "לא רשום (לא לפיד הכללי)", "privacy_policy.last_updated": "עודכן לאחרונה {date}", "privacy_policy.title": "מדיניות פרטיות", + "recommended": "מומלץ", "refresh": "רענון", "regeneration_indicator.label": "טוען…", "regeneration_indicator.sublabel": "פיד הבית שלך בהכנה!", diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json index f4473b716..387941b5e 100644 --- a/app/javascript/mastodon/locales/hi.json +++ b/app/javascript/mastodon/locales/hi.json @@ -415,6 +415,8 @@ "onboarding.compose.template": "नमस्कार #मस्टोडोन", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.discoverable": "अपना प्रोफाइल खोजने योग्य बनाएं", + "onboarding.profile.discoverable_hint": "जब आप मॅस्टोडॉन पर डिस्कवरेबिलिटी चुनते हैं तो आपके पोस्ट ट्रेंडिंग और सर्च में दिख सकते हैं और आपका प्रोफाइल आपके ही जैसे अकाउंट्स को सुझाया जा सकता है।", "onboarding.share.message": "मैं {username} मॅस्टोडॉन पर हूं! मुझे यहां {url} फॉलो करें", "onboarding.share.next_steps": "आगे कि संभवित विधि", "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", @@ -441,6 +443,7 @@ "privacy.public.long": "सब को दिखाई देगा", "privacy.public.short": "सार्वजनिक", "privacy.unlisted.short": "अनलिस्टेड", + "recommended": "अनुशंसित", "refresh": "रीफ्रेश करें", "regeneration_indicator.label": "लोड हो रहा है...", "relative_time.full.just_now": "अभी-अभी", diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index 01524e553..6da7d6cd8 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -225,6 +225,7 @@ "follow_request.authorize": "Autoriziraj", "follow_request.reject": "Odbij", "footer.about": "O aplikaciji", + "footer.directory": "Direktorij profila", "footer.get_app": "Preuzmi aplikaciju", "footer.invite": "Pozovi ljude", "footer.keyboard_shortcuts": "Tipkovni prečaci", @@ -244,6 +245,7 @@ "hashtag.column_settings.tag_toggle": "Uključi dodatne oznake za ovaj stupac", "hashtag.follow": "Prati hashtag", "hashtag.unfollow": "Prestani pratiti hashtag", + "home.actions.go_to_explore": "Vidi trendove", "home.column_settings.basic": "Osnovno", "home.column_settings.show_reblogs": "Pokaži boostove", "home.column_settings.show_replies": "Pokaži odgovore", @@ -310,6 +312,7 @@ "mute_modal.duration": "Trajanje", "mute_modal.hide_notifications": "Sakrij obavijesti ovog korisnika?", "navigation_bar.about": "O aplikaciji", + "navigation_bar.advanced_interface": "Otvori u naprednom web sučelju", "navigation_bar.blocks": "Blokirani korisnici", "navigation_bar.community_timeline": "Lokalna vremenska crta", "navigation_bar.compose": "Compose new toot", @@ -364,6 +367,7 @@ "onboarding.actions.go_to_home": "Go to your home feed", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.upload_avatar": "Učitaj sliku profila", "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", "onboarding.start.skip": "Want to skip right ahead?", "onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.", @@ -393,6 +397,7 @@ "privacy.unlisted.short": "Neprikazano", "privacy_policy.last_updated": "Zadnje ažurirannje {date}", "privacy_policy.title": "Pravila o zaštiti privatnosti", + "recommended": "Preporučeno", "refresh": "Osvježi", "regeneration_indicator.label": "Učitavanje…", "regeneration_indicator.sublabel": "Priprema se Vaša početna stranica!", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 83948b178..9be5b57e4 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Sajnos jelenleg nem jeleníthető meg eredmény. Kipróbálhatod a keresést vagy böngészheted a felfedező oldalon a követni kívánt személyeket, vagy próbáld meg később.", "onboarding.follows.lead": "A saját hírfolyamod az elsődleges tapasztalás a Mastodonon. Minél több embert követsz, annál aktívabb és érdekesebb a dolog. Az induláshoz itt van néhány javaslat:", "onboarding.follows.title": "Népszerű a Mastodonon", - "onboarding.profile.discoverable": "Profil és bejegyzések szerepeltetése a felfedezési algoritmusokban", + "onboarding.profile.discoverable": "Saját profil beállítása felfedezhetőként", + "onboarding.profile.discoverable_hint": "A Mastodonon a felfedezhetőség választása esetén a saját bejegyzéseid megjelenhetnek a keresési eredmények és a felkapott tartalmak között, valamint a profilod a hozzád hasonló érdeklődési körrel rendelkező embereknél is ajánlásra kerülhet.", "onboarding.profile.display_name": "Megjelenített név", "onboarding.profile.display_name_hint": "Teljes neved vagy vicces neved…", - "onboarding.profile.indexable": "Nyilvános bejegyzések szerepeltetése a keresési eredményekben", "onboarding.profile.lead": "Ezt később bármikor befejezheted a beállításokban, ahol még több testreszabási lehetőség áll rendelkezésre.", "onboarding.profile.note": "Bemutatkozás", "onboarding.profile.note_hint": "Megemlíthetsz @másokat vagy #hashtag-eket…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Listázatlan", "privacy_policy.last_updated": "Utoljára frissítve: {date}", "privacy_policy.title": "Adatvédelmi szabályzat", + "recommended": "Ajánlott", "refresh": "Frissítés", "regeneration_indicator.label": "Betöltés…", "regeneration_indicator.sublabel": "A saját idővonalad épp készül!", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index b3c55d4f6..4c9ca12d9 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Því miður er ekki hægt að birta neinar niðurstöður í augnablikinu. Þú getur reynt að nota leitina eða skoðað könnunarsíðuna til að finna fólk til að fylgjast með, nú eða prófað aftur síðar.", "onboarding.follows.lead": "Þú ræktar heimastreymið þitt. Því fleira fólki sem þú fylgist með, því virkara og áhugaverðara verður það. Að fylgjast með þessum notendum gæti verið ágætt til að byrja með - þú getur alltaf hætt að fylgjast með þeim síðar!", "onboarding.follows.title": "Vinsælt á Mastodon", - "onboarding.profile.discoverable": "Hafa notandasnið og færslur með í reikniritum leitar", + "onboarding.profile.discoverable": "Gera notandasniðið mitt uppgötvanlegt", + "onboarding.profile.discoverable_hint": "Þegar þú velur að hægt sé að uppgötva þig á Mastodon, munu færslurnar þínar birtast í leitarniðurstöðum og vinsældalistum, auk þess sem stungið verður upp á notandasniðinu þínu við fólk sem er með svipuð áhugamál og þú.", "onboarding.profile.display_name": "Birtingarnafn", "onboarding.profile.display_name_hint": "Fullt nafn þitt eða eitthvað til gamans…", - "onboarding.profile.indexable": "Hafa opinberar færslur með í leitarniðurstöðum", "onboarding.profile.lead": "Þú getur alltaf klárað þetta seinna í stillingunum, þar sem enn fleiri möguleikar bjóðast á sérsníðingum.", "onboarding.profile.note": "Æviágrip", "onboarding.profile.note_hint": "Þú getur @minnst á annað fólk eða #myllumerki…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Óskráð", "privacy_policy.last_updated": "Síðast uppfært {date}", "privacy_policy.title": "Persónuverndarstefna", + "recommended": "Mælt með", "refresh": "Endurlesa", "regeneration_indicator.label": "Hleð inn…", "regeneration_indicator.sublabel": "Verið er að útbúa heimastreymið þitt!", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 02e5991ab..2ecf1d8c1 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Sfortunatamente, nessun risultato può essere mostrato in questo momento. Puoi provare a utilizzare la ricerca o sfogliare la pagina di esplorazione per trovare persone da seguire, oppure riprova più tardi.", "onboarding.follows.lead": "La cronologia della tua home è gestita da te. Più persone segui, più attiva e interessante sarà. Questi profili possono essere un buon punto di partenza; puoi sempre smettere di seguirli in seguito!", "onboarding.follows.title": "Popolare su Mastodon", - "onboarding.profile.discoverable": "Include il profilo e i post negli algoritmi di scoperta", + "onboarding.profile.discoverable": "Rendi il mio profilo rilevabile", + "onboarding.profile.discoverable_hint": "Quando attivi la rilevabilità su Mastodon, i tuoi post potrebbero apparire nei risultati di ricerca e nelle tendenze e il tuo profilo potrebbe essere suggerito a persone con interessi simili ai tuoi.", "onboarding.profile.display_name": "Nome da visualizzare", "onboarding.profile.display_name_hint": "Il tuo nome completo o il tuo nome divertente…", - "onboarding.profile.indexable": "Includi i post pubblici nei risultati di ricerca", "onboarding.profile.lead": "Puoi sempre completarlo in un secondo momento nelle impostazioni, dove sono disponibili ancora più opzioni di personalizzazione.", "onboarding.profile.note": "Biografia", "onboarding.profile.note_hint": "Puoi @menzionare altre persone o #hashtags…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Non elencato", "privacy_policy.last_updated": "Ultimo aggiornamento {date}", "privacy_policy.title": "Politica sulla Privacy", + "recommended": "Consigliato", "refresh": "Ricarica", "regeneration_indicator.label": "Caricamento…", "regeneration_indicator.sublabel": "Il feed della tua home è in preparazione!", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index f8c85b774..3cb0565d0 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -21,6 +21,7 @@ "account.blocked": "ブロック済み", "account.browse_more_on_origin_server": "リモートで表示", "account.cancel_follow_request": "フォローリクエストの取り消し", + "account.copy": "プロフィールのリンクをコピーして下さい", "account.direct": "@{name}さんに非公開でメンション", "account.disable_notifications": "@{name}さんの投稿時の通知を停止", "account.domain_blocked": "ドメインブロック中", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "既読にする", "conversation.open": "会話を表示", "conversation.with": "{names}", + "copy_icon_button.copied": "クリップボードにコピーされた", "copypaste.copied": "コピーしました", "copypaste.copy_to_clipboard": "クリップボードにコピー", "directory.federated": "既知の連合より", @@ -479,6 +481,17 @@ "onboarding.follows.empty": "表示できる結果はありません。検索やエクスプローラーを使ったり、ほかのアカウントをフォローしたり、後でもう一度試しください。", "onboarding.follows.lead": "ホームタイムラインはMastodonの軸足となる場所です。たくさんのユーザーをフォローすることで、ホームタイムラインはよりにぎやかでおもしろいものになります。手はじめに、おすすめのアカウントから何人かフォローしてみましょう:", "onboarding.follows.title": "ホームタイムラインを埋める", + "onboarding.profile.discoverable": "自分のプロフィールが発見できないようにする", + "onboarding.profile.discoverable_hint": "マストドンの見つけやすくする機能が個人情報を利用することに承諾すると、あなたの投稿が検索結果やトレンドに表示されることがあります。また、あなたのプロフィールがあなたと似た興味関心を持つ人に提案されることがあります。", + "onboarding.profile.display_name": "表示名", + "onboarding.profile.display_name_hint": "あなたのフルネーム、または楽しい名前…", + "onboarding.profile.lead": "このことは後でいつでも設定から完了させることが出来ますし、設定では更に多くのカスタマイズが利用可能になっています。", + "onboarding.profile.note": "自己紹介", + "onboarding.profile.note_hint": "@を使用して他の人々にメンションをすることができます。また#でハッシュタグが使用できます", + "onboarding.profile.save_and_continue": "保存してから続行して下さい", + "onboarding.profile.title": "プロフィールの設定", + "onboarding.profile.upload_avatar": "プロフィール画像をアップロードしてください", + "onboarding.profile.upload_header": "プロフィールのヘッダー画像をアップロードして下さい", "onboarding.share.lead": "新しいMastodonのアカウントをみんなに紹介しましょう。", "onboarding.share.message": "「{username}」で #Mastodon はじめました! {url}", "onboarding.share.next_steps": "次のステップに進む:", @@ -522,6 +535,7 @@ "privacy.unlisted.short": "非収載", "privacy_policy.last_updated": "{date}に更新", "privacy_policy.title": "プライバシーポリシー", + "recommended": "おすすめ", "refresh": "更新", "regeneration_indicator.label": "読み込み中…", "regeneration_indicator.sublabel": "ホームタイムラインは準備中です!", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index de72e382c..8d1c77fac 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -192,7 +192,7 @@ "conversation.mark_as_read": "읽은 상태로 표시", "conversation.open": "대화 보기", "conversation.with": "{names} 님과", - "copy_icon_button.copied": "클립보드에 복사함", + "copy_icon_button.copied": "클립보드에 복사됨", "copypaste.copied": "복사됨", "copypaste.copy_to_clipboard": "클립보드에 복사", "directory.federated": "알려진 연합우주로부터", @@ -481,10 +481,9 @@ "onboarding.follows.empty": "안타깝지만 아직은 아무 것도 보여드릴 수 없습니다. 검색을 이용하거나 발견하기 페이지에서 팔로우 할 사람을 찾을 수 있습니다. 아니면 잠시 후에 다시 시도하세요.", "onboarding.follows.lead": "홈 피드는 마스토돈을 경험하는 주된 경로입니다. 더 많은 사람들을 팔로우 할수록 더 활발하고 흥미로워질 것입니다. 여기 시작을 위한 몇몇 추천을 드립니다:", "onboarding.follows.title": "내게 맞는 홈 피드 꾸미기", - "onboarding.profile.discoverable": "발견하기 알고리즘에 프로필과 게시물을 추천하기", + "onboarding.profile.discoverable": "내 프로필을 발견 가능하도록 설정", "onboarding.profile.display_name": "표시되는 이름", "onboarding.profile.display_name_hint": "진짜 이름 또는 재미난 이름…", - "onboarding.profile.indexable": "공개 게시물을 검색 결과에 포함시키기", "onboarding.profile.lead": "언제든지 나중에 설정 메뉴에서 마저 할 수 있고, 그곳에서 더 많은 맞춤 옵션을 고를 수 있습니다.", "onboarding.profile.note": "자기소개", "onboarding.profile.note_hint": "남을 @mention 하거나 #hashtag 태그를 달 수 있습니다…", @@ -535,6 +534,7 @@ "privacy.unlisted.short": "미등재", "privacy_policy.last_updated": "{date}에 마지막으로 업데이트됨", "privacy_policy.title": "개인정보처리방침", + "recommended": "추천함", "refresh": "새로고침", "regeneration_indicator.label": "불러오는 중…", "regeneration_indicator.sublabel": "홈 피드를 준비하고 있습니다!", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index af9a3eaa0..4cb95426a 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -30,14 +30,17 @@ "account.endorse": "Savybė profilyje", "account.featured_tags.last_status_at": "Paskutinį kartą paskelbta {date}", "account.featured_tags.last_status_never": "Nėra įrašų", + "account.featured_tags.title": "{name} rekomenduojamos grotažymės", "account.follow": "Sekti", "account.followers": "Sekėjai", "account.followers.empty": "Šio naudotojo dar niekas neseka.", "account.followers_counter": "{count, plural, one {{counter} sekėjas (-a)} few {{counter} sekėjai} many {{counter} sekėjo} other {{counter} sekėjų}}", "account.following": "Seka", + "account.following_counter": "{count, plural, one {{counter} Seka} few {{counter} Seka} many {{counter} Seka} other {{counter} Seka}}", "account.follows.empty": "Šis (-i) naudotojas (-a) dar nieko neseka.", "account.follows_you": "Seka tave", "account.go_to_profile": "Eiti į profilį", + "account.hide_reblogs": "Slėpti \"boosts\" iš @{name}", "account.in_memoriam": "Atminimui.", "account.joined_short": "Prisijungė", "account.languages": "Keisti prenumeruojamas kalbas", @@ -58,14 +61,19 @@ "account.requested": "Laukiama patvirtinimo. Spausk, kad atšaukti sekimo užklausą.", "account.requested_follow": "{name} paprašė tave sekti", "account.share": "Bendrinti @{name} profilį", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", - "account.unblock_domain": "Unhide {domain}", + "account.show_reblogs": "Rodyti \"boosts\" iš @{name}", + "account.statuses_counter": "{count, plural, one {{counter} įrašas} few {{counter} įrašai} many {{counter} įrašo} other {{counter} įrašų}}", + "account.unblock": "Atblokuoti @{name}", + "account.unblock_domain": "Atblokuoti domeną {domain}", "account.unblock_short": "Atblokuoti", + "account.unendorse": "Nerodyti profilyje", "account.unfollow": "Nebesekti", "account.unmute": "Atitildyti @{name}", "account.unmute_notifications_short": "Atitildyti pranešimus", "account.unmute_short": "Atitildyti", "account_note.placeholder": "Spausk norėdamas (-a) pridėti pastabą", + "admin.dashboard.daily_retention": "Vartotojų išbuvimo rodiklis pagal dieną po registracijos", + "admin.dashboard.monthly_retention": "Vartotojų išbuvimo rodiklis pagal mėnesį po registracijos", "admin.dashboard.retention.average": "Vidurkis", "admin.dashboard.retention.cohort": "Registravimo mėnuo", "admin.dashboard.retention.cohort_size": "Nauji naudotojai", @@ -92,6 +100,7 @@ "bundle_column_error.routing.body": "Prašyto puslapio nepavyko rasti. Ar esi tikras (-a), kad adreso juostoje nurodytas URL adresas yra teisingas?", "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Uždaryti", + "bundle_modal_error.message": "Kraunant šį komponentą kažkas nepavyko.", "bundle_modal_error.retry": "Bandyti dar kartą", "closed_registrations.other_server_instructions": "Kadangi Mastodon yra decentralizuotas, gali susikurti paskyrą kitame serveryje ir vis tiek bendrauti su šiuo serveriu.", "closed_registrations_modal.description": "Sukurti paskyrą {domain} šiuo metu neįmanoma, tačiau nepamiršk, kad norint naudotis Mastodon nebūtina turėti paskyrą {domain}.", @@ -116,50 +125,76 @@ "column.public": "Federacinė laiko skalė", "column_back_button.label": "Atgal", "column_header.hide_settings": "Slėpti nustatymus", + "column_header.moveLeft_settings": "Judinti stulpelį į kairę", + "column_header.moveRight_settings": "Judinti stulpelį į dešinę", "column_header.pin": "Prisegti", "column_header.show_settings": "Rodyti nustatymus", "column_header.unpin": "Atsegti", "column_subheading.settings": "Nustatymai", + "community.column_settings.local_only": "Tik vietinis", "community.column_settings.media_only": "Tik medija", + "community.column_settings.remote_only": "Tik nuotolinis", "compose.language.change": "Keisti kalbą", "compose.language.search": "Ieškoti kalbų...", "compose.published.body": "Įrašas paskelbtas.", + "compose.published.open": "Atidaryti", + "compose.saved.body": "Įrašas išsaugotas.", "compose_form.direct_message_warning_learn_more": "Sužinoti daugiau", "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.", + "compose_form.lock_disclaimer": "Jūsų paskyra nėra {locked}. Kiekvienas gali jus sekti ir peržiūrėti tik sekėjams skirtus įrašus.", + "compose_form.lock_disclaimer.lock": "užrakinta", "compose_form.placeholder": "Kas tavo mintyse?", "compose_form.poll.add_option": "Pridėti pasirinkimą", "compose_form.poll.duration": "Apklausos trukmė", "compose_form.poll.option_placeholder": "Pasirinkimas {number}", "compose_form.poll.remove_option": "Pašalinti šį pasirinkimą", "compose_form.poll.switch_to_multiple": "Keisti apklausą, kad būtų galima pasirinkti kelis pasirinkimus", - "compose_form.publish_form": "Publish", - "compose_form.sensitive.hide": "{count, plural, one {Žymėti mediją kaip jautrią} few {Žymėti medijas kaip jautrias} many {Žymėti medijos kaip jautrios} other {Žymėti medijų kaip jautrių}}", - "compose_form.sensitive.marked": "{count, plural, one {Medija pažymėta kaip jautri} few {Medijos pažymėtos kaip jautrios} many {Medijos pažymėta kaip jautrios} other {Medijų pažymėtos kaip jautrios}}", - "compose_form.sensitive.unmarked": "{count, plural, one {Medija nepažymėta kaip jautri} few {Medijos nepažymėtos kaip jautrios} many {Medijos nepažymėta kaip jautri} other {Medijų nepažymėta kaip jautrios}}", - "compose_form.spoiler.marked": "Text is hidden behind warning", + "compose_form.poll.switch_to_single": "Pakeisti apklausą, kad būtų galima pasirinkti vieną variantą", + "compose_form.publish": "Skelbti", + "compose_form.publish_form": "Naujas įrašas", + "compose_form.publish_loud": "{publish}!", + "compose_form.save_changes": "Išsaugoti pakeitimus", + "compose_form.sensitive.hide": "{count, plural, one {Žymėti mediją kaip jautrią} few {Žymėti medijas kaip jautrias} many {Žymėti medijo kaip jautrio} other {Žymėti medijų kaip jautrių}}", + "compose_form.sensitive.marked": "{count, plural, one {Medija pažymėta kaip jautri} few {Medijos pažymėtos kaip jautrios} many {Medijo pažymėta kaip jautrio} other {Medijų pažymėtų kaip jautrių}}", + "compose_form.sensitive.unmarked": "{count, plural, one {Medija nepažymėta kaip jautri} few {Medijos nepažymėtos kaip jautrios} many {Medijo nepažymėta kaip jautrio} other {Medijų nepažymėtų kaip jautrių}}", + "compose_form.spoiler.marked": "Pašalinti turinio įspėjimą", "compose_form.spoiler.unmarked": "Pridėti turinio įspėjimą", "compose_form.spoiler_placeholder": "Rašyk savo įspėjimą čia", "confirmation_modal.cancel": "Atšaukti", "confirmations.block.block_and_report": "Blokuoti ir pranešti", "confirmations.block.confirm": "Blokuoti", "confirmations.block.message": "Ar tikrai nori užblokuoti {name}?", + "confirmations.cancel_follow_request.confirm": "Atšaukti prašymą", + "confirmations.cancel_follow_request.message": "Ar tikrai nori atšaukti savo prašymą sekti {name}?", "confirmations.delete.confirm": "Ištrinti", "confirmations.delete.message": "Are you sure you want to delete this status?", + "confirmations.delete_list.confirm": "Ištrinti", + "confirmations.delete_list.message": "Ar tikrai nori visam laikui ištrinti šį sąrašą?", "confirmations.discard_edit_media.confirm": "Atmesti", "confirmations.discard_edit_media.message": "Turi neišsaugotų medijos aprašymo ar peržiūros pakeitimų, vis tiek juos atmesti?", "confirmations.domain_block.confirm": "Hide entire domain", + "confirmations.edit.confirm": "Redaguoti", + "confirmations.edit.message": "Redaguojant dabar, bus perrašyta šiuo metu kuriama žinutė. Ar tikrai nori tęsti?", "confirmations.logout.confirm": "Atsijungti", "confirmations.logout.message": "Ar tikrai nori atsijungti?", "confirmations.mute.confirm": "Nutildyti", "confirmations.mute.explanation": "Tai paslėps jų įrašus ir įrašus, kuriuose jie menėmi, tačiau jie vis tiek galės matyti tavo įrašus ir sekti.", "confirmations.reply.confirm": "Atsakyti", - "confirmations.reply.message": "Atsakydamas (-a) dabar perrašysi šiuo metu rašomą žinutę. Ar tikrai nori tęsti?", + "confirmations.reply.message": "Atsakant dabar, bus perrašyta metu kuriama žinutė. Ar tikrai nori tęsti?", "confirmations.unfollow.confirm": "Nebesekti", + "conversation.mark_as_read": "Žymėti kaip skaitytą", + "conversation.open": "Peržiūrėti pokalbį", + "conversation.with": "Su {names}", "copy_icon_button.copied": "Nukopijuota į iškarpinę", + "copypaste.copied": "Nukopijuota", + "copypaste.copy_to_clipboard": "Kopijuoti į iškarpinę", + "disabled_account_banner.account_settings": "Paskyros nustatymai", "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", "embed.instructions": "Embed this status on your website by copying the code below.", + "embed.preview": "Štai kaip tai atrodys:", + "emoji_button.objects": "Objektai", "emoji_button.search": "Paieška...", "empty_column.account_hides_collections": "Šis naudotojas (-a) pasirinko nepadaryti šią informaciją prieinamą", "empty_column.account_timeline": "No toots here!", @@ -168,12 +203,64 @@ "empty_column.hashtag": "Nėra nieko šiame saitažodyje kol kas.", "empty_column.home": "Your home timeline is empty! Follow more people to fill it up. {suggestions}", "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", + "explore.title": "Naršyti", + "explore.trending_links": "Naujienos", + "explore.trending_statuses": "Įrašai", + "explore.trending_tags": "Saitažodžiai", + "filter_modal.added.context_mismatch_explanation": "Ši filtro kategorija netaikoma kontekste, kuriame peržiūrėjote šį pranešimą. Jei norite, kad pranešimas būtų filtruojamas ir šiame kontekste, turėsite redaguoti filtrą.", + "filter_modal.added.context_mismatch_title": "Konteksto neatitikimas!", + "filter_modal.added.expired_explanation": "Ši filtro kategorija nustojo galioti, kad ji būtų taikoma, turėsite pakeisti galiojimo datą.", + "filter_modal.added.expired_title": "Pasibaigė filtro galiojimo laikas!", + "filter_modal.added.review_and_configure": "Norėdami peržiūrėti ir toliau konfigūruoti šią filtro kategoriją, eikite į {settings_link}.", + "filter_modal.added.review_and_configure_title": "Filtro nuostatos", + "filter_modal.added.settings_link": "nustatymų puslapis", + "filter_modal.added.short_explanation": "Šis pranešimas buvo įtrauktas į šią filtro kategoriją: {title}.", + "filter_modal.added.title": "Pridėtas filtras!", + "filter_modal.select_filter.context_mismatch": "netaikoma šiame kontekste", + "filter_modal.select_filter.expired": "nebegalioja", + "filter_modal.select_filter.prompt_new": "Nauja kategorija: {name}", + "filter_modal.select_filter.search": "Ieškoti arba sukurti", + "filter_modal.select_filter.subtitle": "Naudoti esamą kategoriją arba sukurti naują", + "filter_modal.select_filter.title": "Filtruoti šį įrašą", + "filter_modal.title.status": "Filtruoti šį įrašą", + "firehose.all": "Visi", "firehose.local": "Šis serveris", + "firehose.remote": "Kiti serveriai", + "follow_request.authorize": "Autorizuoti", + "follow_request.reject": "Atmesti", "follow_requests.unlocked_explanation": "Nors tavo paskyra neužrakinta, {domain} personalas mano, kad galbūt norėsi rankiniu būdu patikrinti šių paskyrų sekimo užklausas.", "followed_tags": "Sekamos saitažodžiai", "footer.about": "Apie", + "footer.directory": "Profilių katalogas", + "footer.get_app": "Gauti programėlę", "footer.invite": "Kviesti žmones", + "footer.keyboard_shortcuts": "Spartieji klavišai", + "footer.privacy_policy": "Privatumo politika", + "footer.source_code": "Peržiūrėti šaltinio kodą", + "footer.status": "Būsena", + "generic.saved": "Išsaugoti", + "getting_started.heading": "Pradedant", + "hashtag.column_header.tag_mode.all": "ir {additional}", + "hashtag.column_header.tag_mode.any": "ar {additional}", + "hashtag.column_header.tag_mode.none": "be {additional}", + "hashtag.column_settings.select.no_options_message": "Pasiūlymų nerasta", + "hashtag.column_settings.select.placeholder": "Įvesti grotažymes…", + "hashtag.column_settings.tag_mode.all": "Visi šie", + "hashtag.column_settings.tag_mode.any": "Bet kuris šių", + "hashtag.column_settings.tag_mode.none": "Nė vienas iš šių", "hashtag.column_settings.tag_toggle": "Include additional tags in this column", + "hashtag.counter_by_accounts": "{count, plural,one {{counter} dalyvis}other {{counter} dalyviai}}", + "hashtag.counter_by_uses": "{count, plural, one {{counter} įrašas} other {{counter} įrašų}}", + "hashtag.counter_by_uses_today": "{count, plural, one {{counter} įrašas} other {{counter} įrašų}} šiandien", + "hashtag.follow": "Sekti grotažymę", + "hashtag.unfollow": "Nesekti grotažymės", + "hashtags.and_other": "…ir{count, plural,other {#daugiau}}", + "home.actions.go_to_explore": "Žiūrėti kas populiaru", + "home.actions.go_to_suggestions": "Rasti žmonių sekimui", + "home.column_settings.basic": "Pagrindinis", + "home.column_settings.show_reblogs": "Rodyti \"boosts\"", + "home.column_settings.show_replies": "Rodyti atsakymus", + "home.hide_announcements": "Slėpti skelbimus", "interaction_modal.no_account_yet": "Nesi Mastodon?", "interaction_modal.on_another_server": "Kitame serveryje", "interaction_modal.on_this_server": "Šiame serveryje", @@ -214,8 +301,18 @@ "lightbox.close": "Uždaryti", "loading_indicator.label": "Kraunama…", "media_gallery.toggle_visible": "{number, plural, one {Slėpti vaizdą} few {Slėpti vaizdus} many {Slėpti vaizdo} other {Slėpti vaizdų}}", + "moved_to_account_banner.text": "Tavo paskyra {disabledAccount} šiuo metu yra išjungta, nes persikėlei į {movedToAccount}.", + "mute_modal.duration": "Trukmė", + "mute_modal.hide_notifications": "Slėpti šio naudotojo pranešimus?", "navigation_bar.compose": "Compose new toot", + "navigation_bar.discover": "Atrasti", "navigation_bar.domain_blocks": "Hidden domains", + "navigation_bar.edit_profile": "Redaguoti profilį", + "navigation_bar.explore": "Naršyti", + "navigation_bar.favourites": "Mėgstamiausi", + "navigation_bar.filters": "Nutylėti žodžiai", + "navigation_bar.follow_requests": "Sekti prašymus", + "navigation_bar.followed_tags": "Sekti grotažymę", "navigation_bar.follows_and_followers": "Sekimai ir sekėjai", "navigation_bar.lists": "Sąrašai", "navigation_bar.logout": "Atsijungti", @@ -224,7 +321,16 @@ "navigation_bar.personal": "Asmeninis", "navigation_bar.pins": "Pinned toots", "navigation_bar.preferences": "Nuostatos", + "navigation_bar.public_timeline": "Federuota laiko juosta", + "navigation_bar.search": "Ieškoti", + "navigation_bar.security": "Apsauga", "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", + "notification.admin.report": "{name} pranešė.{target}", + "notification.admin.sign_up": "{name} užsiregistravo", + "notification.favourite": "{name} pamėgo jūsų įrašą", + "notification.follow": "{name} pradėjo jus sekti", + "notification.follow_request": "{name} nori tapti jūsų sekėju", + "notification.mention": "{name} paminėjo jus", "notification.own_poll": "Tavo apklausa baigėsi", "notification.poll": "Apklausa, kurioje balsavai, pasibaigė", "notification.reblog": "{name} boosted your status", @@ -233,15 +339,51 @@ "notifications.clear": "Išvalyti pranešimus", "notifications.clear_confirmation": "Ar tikrai nori visam laikui išvalyti visus pranešimus?", "notifications.column_settings.admin.report": "Nauji ataskaitos:", + "notifications.column_settings.admin.sign_up": "Nauji prisiregistravimai:", + "notifications.column_settings.alert": "Darbalaukio pranešimai", + "notifications.column_settings.favourite": "Mėgstamiausi:", + "notifications.column_settings.filter_bar.advanced": "Rodyti visas kategorijas", + "notifications.column_settings.filter_bar.category": "Greito filtro juosta", + "notifications.column_settings.filter_bar.show_bar": "Rodyti filtro juostą", + "notifications.column_settings.follow": "Nauji sekėjai:", + "notifications.column_settings.follow_request": "Nauji prašymai sekti:", + "notifications.column_settings.mention": "Paminėjimai:", + "notifications.column_settings.poll": "Balsavimo rezultatai:", + "notifications.column_settings.push": "\"Push\" pranešimai", + "notifications.column_settings.reblog": "\"Boost\" kiekis:", + "notifications.column_settings.show": "Rodyti stulpelyje", + "notifications.column_settings.sound": "Paleisti garsą", "notifications.column_settings.status": "New toots:", + "notifications.column_settings.unread_notifications.category": "Neperskaityti pranešimai", + "notifications.column_settings.unread_notifications.highlight": "Paryškinti neperskaitytus pranešimus", + "notifications.column_settings.update": "Redagavimai:", + "notifications.filter.all": "Visi", + "notifications.filter.boosts": "\"Boost\" kiekis", + "notifications.filter.favourites": "Mėgstamiausi", + "notifications.filter.follows": "Sekimai", "notifications.filter.mentions": "Paminėjimai", + "notifications.filter.polls": "Balsavimo rezultatai", + "notifications.filter.statuses": "Atnaujinimai iš žmonių kuriuos sekate", + "notifications.grant_permission": "Suteikti leidimą.", + "notifications.group": "{count} pranešimai", + "notifications.mark_as_read": "Pažymėti kiekvieną pranešimą kaip perskaitytą", + "notifications.permission_denied": "Darbalaukio pranešimai nepasiekiami dėl anksčiau atmestos naršyklės leidimų užklausos", + "notifications.permission_denied_alert": "Negalima įjungti darbalaukio pranešimų, nes prieš tai naršyklės leidimas buvo atmestas", + "notifications.permission_required": "Darbalaukio pranešimai nepasiekiami, nes nesuteiktas reikiamas leidimas.", + "notifications_permission_banner.enable": "Įjungti darbalaukio pranešimus", + "notifications_permission_banner.how_to_control": "Jei norite gauti pranešimus, kai \"Mastodon\" nėra atidarytas, įjunkite darbalaukio pranešimus. Įjungę darbalaukio pranešimus, galite tiksliai valdyti, kokių tipų sąveikos generuoja darbalaukio pranešimus, naudodamiesi pirmiau esančiu mygtuku {icon}.", + "onboarding.action.back": "Gražinkite mane atgal", + "onboarding.actions.back": "Gražinkite mane atgal", "onboarding.actions.go_to_explore": "See what's trending", "onboarding.actions.go_to_home": "Go to your home feed", + "onboarding.compose.template": "Sveiki #Mastodon!", + "onboarding.follows.empty": "Deja, šiuo metu jokių rezultatų parodyti negalima. Galite pabandyti naudoti paiešką arba naršyti atradimo puslapyje, kad surastumėte žmonių, kuriuos norite sekti, arba pabandyti vėliau.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.discoverable": "Padaryti mano profilį atrandamą", + "onboarding.profile.discoverable_hint": "Kai pasirenki Mastodon atrandamumą, tavo įrašai gali būti rodomi paieškos rezultatuose ir trendose, o profilis gali būti siūlomas panašių interesų turintiems žmonėms.", "onboarding.profile.display_name": "Rodomas vardas", "onboarding.profile.display_name_hint": "Tavo pilnas vardas arba linksmas vardas…", - "onboarding.profile.indexable": "Įtraukti viešus įrašus į paieškos rezultatus", "onboarding.profile.lead": "Gali visada tai užbaigti vėliau nustatymuose, kur yra dar daugiau pritaikymo parinkčių.", "onboarding.profile.note": "Biografija", "onboarding.profile.note_hint": "Gali @paminėti kitus žmones arba #saitažodžius…", @@ -249,12 +391,15 @@ "onboarding.profile.title": "Profilio konfigūravimas", "onboarding.profile.upload_avatar": "Įkelti profilio nuotrauką", "onboarding.profile.upload_header": "Įkelti profilio antraštę", + "onboarding.share.lead": "Praneškite žmonėms, kaip jus rasti \"Mastodon\"!", "onboarding.share.message": "Aš {username} #Mastodon! Ateik sekti manęs adresu {url}", + "onboarding.share.next_steps": "Galimi kiti žingsniai:", "onboarding.start.lead": "Dabar esi Mastodon dalis – unikalios decentralizuotos socialinės žiniasklaidos platformos, kurioje tu, o ne algoritmas, pats nustatai savo patirtį. Pradėkime tavo kelionę šioje naujoje socialinėje erdvėje:", "onboarding.start.skip": "Want to skip right ahead?", "onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.", "onboarding.steps.follow_people.title": "Follow {count, plural, one {one person} other {# people}}", "onboarding.steps.publish_status.body": "Say hello to the world.", + "onboarding.steps.publish_status.title": "Susikūrk savo pirmąjį įrašą", "onboarding.steps.setup_profile.body": "Others are more likely to interact with you with a filled out profile.", "onboarding.steps.setup_profile.title": "Customize your profile", "onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!", @@ -270,30 +415,108 @@ "privacy.unlisted.long": "Matomas visiems, bet atsisakyta atradimo funkcijų", "privacy.unlisted.short": "Neįtrauktas į sąrašą", "privacy_policy.last_updated": "Paskutinį kartą atnaujinta {date}", - "report.placeholder": "Type or paste additional comments", - "report.submit": "Submit report", + "recommended": "Rekomenduojama", + "relative_time.hours": "{number} val.", + "relative_time.just_now": "dabar", + "relative_time.minutes": "{number} min.", + "relative_time.seconds": "{number} sek.", + "relative_time.today": "šiandien", + "report.mute_explanation": "Jų įrašų nematysi. Jie vis tiek gali tave sekti ir matyti įrašus, bet nežinos, kad jie nutildyti.", + "report.next": "Tęsti", + "report.placeholder": "Papildomi komentarai", + "report.reasons.dislike": "Man tai nepatinka", + "report.reasons.dislike_description": "Tai nėra tai, ką nori matyti", + "report.reasons.legal": "Tai nelegalu", + "report.reasons.legal_description": "Manai, kad tai pažeidžia tavo arba serverio šalies įstatymus", + "report.reasons.other": "Tai kažkas kita", + "report.rules.subtitle": "Pasirink viską, kas tinka", + "report.rules.title": "Kokios taisyklės pažeidžiamos?", + "report.statuses.subtitle": "Pasirinkti viską, kas tinka", + "report.statuses.title": "Ar yra kokių nors įrašų, patvirtinančių šį pranešimą?", + "report.submit": "Pateikti", "report.target": "Report {target}", + "report.thanks.take_action": "Čia pateikiamos galimybės kontroliuoti, ką matote \"Mastodon\":", + "report.thanks.take_action_actionable": "Kol tai peržiūrėsime, galite imtis veiksmų prieš @{name}:", + "report.thanks.title": "Nenorite to matyti?", + "report.thanks.title_actionable": "Ačiū, kad pranešėte, mes tai išnagrinėsime.", + "report.unfollow": "Nebesekti @{name}", + "report.unfollow_explanation": "Jūs sekate šią paskyrą. Norėdami nebematyti jų įrašų savo pagrindiniame kanale, panaikinkite jų sekimą.", "report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached", + "search.placeholder": "Paieška", + "search.search_or_paste": "Ieškok arba įklijuok URL", + "search_popout.full_text_search_disabled_message": "Nepasiekima {domain}.", + "search_popout.language_code": "ISO kalbos kodas", + "search_popout.specific_date": "konkreti data", + "search_popout.user": "naudotojas", + "search_results.accounts": "Profiliai", + "search_results.all": "Visi", + "search_results.hashtags": "Saitažodžiai", + "search_results.nothing_found": "Nepavyko rasti nieko pagal šiuos paieškos terminus.", "search_results.statuses": "Toots", - "sign_in_banner.sign_in": "Sign in", + "sign_in_banner.sign_in": "Prisijungimas", + "sign_in_banner.text": "Prisijunk, kad galėtum sekti profilius arba saitažodžius, mėgsti, bendrinti ir atsakyti į įrašus. Taip pat gali bendrauti iš savo paskyros kitame serveryje.", "status.admin_status": "Open this status in the moderation interface", - "status.copy": "Copy link to status", + "status.copy": "Kopijuoti nuorodą į įrašą", + "status.delete": "Ištrinti", + "status.edit": "Redaguoti", + "status.edited": "Redaguota {date}", "status.edited_x_times": "Edited {count, plural, one {# time} other {# times}}", + "status.hide": "Slėpti įrašą", + "status.load_more": "Pakrauti daugiau", "status.media.open": "Spausk, kad atidaryti", - "status.media.show": "Spausk, kad pamatyti", + "status.media.show": "Spausk, kad matyti", "status.media_hidden": "Paslėpta medija", + "status.mention": "Paminėti @{name}", + "status.more": "Daugiau", "status.open": "Expand this status", - "status.pinned": "Pinned toot", + "status.pin": "Prisegti prie profilio", + "status.pinned": "Prisegtas įrašas", + "status.read_more": "Skaityti daugiau", "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", - "status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}", + "status.redraft": "Ištrinti ir iš naujo parengti juodraštį", + "status.reply": "Atsakyti", + "status.replyAll": "Atsakyti į giją", + "status.report": "Pranešti @{name}", + "status.sensitive_warning": "Jautrus turinys", + "status.share": "Bendrinti", + "status.show_filter_reason": "Rodyti vis tiek", + "status.show_less": "Rodyti mažiau", + "status.show_less_all": "Rodyti mažiau visiems", + "status.show_more": "Rodyti daugiau", + "status.show_more_all": "Rodyti daugiau visiems", + "status.show_original": "Rodyti originalą", + "status.title.with_attachments": "{user}{attachmentCount, plural, one {priedas} few {{attachmentCount} priedai} many {{attachmentCount} priedo} other {{attachmentCount} priedų}}", + "status.translate": "Versti", + "status.translated_from_with": "Išversta iš {lang} naudojant {provider}", "status.uncached_media_warning": "Peržiūra nepasiekiama", - "timeline_hint.resources.statuses": "Older toots", + "tabs_bar.home": "Pradžia", + "tabs_bar.notifications": "Pranešimai", + "time_remaining.days": "Liko {number, plural, one {# diena} few {# dienos} many {# dieno} other {# dienų}}", + "timeline_hint.remote_resource_not_displayed": "{resource} iš kitų serverių nerodomas.", + "timeline_hint.resources.followers": "Sekėjai", + "timeline_hint.resources.follows": "Seka", + "timeline_hint.resources.statuses": "Senesni įrašai", "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {# days}}", + "ui.beforeunload": "Jei paliksi Mastodon, tavo juodraštis bus prarastas.", + "units.short.thousand": "{count} tūkst.", "upload_form.audio_description": "Describe for people with hearing loss", "upload_form.description": "Describe for the visually impaired", "upload_form.description_missing": "Nėra pridėto aprašymo", "upload_form.edit": "Redaguoti", + "upload_form.undo": "Ištrinti", "upload_form.video_description": "Describe for people with hearing loss or visual impairment", + "upload_modal.choose_image": "Pasirinkti vaizdą", + "upload_modal.description_placeholder": "Greita rudoji lapė peršoka tinginį šunį", "upload_modal.edit_media": "Redaguoti mediją", - "upload_progress.label": "Uploading…" + "upload_progress.label": "Įkeliama...", + "upload_progress.processing": "Apdorojama…", + "username.taken": "Šis naudotojo vardas užimtas. Pabandyk kitą.", + "video.close": "Uždaryti vaizdo įrašą", + "video.download": "Atsisiųsti failą", + "video.exit_fullscreen": "Išeiti iš viso ekrano", + "video.fullscreen": "Visas ekranas", + "video.hide": "Slėpti vaizdo įrašą", + "video.mute": "Nutildyti garsą", + "video.play": "Leisti", + "video.unmute": "Atitildyti garsą" } diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index e0fa73ef6..b39f1a5c8 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Helaas kunnen op dit moment geen resultaten worden getoond. Je kunt proberen te zoeken of op de verkenningspagina te bladeren om mensen te vinden die je kunt volgen, of probeer het later opnieuw.", "onboarding.follows.lead": "Jouw starttijdlijn is de belangrijkste manier om Mastodon te ervaren. Hoe meer mensen je volgt, hoe actiever en interessanter het zal zijn. Om te beginnen, zijn hier enkele suggesties:", "onboarding.follows.title": "Je starttijdlijn aan jouw wensen aanpassen", - "onboarding.profile.discoverable": "Profiel en berichten laten uitlichten in ontdekkingsalgoritmes", + "onboarding.profile.discoverable": "Maak mij profiel ontdekbaar", + "onboarding.profile.discoverable_hint": "Wanneer je kiest voor Mastodon kun je berichten weergeven in zoekresultaten en trending, en je profiel kan worden voorgesteld aan mensen met vergelijkbare interesses.", "onboarding.profile.display_name": "Weergavenaam", "onboarding.profile.display_name_hint": "Jouw volledige naam of een leuke bijnaam…", - "onboarding.profile.indexable": "Openbare berichten in zoekresultaten opnemen", "onboarding.profile.lead": "Je kunt dit later altijd aanvullen in de instellingen, waar nog meer aanpassingsopties beschikbaar zijn.", "onboarding.profile.note": "Biografie", "onboarding.profile.note_hint": "Je kunt andere mensen @vermelden of #hashtags gebruiken…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Minder openbaar", "privacy_policy.last_updated": "Laatst bijgewerkt op {date}", "privacy_policy.title": "Privacybeleid", + "recommended": "Aanbevolen", "refresh": "Vernieuwen", "regeneration_indicator.label": "Aan het laden…", "regeneration_indicator.sublabel": "Jouw starttijdlijn wordt aangemaakt!", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index 5e4459e43..4750b1adc 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -481,10 +481,8 @@ "onboarding.follows.empty": "Me kan ikkje visa deg nokon resultat no. Du kan prøva å søkja eller bla gjennom utforsk-sida for å finna folk å fylgja, eller du kan prøva att seinare.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", - "onboarding.profile.discoverable": "Ta med profilen og innlegga i oppdagingsalgoritmar", "onboarding.profile.display_name": "Synleg namn", "onboarding.profile.display_name_hint": "Det fulle namnet eller kallenamnet ditt…", - "onboarding.profile.indexable": "Ta med offentlege innlegg i søkjeresultat", "onboarding.profile.lead": "Du kan alltid fullføra dette seinare i innstillingane, og der er det endå fleire tilpassingsalternativ.", "onboarding.profile.note": "Om meg", "onboarding.profile.note_hint": "Du kan @nemna folk eller #emneknaggar…", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index 0dce1e666..1739d4aa3 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -481,10 +481,8 @@ "onboarding.follows.empty": "Dessverre kan ingen resultater vises akkurat nå. Du kan prøve å bruke søk eller bla gjennom utforske-siden for å finne folk å følge, eller prøve igjen senere.", "onboarding.follows.lead": "Hjem-skjermen din er den viktigste måten å oppleve Mastodon på. Jo flere du følger, jo mer aktiv og interessant blir det. For å komme i gang, er her noen forslag:", "onboarding.follows.title": "Populært på Mastodon", - "onboarding.profile.discoverable": "Fremhevede profiler og innlegg i oppdagelsealgoritmer", "onboarding.profile.display_name": "Visningsnavn", "onboarding.profile.display_name_hint": "Ditt fulle navn eller ditt morsomme navn…", - "onboarding.profile.indexable": "Inkluder offentlige innlegg i søkeresultatene", "onboarding.profile.lead": "Du kan alltid fullføre dette senere i innstillingene, der enda flere tilpasningsalternativer er tilgjengelige.", "onboarding.profile.note": "Om meg", "onboarding.profile.note_hint": "Du kan @nevne andre eller #emneknagger…", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index d316143e1..1e6985df2 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Niestety w tej chwili nie można przedstawić żadnych wyników. Możesz spróbować wyszukać lub przeglądać stronę, aby znaleźć osoby do śledzenia, lub spróbować ponownie później.", "onboarding.follows.lead": "Zarządasz swoim własnym kanałem. Im więcej ludzi śledzisz, tym bardziej aktywny i ciekawy będzie Twój kanał. Te profile mogą być dobrym punktem wyjścia— możesz przestać je obserwować w dowolnej chwili!", "onboarding.follows.title": "Popularne na Mastodonie", - "onboarding.profile.discoverable": "Udostępniaj profil i wpisy funkcjom odkrywania", + "onboarding.profile.discoverable": "Spraw mój profil odkrywalnym", + "onboarding.profile.discoverable_hint": "Kiedy zapisujesz się do odkrywalności w Mastodonie, twoje wpisy mogą pokazywać się w wynikach wyszukiwania i trendach, a twój profil może być sugerowany użytkownikom o podobnych zainteresowaniach.", "onboarding.profile.display_name": "Nazwa wyświetlana", "onboarding.profile.display_name_hint": "Twoje imię lub pseudonim…", - "onboarding.profile.indexable": "Pokaż publiczne wpisy w wynikach wyszukiwania", "onboarding.profile.lead": "Możesz wypełnić te dane później w menu ustawień, gdzie dostępnych jest jeszcze więcej opcji.", "onboarding.profile.note": "O mnie", "onboarding.profile.note_hint": "Możesz @wspomnieć użytkowników albo #hasztagi…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Niewidoczny", "privacy_policy.last_updated": "Data ostatniej aktualizacji: {date}", "privacy_policy.title": "Polityka prywatności", + "recommended": "Zalecane", "refresh": "Odśwież", "regeneration_indicator.label": "Ładuję…", "regeneration_indicator.sublabel": "Twoja oś czasu jest przygotowywana!", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 7ce63e9b1..68f367abc 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -21,6 +21,7 @@ "account.blocked": "Bloqueado", "account.browse_more_on_origin_server": "Veja mais no perfil original", "account.cancel_follow_request": "Cancelar solicitação para seguir", + "account.copy": "Copiar link do perfil", "account.direct": "Mencione em privado @{name}", "account.disable_notifications": "Cancelar notificações de @{name}", "account.domain_blocked": "Domínio bloqueado", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marcar como lida", "conversation.open": "Ver conversa", "conversation.with": "Com {names}", + "copy_icon_button.copied": "Copiado para a área de transferência", "copypaste.copied": "Copiado", "copypaste.copy_to_clipboard": "Copiar para a área de transferência", "directory.federated": "Do fediverso conhecido", @@ -390,6 +392,7 @@ "lists.search": "Procurar entre as pessoas que segue", "lists.subheading": "Suas listas", "load_pending": "{count, plural, one {# novo item} other {# novos items}}", + "loading_indicator.label": "Carregando…", "media_gallery.toggle_visible": "{number, plural, one {Ocultar mídia} other {Ocultar mídias}}", "moved_to_account_banner.text": "Sua conta {disabledAccount} está desativada porque você a moveu para {movedToAccount}.", "mute_modal.duration": "Duração", @@ -478,6 +481,17 @@ "onboarding.follows.empty": "Infelizmente, não é possível mostrar resultados agora. Você pode tentar usar a busca ou navegar na página de exploração para encontrar pessoas para seguir, ou tentar novamente mais tarde.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular no Mastodon", + "onboarding.profile.discoverable": "Tornar meu perfil descobrível", + "onboarding.profile.discoverable_hint": "Quando você aceita a capacidade de descoberta no Mastodon, suas postagens podem aparecer nos resultados de pesquisa e nas tendências, e seu perfil pode ser sugerido a pessoas com interesses similares aos seus.", + "onboarding.profile.display_name": "Nome de exibição", + "onboarding.profile.display_name_hint": "Seu nome completo ou apelido…", + "onboarding.profile.lead": "Você sempre pode completar isso mais tarde nas configurações, onde ainda mais opções de personalização estão disponíveis.", + "onboarding.profile.note": "Biografia", + "onboarding.profile.note_hint": "Você pode @mencionar outras pessoas ou usar #hashtags…", + "onboarding.profile.save_and_continue": "Salvar e continuar", + "onboarding.profile.title": "Configuração do perfil", + "onboarding.profile.upload_avatar": "Enviar imagem de perfil", + "onboarding.profile.upload_header": "Carregar cabeçalho do perfil", "onboarding.share.lead": "Deixe as pessoas saberem como elas podem te encontrar no Mastodon!", "onboarding.share.message": "Eu sou {username} no #Mastodon! Venha me seguir em {url}", "onboarding.share.next_steps": "Possíveis próximos passos:", @@ -521,6 +535,7 @@ "privacy.unlisted.short": "Não-listado", "privacy_policy.last_updated": "Atualizado {date}", "privacy_policy.title": "Política de privacidade", + "recommended": "Recomendado", "refresh": "Atualizar", "regeneration_indicator.label": "Carregando…", "regeneration_indicator.sublabel": "Sua página inicial está sendo preparada!", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index 0ad315152..36e09ac96 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Infelizmente, não é possível mostrar resultados neste momento. Pode tentar utilizar a pesquisa ou navegar na página \"Explorar\" para encontrar pessoas para seguir ou tentar novamente mais tarde.", "onboarding.follows.lead": "Você personaliza a sua própria página inicial. Quanto mais pessoas seguir, mais ativa e interessante ela será. Estes perfis podem ser um bom ponto de partida - pode sempre deixar de os seguir mais tarde!", "onboarding.follows.title": "Popular no Mastodon", - "onboarding.profile.discoverable": "Destacar perfil e publicações nos algoritmos de descoberta", + "onboarding.profile.discoverable": "Permitir que o meu perfil seja descoberto", + "onboarding.profile.discoverable_hint": "Quando opta pela possibilidade de ser descoberto no Mastodon, as suas mensagens podem aparecer nos resultados de pesquisa e nas tendências, e o seu perfil pode ser sugerido a pessoas com interesses semelhantes aos seus.", "onboarding.profile.display_name": "Nome a apresentar", "onboarding.profile.display_name_hint": "O seu nome completo ou o seu nome divertido…", - "onboarding.profile.indexable": "Incluir publicações públicas nos resultados de pesquisa", "onboarding.profile.lead": "Pode sempre completar isto mais tarde, nas configurações, onde ainda estão disponíveis mais opções de personalização.", "onboarding.profile.note": "Bio", "onboarding.profile.note_hint": "Pode @mencionar outras pessoas ou #hashtags…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Não listar", "privacy_policy.last_updated": "Última atualização em {date}", "privacy_policy.title": "Política de privacidade", + "recommended": "Recomendado", "refresh": "Actualizar", "regeneration_indicator.label": "A carregar…", "regeneration_indicator.sublabel": "A tua página inicial está a ser preparada!", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 24186794b..9115695d8 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -21,6 +21,7 @@ "account.blocked": "Blokovaný/á", "account.browse_more_on_origin_server": "Prehľadávaj viac na pôvodnom profile", "account.cancel_follow_request": "Zruš žiadosť o sledovanie", + "account.copy": "Skopíruj odkaz pre profil", "account.direct": "Spomeň @{name} súkromne", "account.disable_notifications": "Prestaň mi oznamovať, keď má @{name} príspevky", "account.domain_blocked": "Doména skrytá", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Označ za prečítané", "conversation.open": "Ukáž konverzáciu", "conversation.with": "S {names}", + "copy_icon_button.copied": "Skopírovaný do schránky", "copypaste.copied": "Skopírované", "copypaste.copy_to_clipboard": "Skopíruj do schránky", "directory.federated": "Zo známého fedivesmíru", @@ -477,6 +479,7 @@ "onboarding.follows.empty": "Žiaľ, momentálne sa nedajú zobraziť žiadne výsledky. Môžete skúsiť použiť vyhľadávanie alebo navštíviť stránku objavovania a nájsť ľudí, ktorých chcete sledovať, alebo to skúste znova neskôr.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.discoverable": "Urob môj profil objaviteľný", "onboarding.share.lead": "Daj ľudom vedieť, ako ťa môžu na Mastodone nájsť!", "onboarding.share.message": "Na Mastodone som {username}. Príď ma nasledovať na {url}", "onboarding.share.next_steps": "Ďalšie možné kroky:", @@ -520,6 +523,7 @@ "privacy.unlisted.short": "Verejne, ale nezobraziť v osi", "privacy_policy.last_updated": "Posledná úprava {date}", "privacy_policy.title": "Zásady súkromia", + "recommended": "Odporúčané", "refresh": "Obnoviť", "regeneration_indicator.label": "Načítava sa…", "regeneration_indicator.sublabel": "Tvoja domovská nástenka sa pripravuje!", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index d179a8656..21d198284 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -21,6 +21,7 @@ "account.blocked": "Blokirano", "account.browse_more_on_origin_server": "Brskaj več po izvirnem profilu", "account.cancel_follow_request": "Umakni zahtevo za sledenje", + "account.copy": "Kopiraj povezavo do profila", "account.direct": "Zasebno omeni @{name}", "account.disable_notifications": "Ne obveščaj me več, ko ima @{name} novo objavo", "account.domain_blocked": "Blokirana domena", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Označi kot prebrano", "conversation.open": "Pokaži pogovor", "conversation.with": "Z {names}", + "copy_icon_button.copied": "Kopirano v odložišče", "copypaste.copied": "Kopirano", "copypaste.copy_to_clipboard": "Kopiraj na odložišče", "directory.federated": "Iz znanega fediverzuma", @@ -390,6 +392,7 @@ "lists.search": "Iščite med ljudmi, katerim sledite", "lists.subheading": "Vaši seznami", "load_pending": "{count, plural, one {# nov element} two {# nova elementa} few {# novi elementi} other {# novih elementov}}", + "loading_indicator.label": "Nalaganje …", "media_gallery.toggle_visible": "{number, plural,one {Skrij sliko} two {Skrij sliki} other {Skrij slike}}", "moved_to_account_banner.text": "Vaš račun {disabledAccount} je trenutno onemogočen, ker ste se prestavili na {movedToAccount}.", "mute_modal.duration": "Trajanje", @@ -478,6 +481,17 @@ "onboarding.follows.empty": "Žal trenutno ni mogoče prikazati nobenih rezultatov. Lahko poskusite z iskanjem ali brskanjem po strani za raziskovanje, da poiščete osebe, ki jim želite slediti, ali poskusite znova pozneje.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Priljubljeno na Mastodonu", + "onboarding.profile.discoverable": "Naj bo moj profil mogoče najti", + "onboarding.profile.discoverable_hint": "Ko se odločite za razkrivanje na Mastodonu, se lahko vaše objave pojavijo v rezultatih iskanja in trendih, vaš profil pa se lahko predlaga ljudem, ki imajo podobne interese kot vi.", + "onboarding.profile.display_name": "Pojavno ime", + "onboarding.profile.display_name_hint": "Vaše polno ime ali lažno ime ...", + "onboarding.profile.lead": "To lahko vedno dokončate med nastavitvami, kjer je na voljo še več možnosti prilagajanja.", + "onboarding.profile.note": "Biografija", + "onboarding.profile.note_hint": "Druge osebe lahko @omenite ali #ključite ...", + "onboarding.profile.save_and_continue": "Shrani in nadaljuj", + "onboarding.profile.title": "Nastavitev profila", + "onboarding.profile.upload_avatar": "Naloži sliko profila", + "onboarding.profile.upload_header": "Naloži glavo profila", "onboarding.share.lead": "Povejte vsem, kako vas lahko najdejo na Mastodonu!", "onboarding.share.message": "Sem {username} na #Mastodon! Sledite mi na {url}", "onboarding.share.next_steps": "Možni naslednji koraki:", @@ -521,6 +535,7 @@ "privacy.unlisted.short": "Ni prikazano", "privacy_policy.last_updated": "Zadnja posodobitev {date}", "privacy_policy.title": "Pravilnik o zasebnosti", + "recommended": "Priporočeno", "refresh": "Osveži", "regeneration_indicator.label": "Nalaganje …", "regeneration_indicator.sublabel": "Vaš domači vir se pripravlja!", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index c3110aa56..86042a91e 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "Mjerisht, s’mund të shfaqen përfundime tani. Mund të provoni të përdorni kërkimin, ose të shfletoni faqen e eksplorimit, që të gjeni persona për ndjekje, ose të riprovoni më vonë.", "onboarding.follows.lead": "Ju kujdeseni për prurjen tuaj. Sa më tepër persona të tjerë të ndiqni, aq më aktive dhe interesante do të bëhet ajo. Këto profile mund të jenë një pikënisje e mirë—mundeni përherë të ndërpritni ndjekjen e tyre më vonë!", "onboarding.follows.title": "Popullore në Mastodon", - "onboarding.profile.discoverable": "Profilin dhe postimet bëji objekt të algoritmeve të zbulimit", + "onboarding.profile.discoverable": "Bëje profilin tim të zbulueshëm", + "onboarding.profile.discoverable_hint": "Kur zgjidhni të jeni i zbulueshëm në Mastodon, postimet tuaja mund të shfaqen në përfundime kërkimesh dhe gjëra në modë dhe profili juaj mund t’u sugjerohet njerëzve me interesa të ngjashme me ju.", "onboarding.profile.display_name": "Emër në ekran", "onboarding.profile.display_name_hint": "Emri juaj i plotë, ose ç’të doni…", - "onboarding.profile.indexable": "Përfshi postime publike në përfundime kërkimi", "onboarding.profile.lead": "Këtë mund ta plotësoni përherë më vonë, te rregullimet, ku ka edhe më tepër mundësi përshtatjeje.", "onboarding.profile.note": "Jetëshkrim", "onboarding.profile.note_hint": "Mund të @përmendni persona të tjerë, ose #hashtagë…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Jo në lista", "privacy_policy.last_updated": "Përditësuar së fundi më {date}", "privacy_policy.title": "Rregulla Privatësie", + "recommended": "E rekomanduar", "refresh": "Rifreskoje", "regeneration_indicator.label": "Po ngarkohet…", "regeneration_indicator.sublabel": "Prurja juaj vetjake po përgatitet!", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index c614215aa..898f0c124 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -481,6 +481,17 @@ "onboarding.follows.empty": "Нажалост, тренутно се не могу приказати резултати. Можете покушати са коришћењем претраге или прегледањем странице за истраживање да бисте пронашли људе које ћете пратити или покушајте поново касније.", "onboarding.follows.lead": "Ваша почетна страница је примарни начин да доживите Mastodon. Што више људи будете пратили, то ће бити активније и занимљивије. Да бисте започели, ево неколико предлога:", "onboarding.follows.title": "Персонализујте своју почетну страницу", + "onboarding.profile.discoverable": "Нека се мој профил може открити другима", + "onboarding.profile.discoverable_hint": "Када омогућите могућност откривања на Mastodon-у, ваше објаве се могу појавити у резултатима претраге и у тренду, а ваш профил може бити предложен људима са сличним интересовањима.", + "onboarding.profile.display_name": "Име за приказ", + "onboarding.profile.display_name_hint": "Ваше пуно име или надимак…", + "onboarding.profile.lead": "Ово можете увек довршити касније у подешавањима, где је доступно још више опција прилагођавања.", + "onboarding.profile.note": "Биографија", + "onboarding.profile.note_hint": "Можете да @поменете друге људе или #хеш ознаке…", + "onboarding.profile.save_and_continue": "Сачувај и настави", + "onboarding.profile.title": "Подешавање профила", + "onboarding.profile.upload_avatar": "Отпреми слику профила", + "onboarding.profile.upload_header": "Отпреми заглавље профила", "onboarding.share.lead": "Нека људи знају како могу да вас пронађу на Mastodon-у!", "onboarding.share.message": "Ја сам {username} на #Mastodon-у! Пратите ме на {url}", "onboarding.share.next_steps": "Могући следећи кораци:", @@ -524,6 +535,7 @@ "privacy.unlisted.short": "Неизлистано", "privacy_policy.last_updated": "Последње ажурирање {date}", "privacy_policy.title": "Политика приватности", + "recommended": "Препоручено", "refresh": "Освежи", "regeneration_indicator.label": "Учитавање…", "regeneration_indicator.sublabel": "Ваша почетна страница се припрема!", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 0b1a7f6ad..6473a41d6 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -481,9 +481,10 @@ "onboarding.follows.empty": "Tyvärr kan inga resultat visas just nu. Du kan prova att använda sökfunktionen eller utforska sidan för att hitta personer att följa, eller försök igen senare.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.discoverable": "Gör min profil upptäckbar", + "onboarding.profile.discoverable_hint": "När du väljer att vara upptäckbar på Mastodon kan dina inlägg visas i sök- och trendresultat, och din profil kan föreslås för personer med liknande intressen som du.", "onboarding.profile.display_name": "Visningsnamn", "onboarding.profile.display_name_hint": "Fullständigt namn eller ditt roliga namn…", - "onboarding.profile.indexable": "Inkludera offentliga inlägg i sökresultaten", "onboarding.profile.lead": "Du kan alltid slutföra detta senare i inställningarna, där ännu fler anpassningsalternativ finns tillgängliga.", "onboarding.profile.note": "Bio", "onboarding.profile.note_hint": "Du kan @nämna andra personer eller #hashtags…", @@ -532,6 +533,7 @@ "privacy.unlisted.short": "Olistad", "privacy_policy.last_updated": "Senast uppdaterad {date}", "privacy_policy.title": "Integritetspolicy", + "recommended": "Rekommenderas", "refresh": "Läs om", "regeneration_indicator.label": "Laddar…", "regeneration_indicator.sublabel": "Ditt hemmaflöde förbereds!", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index c86b7c379..d60509143 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -481,11 +481,11 @@ "onboarding.follows.empty": "น่าเสียดาย ไม่สามารถแสดงผลลัพธ์ได้ในตอนนี้ คุณสามารถลองใช้การค้นหาหรือเรียกดูหน้าสำรวจเพื่อค้นหาผู้คนที่จะติดตาม หรือลองอีกครั้งในภายหลัง", "onboarding.follows.lead": "ฟีดหน้าแรกของคุณเป็นวิธีหลักในการสัมผัส Mastodon ยิ่งคุณติดตามผู้คนมากเท่าไร ฟีดหน้าแรกก็จะยิ่งมีการใช้งานและน่าสนใจมากขึ้นเท่านั้น เพื่อช่วยให้คุณเริ่มต้นใช้งาน นี่คือข้อเสนอแนะบางส่วน:", "onboarding.follows.title": "ปรับแต่งฟีดหน้าแรกของคุณ", - "onboarding.profile.discoverable": "แสดงโปรไฟล์และโพสต์ในอัลกอริทึมการค้นพบ", + "onboarding.profile.discoverable": "ทำให้โปรไฟล์ของฉันสามารถค้นพบได้", + "onboarding.profile.discoverable_hint": "เมื่อคุณเลือกรับความสามารถในการค้นพบใน Mastodon โพสต์ของคุณอาจปรากฏในผลลัพธ์การค้นหาและกำลังนิยม และอาจเสนอแนะโปรไฟล์ของคุณให้กับผู้คนที่มีความสนใจคล้ายกับคุณ", "onboarding.profile.display_name": "ชื่อที่แสดง", "onboarding.profile.display_name_hint": "ชื่อเต็มของคุณหรือชื่อแบบสนุกสนานของคุณ…", - "onboarding.profile.indexable": "รวมโพสต์สาธารณะในผลลัพธ์การค้นหา", - "onboarding.profile.lead": "คุณสามารถกลับมาทำต่อได้เสมอในการตั้งค่า ซึ่งจะมีตัวเลือกในการปรับแต่งมากกว่า", + "onboarding.profile.lead": "คุณสามารถทำสิ่งนี้ให้เสร็จสมบูรณ์ในภายหลังได้เสมอในการตั้งค่า ที่ซึ่งตัวเลือกการปรับแต่งเพิ่มเติมพร้อมใช้งาน", "onboarding.profile.note": "ชีวประวัติ", "onboarding.profile.note_hint": "คุณสามารถ @กล่าวถึง ผู้คนอื่น ๆ หรือ #แฮชแท็ก…", "onboarding.profile.save_and_continue": "บันทึกและดำเนินการต่อ", @@ -496,7 +496,7 @@ "onboarding.share.message": "ฉันคือ {username} ใน #Mastodon! มาติดตามฉันที่ {url}", "onboarding.share.next_steps": "ขั้นตอนถัดไปที่เป็นไปได้:", "onboarding.share.title": "แบ่งปันโปรไฟล์ของคุณ", - "onboarding.start.lead": "ตอนนี้คุณเป็นส่วนหนึ่งของ Mastodon แพลตฟอร์มสื่อสังคมที่มีเอกลักษณ์ กระจายศูนย์ ที่ซึ่งคุณ—ไม่ใช่อัลกอริทึม—เรียบเรียงประสบการณ์ของคุณเอง มาช่วยให้คุณเริ่มต้นใช้งานพรมแดนทางสังคมใหม่นี้กันเลย:", + "onboarding.start.lead": "ตอนนี้คุณเป็นส่วนหนึ่งของ Mastodon แพลตฟอร์มสื่อสังคมที่มีเอกลักษณ์เฉพาะตัว กระจายศูนย์ ที่ซึ่งคุณ—ไม่ใช่อัลกอริทึม—เรียบเรียงประสบการณ์ของคุณเอง มาช่วยให้คุณเริ่มต้นใช้งานพรมแดนทางสังคมใหม่นี้กันเลย:", "onboarding.start.skip": "ไม่ต้องการความช่วยเหลือในการเริ่มต้นใช้งาน?", "onboarding.start.title": "คุณทำสำเร็จแล้ว!", "onboarding.steps.follow_people.body": "การติดตามผู้คนที่น่าสนใจคือสิ่งที่ Mastodon ให้ความสำคัญ", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "ไม่อยู่ในรายการ", "privacy_policy.last_updated": "อัปเดตล่าสุดเมื่อ {date}", "privacy_policy.title": "นโยบายความเป็นส่วนตัว", + "recommended": "แนะนำ", "refresh": "รีเฟรช", "regeneration_indicator.label": "กำลังโหลด…", "regeneration_indicator.sublabel": "กำลังเตรียมฟีดหน้าแรกของคุณ!", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index 505b16f4b..25b61f40e 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -21,6 +21,7 @@ "account.blocked": "Engellendi", "account.browse_more_on_origin_server": "Orijinal profilde daha fazlasına göz atın", "account.cancel_follow_request": "Takip isteğini geri çek", + "account.copy": "Gönderi bağlantısını kopyala", "account.direct": "@{name} kullanıcısına özelden değin", "account.disable_notifications": "@{name} kişisinin gönderi bildirimlerini kapat", "account.domain_blocked": "Alan adı engellendi", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Okundu olarak işaretle", "conversation.open": "Sohbeti görüntüle", "conversation.with": "{names} ile", + "copy_icon_button.copied": "Panoya kopyalandı", "copypaste.copied": "Kopyalandı", "copypaste.copy_to_clipboard": "Panoya kopyala", "directory.federated": "Bilinen fediverse'lerden", @@ -479,10 +481,10 @@ "onboarding.follows.empty": "Maalesef şu an bir sonuç gösterilemiyor. Takip edilecek kişileri bulmak için arama veya keşfet sayfasına gözatmayı kullanabilirsiniz veya daha sonra tekrar deneyin.", "onboarding.follows.lead": "Kendi ana akışınızı siz düzenliyorsunuz. Siz daha fazla insanı takip ettikçe, daha etkin ve ilgi çekici olacaktır. Bu profiller iyi bir başlangıç olabilir, isterseniz izlemeyi daha sonra bırakabilirsiniz:", "onboarding.follows.title": "Mastodon'da Popüler", - "onboarding.profile.discoverable": "Profil ve gönderileri keşif algoritmalarında kullan", + "onboarding.profile.discoverable": "Profilimi keşfedilebilir yap", + "onboarding.profile.discoverable_hint": "Mastodon'da keşfedilebilirliği etkinleştirdiğinizde, gönderileriniz arama sonuçlarında ve trendlerde görünebilir aynı zamanda profiliniz sizinle benzer ilgi alanlarına sahip kişilere önerilebilir.", "onboarding.profile.display_name": "Görünen isim", "onboarding.profile.display_name_hint": "Tam adınız veya kullanıcı adınız…", - "onboarding.profile.indexable": "Herkese açık gönderileri arama sonuçlarına ekle", "onboarding.profile.lead": "Bunu her zaman daha sonra ayarlardan tamamlayabilirsiniz, hatta daha fazla özelleştirme seçeneğine de ulaşabilirsiniz.", "onboarding.profile.note": "Kişisel bilgiler", "onboarding.profile.note_hint": "Diğer insanlara @değinebilir veya #etiketler kullanabilirsiniz…", @@ -533,6 +535,7 @@ "privacy.unlisted.short": "Listelenmemiş", "privacy_policy.last_updated": "Son güncelleme {date}", "privacy_policy.title": "Gizlilik Politikası", + "recommended": "Önerilen", "refresh": "Yenile", "regeneration_indicator.label": "Yükleniyor…", "regeneration_indicator.sublabel": "Ana akışın hazırlanıyor!", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 1307d7ea5..585a4b385 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "На жаль, жоден результат не може бути показаний просто зараз. Ви можете спробувати скористатися пошуком або переглядом сторінки огляду, щоб знайти людей для слідкування або повторіть спробу пізніше.", "onboarding.follows.lead": "Ваша домашня стрічка - основний спосіб роботи Mastodon. Чим більше людей, які ви підписані, тим активнішою і цікавою. Ось деякі пропозиції на початок:", "onboarding.follows.title": "Персоналізуйте домашню стрічку", - "onboarding.profile.discoverable": "Враховувати профіль та дописи в алгоритмах пошуку", + "onboarding.profile.discoverable": "Зробити мій профіль видимим", + "onboarding.profile.discoverable_hint": "Якщо ви погоджуєтеся на видимість у Mastodon, ваші дописи можуть з'являтися в результатах пошуку і трендах, і ваш профіль може бути запропоновано людям зі схожими з вашими інтересами.", "onboarding.profile.display_name": "Видиме ім'я", "onboarding.profile.display_name_hint": "Ваше повне ім'я або ваш псевдонім…", - "onboarding.profile.indexable": "Включити загальнодоступні дописи в результати пошуку", "onboarding.profile.lead": "Ви завжди можете завершити це пізніше в Налаштуваннях, де доступно ще більше опцій налаштування.", "onboarding.profile.note": "Біографія", "onboarding.profile.note_hint": "Ви можете @згадувати інших людей або #гештеґи…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "Прихований", "privacy_policy.last_updated": "Оновлено {date}", "privacy_policy.title": "Політика приватності", + "recommended": "Рекомендовано", "refresh": "Оновити", "regeneration_indicator.label": "Завантаження…", "regeneration_indicator.sublabel": "Хвилинку, ми готуємо вашу стрічку!", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index c98be2b74..8fc670557 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -21,6 +21,7 @@ "account.blocked": "Đã chặn", "account.browse_more_on_origin_server": "Truy cập trang của người này", "account.cancel_follow_request": "Thu hồi yêu cầu theo dõi", + "account.copy": "Sao chép địa chỉ", "account.direct": "Nhắn riêng @{name}", "account.disable_notifications": "Tắt thông báo khi @{name} đăng tút", "account.domain_blocked": "Tên miền đã chặn", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Đánh dấu là đã đọc", "conversation.open": "Xem toàn bộ tin nhắn", "conversation.with": "Với {names}", + "copy_icon_button.copied": "Đã sao chép vào bộ nhớ tạm", "copypaste.copied": "Đã sao chép", "copypaste.copy_to_clipboard": "Sao chép vào bộ nhớ tạm", "directory.federated": "Từ mạng liên hợp", @@ -390,6 +392,7 @@ "lists.search": "Tìm kiếm những người mà bạn quan tâm", "lists.subheading": "Danh sách của bạn", "load_pending": "{count, plural, one {# tút mới} other {# tút mới}}", + "loading_indicator.label": "Đang tải…", "media_gallery.toggle_visible": "{number, plural, other {Ẩn hình ảnh}}", "moved_to_account_banner.text": "Tài khoản {disabledAccount} của bạn hiện không khả dụng vì bạn đã chuyển sang {movedToAccount}.", "mute_modal.duration": "Thời hạn", @@ -478,6 +481,17 @@ "onboarding.follows.empty": "Không có kết quả có thể được hiển thị lúc này. Bạn có thể thử sử dụng tính năng tìm kiếm hoặc duyệt qua trang khám phá để tìm những người theo dõi hoặc thử lại sau.", "onboarding.follows.lead": "Bạn quản lý bảng tin của riêng bạn. Bạn càng theo dõi nhiều người, nó sẽ càng sôi động và thú vị. Để bắt đầu, đây là vài gợi ý:", "onboarding.follows.title": "Thịnh hành trên Mastodon", + "onboarding.profile.discoverable": "Bật khám phá cho hồ sơ của tôi", + "onboarding.profile.discoverable_hint": "Khi bạn bật khám phá trên Mastodon, các tút của bạn có thể xuất hiện trong kết quả tìm kiếm và xu hướng, đồng thời hồ sơ của bạn sẽ được đề xuất cho những người có cùng sở thích với bạn.", + "onboarding.profile.display_name": "Biệt danh", + "onboarding.profile.display_name_hint": "Tên đầy đủ hoặc biệt danh đều được…", + "onboarding.profile.lead": "Bạn có thể cài đặt lại trong phần cài đặt, nơi thậm chí còn có nhiều tùy chọn hơn.", + "onboarding.profile.note": "Giới thiệu", + "onboarding.profile.note_hint": "Bạn có thể @nhắnriêng ai đó hoặc #hashtags…", + "onboarding.profile.save_and_continue": "Lưu và tiếp tục", + "onboarding.profile.title": "Thiết lập hồ sơ", + "onboarding.profile.upload_avatar": "Tải lên ảnh đại diện", + "onboarding.profile.upload_header": "Tải lên ảnh bìa", "onboarding.share.lead": "Hãy cho mọi người biết làm thế nào họ có thể tìm thấy bạn trên Mastodon!", "onboarding.share.message": "Tôi là {username} trên #Mastodon! Hãy theo dõi tôi tại {url}", "onboarding.share.next_steps": "Các bước kế tiếp:", @@ -521,6 +535,7 @@ "privacy.unlisted.short": "Hạn chế", "privacy_policy.last_updated": "Cập nhật lần cuối {date}", "privacy_policy.title": "Chính sách bảo mật", + "recommended": "Đề xuất", "refresh": "Làm mới", "regeneration_indicator.label": "Đang tải…", "regeneration_indicator.sublabel": "Trang chính của bạn đang được cập nhật!", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 79f463772..e58b50476 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "很抱歉,现在无法显示任何结果。您可以尝试使用搜索或浏览探索页面来查找要关注的人,或稍后再试。", "onboarding.follows.lead": "你管理你自己的家庭饲料。你关注的人越多,它将越活跃和有趣。 这些配置文件可能是一个很好的起点——你可以随时取消关注它们!", "onboarding.follows.title": "定制您的主页动态", - "onboarding.profile.discoverable": "在发现算法中展示您的个人资料和嘟文", + "onboarding.profile.discoverable": "让我的资料卡可被他人发现", + "onboarding.profile.discoverable_hint": "当您选择在 Mastodon 上启用发现功能时,你的嘟文可能会出现在搜索结果和热门中,你的账户可能会被推荐给与你兴趣相似的人。", "onboarding.profile.display_name": "昵称", "onboarding.profile.display_name_hint": "您的全名或昵称…", - "onboarding.profile.indexable": "将您的公开嘟文纳入搜索范围", "onboarding.profile.lead": "您可以稍后在设置中完成此操作,设置中有更多的自定义选项。", "onboarding.profile.note": "简介", "onboarding.profile.note_hint": "您可以提及 @其他人 或 #标签…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "不公开", "privacy_policy.last_updated": "最近更新于 {date}", "privacy_policy.title": "隐私政策", + "recommended": "推荐", "refresh": "刷新", "regeneration_indicator.label": "加载中…", "regeneration_indicator.sublabel": "你的主页动态正在准备中!", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index e7af27c5f..af4dad7f7 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "很遺憾,現在無法顯示任何結果。你可以嘗試搜尋或瀏覽探索頁面來找使用者來追蹤,或者稍後再試。", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", - "onboarding.profile.discoverable": "在探索的演算法中展示個人檔案和帖文", + "onboarding.profile.discoverable": "將個人檔案設為可被搜尋", + "onboarding.profile.discoverable_hint": "當你在 Mastodon 上選擇可被搜尋時,你的帖文可能會出現在搜尋結果和熱門,你的個人檔案也可能被推薦給與你興趣相似的人。", "onboarding.profile.display_name": "顯示名稱", "onboarding.profile.display_name_hint": "你的全名或暱稱…", - "onboarding.profile.indexable": "將公開帖文納入搜尋結果中", "onboarding.profile.lead": "你可以隨時在設定中完成此動作,那裏有更多自訂選項。", "onboarding.profile.note": "簡介", "onboarding.profile.note_hint": "你可以 @提及他人 或使用 #標籤…", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "公開", "privacy_policy.last_updated": "最後更新 {date}", "privacy_policy.title": "私隱政策", + "recommended": "推薦", "refresh": "重新整理", "regeneration_indicator.label": "載入中……", "regeneration_indicator.sublabel": "你的主頁時間軸正在準備中!", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index d4f3010c9..783f95b30 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -481,10 +481,10 @@ "onboarding.follows.empty": "很遺憾,目前未能顯示任何結果。您可以嘗試使用搜尋、瀏覽探索頁面以找尋人們跟隨、或稍候再試。", "onboarding.follows.lead": "您的首頁時間軸是 Mastodon 的核心體驗。若您跟隨更多人的話,它將會變得更活躍有趣。這些個人檔案也許是個好起點,您可以隨時取消跟隨他們!", "onboarding.follows.title": "客製化您的首頁時間軸", - "onboarding.profile.discoverable": "於探索演算法中推薦個人檔案及嘟文", + "onboarding.profile.discoverable": "使我的個人檔案可以被找到", + "onboarding.profile.discoverable_hint": "當您於 Mastodon 上選擇加入可發現性時,您的嘟文可能會出現於搜尋結果與趨勢中。您的個人檔案可能會被推薦給與您志趣相投的人。", "onboarding.profile.display_name": "顯示名稱", "onboarding.profile.display_name_hint": "完整名稱或暱稱...", - "onboarding.profile.indexable": "允許公開嘟文顯示於搜尋結果中", "onboarding.profile.lead": "您隨時可以稍候於設定中完成此操作,將有更多自訂選項可使用。", "onboarding.profile.note": "個人簡介", "onboarding.profile.note_hint": "您可以 @mention 其他人或者使用 #主題標籤...", @@ -535,6 +535,7 @@ "privacy.unlisted.short": "不公開", "privacy_policy.last_updated": "最後更新:{date}", "privacy_policy.title": "隱私權政策", + "recommended": "推薦設定", "refresh": "重新整理", "regeneration_indicator.label": "載入中…", "regeneration_indicator.sublabel": "您的首頁時間軸正在準備中!", diff --git a/config/locales/bg.yml b/config/locales/bg.yml index dfff7058d..4c2bf0fa3 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -611,6 +611,7 @@ bg: created_at: Докладвано delete_and_resolve: Изтриване на публикациите forwarded: Препратено + forwarded_replies_explanation: Този доклад е от отдалечен потребител и за отдалечено съдържание. То е препратено до вас, защото докладваното съдържание е в отговор на един от потребителите ви. forwarded_to: Препратено до %{domain} mark_as_resolved: Маркиране като решено mark_as_sensitive: Означаване като деликатно diff --git a/config/locales/devise.lt.yml b/config/locales/devise.lt.yml index 6c5cb837a..aedba2498 100644 --- a/config/locales/devise.lt.yml +++ b/config/locales/devise.lt.yml @@ -1 +1,35 @@ +--- lt: + devise: + confirmations: + confirmed: Tavo el. pašto adresas buvo sėkmingai patvirtintas. + send_instructions: Po kelių minučių gausi el. laišką su instrukcijomis, kaip patvirtinti savo el. pašto adresą. Jei negavai šio el. laiško, patikrink šlamšto laiškų aplanką. + send_paranoid_instructions: Jei tavo el. pašto adresas yra mūsų duomenų bazėje, po kelių minučių gausi el. laišką su instrukcijomis, kaip patvirtinti savo el. pašto adresą. Jei negavai šio el. laiško, patikrink šlamšto laiškų aplanką. + failure: + already_authenticated: Tu jau prisijungęs (-usi). + inactive: Tavo paskyra dar nėra aktyvuota. + invalid: Netinkami %{authentication_keys} arba slaptažodis. + last_attempt: Turi dar vieną bandymą, kol tavo paskyra bus užrakinta. + locked: Tavo paskyra užrakinta. + not_found_in_database: Netinkami %{authentication_keys} arba slaptažodis. + pending: Tavo paskyra vis dar peržiūrima. + timeout: Tavo seansas baigėsi. Norėdamas (-a) tęsti, prisijunk dar kartą. + unauthenticated: Prieš tęsdamas (-a) turi prisijungti arba užsiregistruoti. + unconfirmed: Prieš tęsdamas (-a) turi patvirtinti savo el. pašto adresą. + mailer: + confirmation_instructions: + action: Patvirtinti el. pašto adresą + action_with_app: Patvirtinti ir grįžti į %{app} + explanation: Šiuo el. pašto adresu sukūrei paskyrą %{host}. Iki jos aktyvavimo liko vienas paspaudimas. Jei tai buvo ne tu, ignoruok šį el. laišką. + explanation_when_pending: Šiuo el. pašto adresu pateikei paraišką pakvietimui į %{host}. Kai patvirtinsi savo el. pašto adresą, mes peržiūrėsime tavo paraišką. Gali prisijungti ir pakeisti savo duomenis arba ištrinti paskyrą, tačiau negalėsi naudotis daugeliu funkcijų, kol tavo paskyra nebus patvirtinta. Jei tavo paraiška bus atmesta, duomenys bus pašalinti, todėl jokių papildomų veiksmų iš tavęs nereikės. Jei tai buvo ne tu, ignoruok šį el. laišką. + unlock_instructions: + subject: 'Mastodon: atrakinimo instrukcijos' + passwords: + no_token: Į šį puslapį gali patekti tik gavęs (-usi) slaptažodžio atstatymo el. laišką. Jei atėjai iš slaptažodžio atstatymo el. laiško, įsitikink, kad naudojai visą pateiktą URL adresą. + registrations: + destroyed: Iki pasimatymo! Tavo paskyra sėkmingai atšaukta. Tikimės, kad netrukus vėl pasimatysime. + errors: + messages: + expired: nustojo galioti, prašyk naujos. + not_found: nerasta. + not_locked: nebuvo užrakintas. diff --git a/config/locales/eo.yml b/config/locales/eo.yml index 066899995..12c646145 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -1720,6 +1720,10 @@ eo: seamless_external_login: Vi estas ensalutinta per ekstera servo, do pasvortaj kaj retadresaj agordoj ne estas disponeblaj. signed_in_as: 'Salutinta kiel:' verification: + extra_instructions_html: <strong>Konsilo:</strong> La ligilo en via retejo povas esti nevidebla. La grava parto estas <code>rel="me"</code>, kiu evitas identoŝtelon en retejoj kun enhavo generita de uzantoj. Vi povas eĉ uzi <code>link</code>-etikedon en la <code>header</code> de la paĝo anstataŭ <code>a</code>, sed la HTML devas esti atingebla sen plenumado de JavaScript. + here_is_how: Jen gvidilo + hint_html: "<strong>Ĉiu ajn povas aŭtentigi sian identecon en Mastodon.</strong> Bazinte sur malfermitaj interretaj normoj, nun kaj ĉiame senkoste. Vi nur bezonas personan retejon, per kiu homoj rekonas vin. Kiam vi ligos tiun retejon de via profilo, ni kontrolos, ĉu la retejo responde ligiĝas kun via profilo, kaj montros videblan indikilon tie." + instructions_html: Kopiu kaj algluu la jenan kodon en la HTML de via retejo. Poste aldonu la adreson de via retejo en unu el la kromaj kampoj de via profilo en la langeto "Redakti profilon" kaj konservu la ŝanĝojn. verification: Kontrolo verified_links: Via kontrolitaj ligiloj webauthn_credentials: diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 955ec50e7..c1e4b78a2 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -784,7 +784,7 @@ gl: destroyed_msg: Eliminado correctamente o subido! software_updates: critical_update: Crítica - actualiza axiña - description: Recomendamos manter actualizado o teu servidor Mastodon para beneficiarte dos últimos arranxos e características. A maiores, de cando en vez hai actualizacións para evitar problemas importantes de seguridade. Debido a isto, Mastodon comproba cada 30 minutos se hai actualizacións e avisarate seguindo as túas preferencias de notificación por correo electrónico. + description: Aconsellamos manter actualizado o teu servidor Mastodon para beneficiarte dos últimos arranxos e características. A maiores, de cando en vez hai actualizacións para evitar problemas importantes de seguridade. Debido a isto, Mastodon comproba cada 30 minutos se hai actualizacións e avisarate seguindo as túas preferencias de notificación por correo electrónico. documentation_link: Saber máis release_notes: Notas da versión title: Actualizacións dispoñibles @@ -1791,7 +1791,7 @@ gl: change_password: cambia o teu contrasinal details: 'Estos son os detalles do acceso:' explanation: Detectamos que accedeches á conta desde un novo enderezo IP. - further_actions_html: Se non foches ti, recomendámosche %{action} inmediatamente e activa o segundo factor de autenticación para manter conta segura. + further_actions_html: Se non foches ti, aconsellámosche %{action} inmediatamente e activar o segundo factor de autenticación para manter conta segura. subject: Accedeuse á túa conta desde novos enderezos IP title: Novo acceso warning: diff --git a/config/locales/he.yml b/config/locales/he.yml index 35dc99650..1e04af93b 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -76,7 +76,7 @@ he: enabled_msg: ביטול השעית החשבון של %{username} בוצע בהצלחה followers: עוקבים follows: נעקבים - header: כותרת + header: תמונת נושא inbox_url: כתובת תיבת דואר נכנס invite_request_text: סיבות להצטרפות invited_by: הוזמן על ידי @@ -128,7 +128,7 @@ he: remove_avatar: הסרת תמונת פרופיל remove_header: הסרת כותרת removed_avatar_msg: תמונת הפרופיל של %{username} הוסרה בהצלחה - removed_header_msg: תמונת הראשה של %{username} הוסרה בהצלחה + removed_header_msg: תמונת הנושא של %{username} הוסרה בהצלחה resend_confirmation: already_confirmed: משתמש זה כבר אושר send: שלח מחדש קישור לאימות @@ -1281,7 +1281,7 @@ he: keywords: מילות מפתח statuses: הודעות מסויימות statuses_hint_html: הסנן פועל על בחירה ידנית של הודעות בין אם הן מתאימות למילות המפתח להלן ואם לאו. posts regardless of whether they match the keywords below. <a href="%{path}">בחינה או הסרה של ההודעות מהסנן</a>. - title: ערוך מסנן + title: לערוך מסנן errors: deprecated_api_multiple_keywords: לא ניתן לשנות פרמטרים אלו מהיישומון הזה בגלל שהם חלים על יותר ממילת מפתח אחת. ניתן להשתמש ביישומון מעודכן יותר או בממשק הוובי. invalid_context: לא סופק הקשר או הקשר לא תקין @@ -1478,7 +1478,7 @@ he: not_found: לא נמצאו on_cooldown: את/ה בתקופת צינון followers_count: עוקבים בזמן המעבר - incoming_migrations: מעבר לחשבון אחר + incoming_migrations: מעבר מחשבון אחר incoming_migrations_html: כדי לעבור מחשבון אחר לחשבון זה, עליך ראשית <a href="%{path}">ליצור שם נרדף לחשבון</a>. moved_msg: חשבונך מופנה עתה ל-%{acct} וכל עוקביך מועברים לשם. not_redirecting: חשבונכם לא מפנה לשום חשבון אחר כעת. @@ -1516,8 +1516,8 @@ he: subject: הודעתך חובבה על ידי %{name} title: חיבוב חדש follow: - body: "%{name} עכשיו במעקב אחריך!" - subject: "%{name} עכשיו במעקב אחריך" + body: "%{name} עכשיו עוקב.ת אחריך!" + subject: "%{name} עכשיו עוקב.ת אחריך" title: עוקב/ת חדש/ה follow_request: action: ניהול בקשות מעקב diff --git a/config/locales/hr.yml b/config/locales/hr.yml index 28bd83015..4f6cdf480 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -65,6 +65,25 @@ hr: empty: Nema pronađenih izvješća. filter_by_action: Filtriraj prema radnji filter_by_user: Filtriraj prema korisniku + email_domain_blocks: + add_new: Dodaj novi + ip_blocks: + add_new: Stvori pravilo + roles: + privileges: + invite_users_description: Dopusti korisnicima da pozovu nove ljude na server + settings: + about: + title: O aplikaciji + warning_presets: + add_new: Dodaj novi + aliases: + add_new: Stvori alias + appearance: + advanced_web_interface: Napredno web sučelje + localization: + body: Mastodon prevode dobrovoljci. + guide_link_text: Svi mogu doprinjeti. application_mailer: settings: 'Promijeni postavke e-pošte: %{link}' view: 'Vidi:' @@ -85,14 +104,19 @@ hr: less_than_x_seconds: Upravo sada over_x_years: "%{count}god" x_months: "%{count}mj" + edit_profile: + basic_information: Osnovne informacije exports: archive_takeout: date: Datum download: Preuzmite svoju arhivu + request: Zatraži svoju arhivu size: Veličina blocks: Blokirali ste lists: Liste storage: Pohrana medijskih sadržaja + featured_tags: + add_new: Dodaj novi filters: contexts: notifications: Obavijesti @@ -130,6 +154,7 @@ hr: few: "%{count} korištenja" one: 1 korištenje other: "%{count} korištenja" + title: Pozovi ljude notification_mailer: favourite: body: "%{name} je označio/la Vaš status favoritom:" @@ -167,6 +192,8 @@ hr: remote_follow: missing_resource: Nije moguće pronaći traženi URL preusmjeravanja za Vaš račun sessions: + browsers: + ie: Internet Explorer revoke: Opozovi revoke_success: Sesija je uspješno opozvana title: Sesije @@ -183,9 +210,11 @@ hr: export: Izvoz podataka featured_tags: Istaknuti hashtagovi import: Uvezi + import_and_export: Uvezi i izvezi notifications: Obavijesti preferences: Postavke profile: Profil + statuses_cleanup: Automatsko brisanje postova two_factor_authentication: Dvofaktorska autentifikacija statuses: open_in_web: Otvori na webu @@ -205,7 +234,11 @@ hr: visibilities: private: Samo pratitelji public: Javno + public_long: Svi mogu vidjeti unlisted: Neprikazano + unlisted_long: Svi mogu vidjeti, ali nije izlistano u javnim timelineovima + statuses_cleanup: + enabled: Automatski obriši strare postove stream_entries: sensitive_content: Osjetljivi sadržaj two_factor_authentication: diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 3318b690a..7be072463 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -599,6 +599,7 @@ ja: created_at: 通報日時 delete_and_resolve: 投稿を削除 forwarded: 転送済み + forwarded_replies_explanation: この報告はリモートユーザーからのものであり、またリモートコンテンツに関するものです。報告されたコンテンツがあなたのユーザーの内の一人に対するリプライの中にあるため、あなたに転送されました。 forwarded_to: "%{domain}に転送されました" mark_as_resolved: 解決済みとしてマーク mark_as_sensitive: 閲覧注意にする @@ -1343,6 +1344,7 @@ ja: '86400': 1日 expires_in_prompt: 無期限 generate: 招待リンクを作成 + invalid: この招待は無効です invited_by: '次の人に招待されました:' max_uses: other: "%{count}" diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 3eb2950bd..e42481120 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -611,6 +611,7 @@ pt-BR: created_at: Denunciado delete_and_resolve: Excluir publicações forwarded: Encaminhados + forwarded_replies_explanation: Este relatório é de um usuário remoto e é sobre um conteúdo remoto. Ele foi encaminhado para você porque o conteúdo denunciado está em resposta a um de seus usuários. forwarded_to: Encaminhado para %{domain} mark_as_resolved: Marcar como resolvido mark_as_sensitive: Marcar como sensível diff --git a/config/locales/simple_form.gl.yml b/config/locales/simple_form.gl.yml index b917f551c..7bafca6b7 100644 --- a/config/locales/simple_form.gl.yml +++ b/config/locales/simple_form.gl.yml @@ -108,7 +108,7 @@ gl: text: Esto axudaranos a revisar a tua solicitude ip_block: comment: Opcional. Lembrar a razón para engadir esta regra. - expires_in: Os enderezos IP son un recurso finito, a veces son compartidos e cambian de mans con frecuencia. Por esta razón, non se recomendan os bloqueos indefinidos de IPs. + expires_in: Os enderezos IP son un recurso finito, a veces son compartidos e cambian de mans con frecuencia. Por esta razón, non se aconsellan os bloqueos indefinidos de IPs. ip: Escribe un enderezo IPv4 ou IPv6. Podes bloquear rangos completos usando a sintaxe CIDR. Ten coidado e non te bloquees a ti mesma! severities: no_access: Bloquear acceso a tódolos recursos @@ -295,7 +295,7 @@ gl: all: Notificar todas as actualizacións critical: Notificar só as actualizacións críticas label: Hai unha nova versión de Mastodon dispoñible - none: Non notificar nunca as actualizacións (non se recomenda) + none: Non notificar nunca as actualizacións (non se aconsella) patch: Notificar as actualizacións de arranxos trending_tag: Hai que revisar unha nova tendencia rule: @@ -322,9 +322,9 @@ gl: template: Modelo de carga url: URL do extremo 'no': Non - not_recommended: Non é recomendable + not_recommended: Non se aconsella overridden: Sobreescrita - recommended: Recomendado + recommended: Aconsellable required: mark: "*" text: requerido diff --git a/config/locales/simple_form.he.yml b/config/locales/simple_form.he.yml index 04b21cd1b..0a8a57c34 100644 --- a/config/locales/simple_form.he.yml +++ b/config/locales/simple_form.he.yml @@ -268,7 +268,7 @@ he: interactions: must_be_follower: חסימת התראות משאינם עוקבים must_be_following: חסימת התראות משאינם נעקבים - must_be_following_dm: חסימת הודעות ישירות מכותבים שאינם במעקב + must_be_following_dm: חסימת הודעות ישירות מחשבונות שאתם לא עוקבים אחריהם invite: comment: הערה invite_request: @@ -286,7 +286,7 @@ he: digest: שליחת הודעות דוא"ל מסכמות favourite: שליחת דוא"ל כשמחבבים הודעה follow: שליחת דוא"ל כשנוספות עוקבות - follow_request: שליחת דוא"ל כשמבקשים לעקוב + follow_request: מישהו.י ביקש.ה לעקוב אחריך mention: שליחת דוא"ל כשפונים אלייך pending_account: נדרשת סקירה של חשבון חדש reblog: שליחת דוא"ל כשמהדהדים הודעה שלך diff --git a/config/locales/simple_form.hr.yml b/config/locales/simple_form.hr.yml index 8f0178c7b..3db4fd3b4 100644 --- a/config/locales/simple_form.hr.yml +++ b/config/locales/simple_form.hr.yml @@ -7,6 +7,7 @@ hr: account_warning_preset: title: Proizvoljno. Nije vidljivo primatelju defaults: + autofollow: Ljudi koji se registriraju kroz pozivnicu će te automatski slijediti avatar: PNG, GIF ili JPG. Najviše %{size}. Bit će smanjeno na %{dimensions}px header: PNG, GIF ili JPG. Najviše %{size}. Bit će smanjeno na %{dimensions}px password: Mora biti najmanje 8 znakova @@ -22,6 +23,7 @@ hr: admin_account_action: type: Radnja defaults: + avatar: Profilna slika confirm_new_password: Potvrdi novu lozinku confirm_password: Potvrdi lozinku current_password: Trenutna lozinka @@ -38,8 +40,10 @@ hr: setting_display_media_default: Zadano setting_display_media_hide_all: Sakrij sve setting_display_media_show_all: Prikaži sve + setting_reduce_motion: Smanji kretanje u animacijama setting_system_font_ui: Koristi zadani font sustava setting_theme: Tema stranice + setting_trends: Prikaži današnje trendove type: Tip uvoza username: Korisničko ime interactions: @@ -53,6 +57,8 @@ hr: mention: Netko Vas spomene reblog: Netko boosta Vaš status 'no': Ne + not_recommended: Nije preporučeno + recommended: Preporučeno required: text: obavezno 'yes': Da diff --git a/config/locales/sl.yml b/config/locales/sl.yml index b31fe118a..65d09cf1b 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -635,6 +635,7 @@ sl: created_at: Prijavljeno delete_and_resolve: Izbriši objave forwarded: Posredovano + forwarded_replies_explanation: To poročilo je od oddaljenega uporabnika in se nanaša na oddaljeno vsebino. Posredovano vam je bilo, ker je vsebina, o kateri poroča, odgovor enemu od vaših uporabnikov. forwarded_to: Posredovano na %{domain} mark_as_resolved: Označi kot rešeno mark_as_sensitive: Označi, kot občutljivo diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index 6ccec7fd9..426440a1a 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -623,6 +623,7 @@ sr-Latn: created_at: Prijavljena delete_and_resolve: Obriši objave forwarded: Prosleđeno + forwarded_replies_explanation: Ovaj izveštaj je od udaljenog korisnika i o udaljenom sadržaju. Prosleđen vam je jer je prijavljeni sadržaj u odgovoru jednom od vaših korisnika. forwarded_to: Prosleđeno ka %{domain} mark_as_resolved: Označi kao rešenu mark_as_sensitive: Obeleži kao osetljivo diff --git a/config/locales/th.yml b/config/locales/th.yml index 0b7498e7d..a8f047cc7 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -1557,7 +1557,7 @@ th: over_total_limit: คุณมีโพสต์ที่จัดกำหนดการไว้เกินขีดจำกัดที่ %{limit} แล้ว too_soon: วันที่จัดกำหนดการต้องอยู่ในอนาคต self_destruct: - lead_html: น่าเสียดาย <strong>%{domain}</strong> กำลังปิดตัวลงอย่างถาวร หากคุณมีบัญชีที่นั่น คุณจะไม่สามารถใช้บัญชีต่อไปได้ แต่คุณยังสามารถขอข้อมูลสำรองของข้อมูลของคุณ + lead_html: น่าเสียดาย <strong>%{domain}</strong> กำลังปิดตัวลงอย่างถาวร หากคุณมีบัญชีที่นั่น คุณจะไม่สามารถใช้บัญชีต่อไปได้ แต่คุณยังคงสามารถขอข้อมูลสำรองของข้อมูลของคุณ title: เซิร์ฟเวอร์นี้กำลังปิดตัวลง sessions: activity: กิจกรรมล่าสุด diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 9d90d1d51..0cd9e0e17 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -599,6 +599,7 @@ vi: created_at: Báo cáo lúc delete_and_resolve: Xóa tút forwarded: Chuyển tiếp + forwarded_replies_explanation: Báo cáo này từ người dùng ở một máy chủ khác và về nội dung ở một máy chủ khác. Nó được chuyển tiếp tới bạn vì nội dung bị báo cáo là lượt trả lời cho một trong những người dùng của bạn. forwarded_to: Chuyển tiếp tới %{domain} mark_as_resolved: Xử lý xong mark_as_sensitive: Đánh dấu nhạy cảm From 09a2db3f6c5b886fe3c5c188c1aded121742c6b9 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 20 Nov 2023 03:48:56 -0500 Subject: [PATCH 073/255] Move api/v2/filters spec to correct path location (#27950) --- spec/requests/api/v2/{filters => }/filters_spec.rb | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spec/requests/api/v2/{filters => }/filters_spec.rb (100%) diff --git a/spec/requests/api/v2/filters/filters_spec.rb b/spec/requests/api/v2/filters_spec.rb similarity index 100% rename from spec/requests/api/v2/filters/filters_spec.rb rename to spec/requests/api/v2/filters_spec.rb From 6464b7cc45e236bec0d42c209eaaa7cd7b0c7284 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 08:50:00 +0000 Subject: [PATCH 074/255] Update dependency public_suffix to v5.0.4 (#27931) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 06088de54..56fa359c2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -533,7 +533,7 @@ GEM private_address_check (0.5.0) psych (5.1.1.1) stringio - public_suffix (5.0.3) + public_suffix (5.0.4) puma (6.4.0) nio4r (~> 2.0) pundit (2.3.1) From 12c22ee5e71ae0220ea10199e4d10deb4140ec44 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 09:53:14 +0100 Subject: [PATCH 075/255] Update eslint (non-major) (#27995) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 182 ++++++++++++++++++------------------------------------ 1 file changed, 61 insertions(+), 121 deletions(-) diff --git a/yarn.lock b/yarn.lock index 20af86e1a..562fdc757 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1743,10 +1743,10 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:8.53.0": - version: 8.53.0 - resolution: "@eslint/js@npm:8.53.0" - checksum: d29f6c207b2f6dc4ef174d16a3c07b0d3a17ca3d805680496ff267edd773e3bac41db4e7dcab622ca1970d892535bd19671e2a756d4eac75e96fd8c8dcdb619b +"@eslint/js@npm:8.54.0": + version: 8.54.0 + resolution: "@eslint/js@npm:8.54.0" + checksum: d61fb4a0be6af2d8cb290121c329697664a75d6255a29926d5454fb02aeb02b87112f67fdf218d10abac42f90c570ac366126751baefc5405d0e017ed0c946c5 languageName: node linkType: hard @@ -1790,16 +1790,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:1.17.4": - version: 1.17.4 - resolution: "@formatjs/ecma402-abstract@npm:1.17.4" - dependencies: - "@formatjs/intl-localematcher": "npm:0.5.1" - tslib: "npm:^2.4.0" - checksum: c24bf58cd3152ad64a29dfab185d1fde91e44423aabb041f332216b37a23256618efee1e252c0015e735bc688708ee279348e2a4a67a77f6cf918028848ef071 - languageName: node - linkType: hard - "@formatjs/ecma402-abstract@npm:1.18.0": version: 1.18.0 resolution: "@formatjs/ecma402-abstract@npm:1.18.0" @@ -1819,17 +1809,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-messageformat-parser@npm:2.7.2": - version: 2.7.2 - resolution: "@formatjs/icu-messageformat-parser@npm:2.7.2" - dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.4" - "@formatjs/icu-skeleton-parser": "npm:1.6.4" - tslib: "npm:^2.4.0" - checksum: c7a2f7daecec9ba36acda2c5b7ef21f515883b886d4d9965d83c93bc55fc604f56c1097d4641608633c32917aaa0b9b0c65c0d162723428249dc29271270a064 - languageName: node - linkType: hard - "@formatjs/icu-messageformat-parser@npm:2.7.3": version: 2.7.3 resolution: "@formatjs/icu-messageformat-parser@npm:2.7.3" @@ -1841,16 +1820,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/icu-skeleton-parser@npm:1.6.4": - version: 1.6.4 - resolution: "@formatjs/icu-skeleton-parser@npm:1.6.4" - dependencies: - "@formatjs/ecma402-abstract": "npm:1.17.4" - tslib: "npm:^2.4.0" - checksum: 3688aad6d12fe677ef0ce3d6a3424c5bde9ed223dc49841de8dd33c547bdd2858f8bce4437fcc135048b4f92385374776ab48e39b3cc5063a45bdb1ce85ad2d4 - languageName: node - linkType: hard - "@formatjs/icu-skeleton-parser@npm:1.7.0": version: 1.7.0 resolution: "@formatjs/icu-skeleton-parser@npm:1.7.0" @@ -1883,15 +1852,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-localematcher@npm:0.5.1": - version: 0.5.1 - resolution: "@formatjs/intl-localematcher@npm:0.5.1" - dependencies: - tslib: "npm:^2.4.0" - checksum: 2282db3e623d3f65681b6a2a2dbffc4f948b8411789f51af1b221610105f809ebec7f58f9afd5008e72c62ed5524c8c321f85c78cab0cffb632e20c0064b701b - languageName: node - linkType: hard - "@formatjs/intl-localematcher@npm:0.5.2": version: 0.5.2 resolution: "@formatjs/intl-localematcher@npm:0.5.2" @@ -1932,26 +1892,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/ts-transformer@npm:3.13.8": - version: 3.13.8 - resolution: "@formatjs/ts-transformer@npm:3.13.8" - dependencies: - "@formatjs/icu-messageformat-parser": "npm:2.7.2" - "@types/json-stable-stringify": "npm:^1.0.32" - "@types/node": "npm:14 || 16 || 17" - chalk: "npm:^4.0.0" - json-stable-stringify: "npm:^1.0.1" - tslib: "npm:^2.4.0" - typescript: "npm:5" - peerDependencies: - ts-jest: ">=27" - peerDependenciesMeta: - ts-jest: - optional: true - checksum: 32b13b75732739ca016d9d654e5f40077cafa3ff2f924fbb5fd91155cd6af3292c5fee9be022bb224fb69d2ab60ed9cdda49ee83fbf9e1e8de470ee33ceae4f3 - languageName: node - linkType: hard - "@formatjs/ts-transformer@npm:3.13.9": version: 3.13.9 resolution: "@formatjs/ts-transformer@npm:3.13.9" @@ -3721,14 +3661,14 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^6.0.0": - version: 6.10.0 - resolution: "@typescript-eslint/eslint-plugin@npm:6.10.0" + version: 6.11.0 + resolution: "@typescript-eslint/eslint-plugin@npm:6.11.0" dependencies: "@eslint-community/regexpp": "npm:^4.5.1" - "@typescript-eslint/scope-manager": "npm:6.10.0" - "@typescript-eslint/type-utils": "npm:6.10.0" - "@typescript-eslint/utils": "npm:6.10.0" - "@typescript-eslint/visitor-keys": "npm:6.10.0" + "@typescript-eslint/scope-manager": "npm:6.11.0" + "@typescript-eslint/type-utils": "npm:6.11.0" + "@typescript-eslint/utils": "npm:6.11.0" + "@typescript-eslint/visitor-keys": "npm:6.11.0" debug: "npm:^4.3.4" graphemer: "npm:^1.4.0" ignore: "npm:^5.2.4" @@ -3741,44 +3681,44 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: f50b17cb753afbfc99549d38585eba8558949b977eb4661dd584e73ee946b3dbe944c9e3b12a233fa06b5e1c7d101730ac88a00c7a91b0a7f1e2c37a98e13c7a + checksum: 6645aa09b9d51c5e3ea781eaf74da75b94f83f3e2d7b3dd988d5ce7eb82dd87e3509471cf2ee8c6b2428d907df5f1b02f29dbd04f54c2653f9566c8c4ce98009 languageName: node linkType: hard "@typescript-eslint/parser@npm:^6.0.0": - version: 6.10.0 - resolution: "@typescript-eslint/parser@npm:6.10.0" + version: 6.11.0 + resolution: "@typescript-eslint/parser@npm:6.11.0" dependencies: - "@typescript-eslint/scope-manager": "npm:6.10.0" - "@typescript-eslint/types": "npm:6.10.0" - "@typescript-eslint/typescript-estree": "npm:6.10.0" - "@typescript-eslint/visitor-keys": "npm:6.10.0" + "@typescript-eslint/scope-manager": "npm:6.11.0" + "@typescript-eslint/types": "npm:6.11.0" + "@typescript-eslint/typescript-estree": "npm:6.11.0" + "@typescript-eslint/visitor-keys": "npm:6.11.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: fd86c31dfdde03636393a3a9cf16716856bb506923069f34d87af14fac363a33578f47476a15d272e4d7a764de00fd905ee11361cc06b81b302a9fa8ebe4c23c + checksum: e7caeb20069102e21f468fc0dbe7ff6fb6b1efa9e72f4c9f39d4a865ed0633f39130b593ef9ae8f394ca1d70563e15410faf30a482a97809951eaac6ed3a67da languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/scope-manager@npm:6.10.0" +"@typescript-eslint/scope-manager@npm:6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/scope-manager@npm:6.11.0" dependencies: - "@typescript-eslint/types": "npm:6.10.0" - "@typescript-eslint/visitor-keys": "npm:6.10.0" - checksum: a5fbee770d763852a7f426b950d495529139f1629fdcb30136c93f787acd82236db4272f78dff1d05a3a10a6406472ae95ae94ab75cfb618a06d75b8cc536cbf + "@typescript-eslint/types": "npm:6.11.0" + "@typescript-eslint/visitor-keys": "npm:6.11.0" + checksum: d8999e2d1a4cbde8a79df5e3ec416f0e3db9532d39f2f4bb5a0ebdf954ae75c183d3277579ba05268fe2c88e88ef87f0fa12f02bb8d95d9e67d92e411241f3a3 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/type-utils@npm:6.10.0" +"@typescript-eslint/type-utils@npm:6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/type-utils@npm:6.11.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:6.10.0" - "@typescript-eslint/utils": "npm:6.10.0" + "@typescript-eslint/typescript-estree": "npm:6.11.0" + "@typescript-eslint/utils": "npm:6.11.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.0.1" peerDependencies: @@ -3786,23 +3726,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: f7c425d4da4d53d78b3d6630216dc1f2809f8dcaed62dc3cf12252102a53103a2aa39a160b310ca1cedebf87b8c339013be0c2360710c7c836b775374730c10e + checksum: ff68f2e052b8d688f1dc1a0050746704c8e0ab6263b47f1f52da73a7d251678e4950af23a95e1cd8e3fcea2457e6e5294ddbe01d29dafa2fdfb5b11ed9452a3f languageName: node linkType: hard -"@typescript-eslint/types@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/types@npm:6.10.0" - checksum: 30f47de625405b3729db6d26a0376d98628bd966c70ca01fab1adcef91bba810d27ce643d844e42d1cc77bb2c6277e62efe278a090da63ba748dfe5710c4757b +"@typescript-eslint/types@npm:6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/types@npm:6.11.0" + checksum: 23182813db39a5e9b9bcc1e85306c953f7b8b22d3885e41fcac0bd725c170fbcb70f4ce55633678cc5921dcf062fa0e55635eb39480c118a4411a00354820223 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/typescript-estree@npm:6.10.0" +"@typescript-eslint/typescript-estree@npm:6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/typescript-estree@npm:6.11.0" dependencies: - "@typescript-eslint/types": "npm:6.10.0" - "@typescript-eslint/visitor-keys": "npm:6.10.0" + "@typescript-eslint/types": "npm:6.11.0" + "@typescript-eslint/visitor-keys": "npm:6.11.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -3811,34 +3751,34 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: ca28ca5a55e2d431c649ad093e4a4302f2b37c430bbeebbe622b05c727fd14dab136aead5a96848499d3ff4d187889733f8871b8dd5205d19bed4a260ad74544 + checksum: 3e183e554e1bc74f065da3015f7137eb40c262f989c547701b1e3f4f20134e574e56b749288cd00d77b9d1ddb705546613c2457661ffc63b6060ffa97ba3aac8 languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.10.0, @typescript-eslint/utils@npm:^6.5.0": - version: 6.10.0 - resolution: "@typescript-eslint/utils@npm:6.10.0" +"@typescript-eslint/utils@npm:6.11.0, @typescript-eslint/utils@npm:^6.5.0": + version: 6.11.0 + resolution: "@typescript-eslint/utils@npm:6.11.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" "@types/json-schema": "npm:^7.0.12" "@types/semver": "npm:^7.5.0" - "@typescript-eslint/scope-manager": "npm:6.10.0" - "@typescript-eslint/types": "npm:6.10.0" - "@typescript-eslint/typescript-estree": "npm:6.10.0" + "@typescript-eslint/scope-manager": "npm:6.11.0" + "@typescript-eslint/types": "npm:6.11.0" + "@typescript-eslint/typescript-estree": "npm:6.11.0" semver: "npm:^7.5.4" peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: 809a1d08b154f76ed7a99edddf872369f6ed93987cea19a18cb9f12b8390bddcff9138d9d94955545da54488d59e0001054bec13baf6d858a1761b059480b887 + checksum: c91eb4578607959acc2b43ddc791571682e45601a19b25d5d120786ed4af607656f83c5c1fa71972e549ddfb5542acf2f7d443ae93b32ee28192c22c106b8883 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.10.0": - version: 6.10.0 - resolution: "@typescript-eslint/visitor-keys@npm:6.10.0" +"@typescript-eslint/visitor-keys@npm:6.11.0": + version: 6.11.0 + resolution: "@typescript-eslint/visitor-keys@npm:6.11.0" dependencies: - "@typescript-eslint/types": "npm:6.10.0" + "@typescript-eslint/types": "npm:6.11.0" eslint-visitor-keys: "npm:^3.4.1" - checksum: f9223c148655ce00bb17db8aa92ee964e62c75d15095893e0b4d653c60a4033f456329b06de3eab4b404d8df359904f0dd6e3c8c842885c6d130e28ccd95ce03 + checksum: 5f48329422b7f286196661d39e93e9defd7c5cf80e6c84c8d03459853f5d9f86a5e91c5e80ea572dcdb907ebbe503bbcc77aeb8b468c294b2aa7b3ccfc81cb88 languageName: node linkType: hard @@ -7405,11 +7345,11 @@ __metadata: linkType: hard "eslint-plugin-formatjs@npm:^4.10.1": - version: 4.11.2 - resolution: "eslint-plugin-formatjs@npm:4.11.2" + version: 4.11.3 + resolution: "eslint-plugin-formatjs@npm:4.11.3" dependencies: - "@formatjs/icu-messageformat-parser": "npm:2.7.2" - "@formatjs/ts-transformer": "npm:3.13.8" + "@formatjs/icu-messageformat-parser": "npm:2.7.3" + "@formatjs/ts-transformer": "npm:3.13.9" "@types/eslint": "npm:7 || 8" "@types/picomatch": "npm:^2.3.0" "@typescript-eslint/utils": "npm:^6.5.0" @@ -7421,7 +7361,7 @@ __metadata: unicode-emoji-utils: "npm:^1.1.1" peerDependencies: eslint: 7 || 8 - checksum: f5a6bffd9c65b9ce765be74d384618e543388720036b070d69d93c00b8c2bfded543141affc7793bf402f2c9177e2bbc395a7d1e8b806a40bfde1744c282a13c + checksum: 66481e0b5af5738bdb2b164ac1c74216c5c26f7c7400456a58387e71424bb30554aef39da43ce29bfd551f7dad678818d9af029022edadc4e1024349339f6984 languageName: node linkType: hard @@ -7588,13 +7528,13 @@ __metadata: linkType: hard "eslint@npm:^8.41.0": - version: 8.53.0 - resolution: "eslint@npm:8.53.0" + version: 8.54.0 + resolution: "eslint@npm:8.54.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.6.1" "@eslint/eslintrc": "npm:^2.1.3" - "@eslint/js": "npm:8.53.0" + "@eslint/js": "npm:8.54.0" "@humanwhocodes/config-array": "npm:^0.11.13" "@humanwhocodes/module-importer": "npm:^1.0.1" "@nodelib/fs.walk": "npm:^1.2.8" @@ -7631,7 +7571,7 @@ __metadata: text-table: "npm:^0.2.0" bin: eslint: bin/eslint.js - checksum: c5cd0049488c0463dab7d97466767ca5a1d0b3b59d0a223122683dc8039ecea30b27867fb9e38906b4c1ab9d09ece8a802a6c540d8905016f1cc4b4bb27329af + checksum: 4f205f832bdbd0218cde374b067791f4f76d7abe8de86b2dc849c273899051126d912ebf71531ee49b8eeaa22cad77febdc8f2876698dc2a76e84a8cb976af22 languageName: node linkType: hard From 1fabf20a8868da26299af1ccad5244d708f5b75e Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 20 Nov 2023 04:04:46 -0500 Subject: [PATCH 076/255] Reduce `.times` usage in `lib/mastodon/cli/accounts` spec (#27944) --- spec/lib/mastodon/cli/accounts_spec.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index 2c8c99471..0445dec6c 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -465,7 +465,7 @@ describe Mastodon::CLI::Accounts do end describe '#approve' do - let(:total_users) { 10 } + let(:total_users) { 4 } before do Form::AdminSettings.new(registrations_mode: 'approved').save @@ -482,7 +482,7 @@ describe Mastodon::CLI::Accounts do context 'with --number option' do context 'when the number is positive' do - let(:options) { { number: 3 } } + let(:options) { { number: 2 } } it 'approves the earliest n pending registrations' do cli.invoke(:approve, nil, options) @@ -978,7 +978,7 @@ describe Mastodon::CLI::Accounts do end context 'when --all option is provided' do - let(:accounts) { Fabricate.times(3, :account) } + let(:accounts) { Fabricate.times(2, :account) } let(:options) { { all: true } } before do @@ -1269,7 +1269,7 @@ describe Mastodon::CLI::Accounts do end context 'when the given username is found' do - let(:total_relationships) { 10 } + let(:total_relationships) { 3 } let!(:accounts) { Fabricate.times(total_relationships, :account) } context 'with --follows option' do @@ -1324,8 +1324,8 @@ describe Mastodon::CLI::Accounts do let(:options) { { followers: true, follows: true } } before do - accounts.first(6).each { |account| account.follow!(target_account) } - accounts.last(4).each { |account| target_account.follow!(account) } + accounts.first(2).each { |account| account.follow!(target_account) } + accounts.last(1).each { |account| target_account.follow!(account) } end it 'resets all "followers" relationships from the target account' do @@ -1363,7 +1363,7 @@ describe Mastodon::CLI::Accounts do let!(:group_account) { Fabricate(:account, actor_type: 'Group', domain: 'example.com') } let!(:mentioned_account) { Fabricate(:account, domain: 'example.com') } let!(:prunable_accounts) do - Fabricate.times(3, :account, domain: 'example.com', bot: false, suspended_at: nil, silenced_at: nil) + Fabricate.times(2, :account, domain: 'example.com', bot: false, suspended_at: nil, silenced_at: nil) end before do From 00c6ebd86f9a084394a7e1017c9e808e4c4b4d77 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 20 Nov 2023 04:07:25 -0500 Subject: [PATCH 077/255] Reduce `.times` usage in `StatusPin` and add `PIN_LIMIT` constant in validator (#27945) --- app/validators/status_pin_validator.rb | 4 ++- spec/models/status_pin_spec.rb | 49 +++++++++++++------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/app/validators/status_pin_validator.rb b/app/validators/status_pin_validator.rb index 2fdd5b34f..c9c1effba 100644 --- a/app/validators/status_pin_validator.rb +++ b/app/validators/status_pin_validator.rb @@ -1,10 +1,12 @@ # frozen_string_literal: true class StatusPinValidator < ActiveModel::Validator + PIN_LIMIT = 5 + def validate(pin) pin.errors.add(:base, I18n.t('statuses.pin_errors.reblog')) if pin.status.reblog? pin.errors.add(:base, I18n.t('statuses.pin_errors.ownership')) if pin.account_id != pin.status.account_id pin.errors.add(:base, I18n.t('statuses.pin_errors.direct')) if pin.status.direct_visibility? - pin.errors.add(:base, I18n.t('statuses.pin_errors.limit')) if pin.account.status_pins.count > 4 && pin.account.local? + pin.errors.add(:base, I18n.t('statuses.pin_errors.limit')) if pin.account.status_pins.count >= PIN_LIMIT && pin.account.local? end end diff --git a/spec/models/status_pin_spec.rb b/spec/models/status_pin_spec.rb index 660b2e92a..da375009a 100644 --- a/spec/models/status_pin_spec.rb +++ b/spec/models/status_pin_spec.rb @@ -40,35 +40,34 @@ RSpec.describe StatusPin do expect(described_class.new(account: account, status: status).save).to be false end - max_pins = 5 - it 'does not allow pins above the max' do - account = Fabricate(:account) - status = [] + context 'with a pin limit' do + before { stub_const('StatusPinValidator::PIN_LIMIT', 2) } - (max_pins + 1).times do |i| - status[i] = Fabricate(:status, account: account) + it 'does not allow pins above the max' do + account = Fabricate(:account) + + Fabricate.times(StatusPinValidator::PIN_LIMIT, :status_pin, account: account) + + pin = described_class.new(account: account, status: Fabricate(:status, account: account)) + expect(pin.save) + .to be(false) + + expect(pin.errors[:base]) + .to contain_exactly(I18n.t('statuses.pin_errors.limit')) end - max_pins.times do |i| - expect(described_class.new(account: account, status: status[i]).save).to be true + it 'allows pins above the max for remote accounts' do + account = Fabricate(:account, domain: 'remote.test', username: 'bob', url: 'https://remote.test/') + + Fabricate.times(StatusPinValidator::PIN_LIMIT, :status_pin, account: account) + + pin = described_class.new(account: account, status: Fabricate(:status, account: account)) + expect(pin.save) + .to be(true) + + expect(pin.errors[:base]) + .to be_empty end - - expect(described_class.new(account: account, status: status[max_pins]).save).to be false - end - - it 'allows pins above the max for remote accounts' do - account = Fabricate(:account, domain: 'remote.test', username: 'bob', url: 'https://remote.test/') - status = [] - - (max_pins + 1).times do |i| - status[i] = Fabricate(:status, account: account) - end - - max_pins.times do |i| - expect(described_class.new(account: account, status: status[i]).save).to be true - end - - expect(described_class.new(account: account, status: status[max_pins]).save).to be true end end end From d2aacea8da2b7229dcef2ba1c7d2c8005ad1370e Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 20 Nov 2023 04:08:22 -0500 Subject: [PATCH 078/255] Reduce `.times` usage in AccountSearch spec, use constant for default limit (#27946) --- app/models/concerns/account_search.rb | 6 ++++-- spec/models/account_spec.rb | 12 +++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/models/concerns/account_search.rb b/app/models/concerns/account_search.rb index 9f7720f11..b855727b4 100644 --- a/app/models/concerns/account_search.rb +++ b/app/models/concerns/account_search.rb @@ -106,6 +106,8 @@ module AccountSearch LIMIT :limit OFFSET :offset SQL + DEFAULT_LIMIT = 10 + def searchable_text PlainTextFormatter.new(note, local?).to_s if discoverable? end @@ -118,7 +120,7 @@ module AccountSearch end class_methods do - def search_for(terms, limit: 10, offset: 0) + def search_for(terms, limit: DEFAULT_LIMIT, offset: 0) tsquery = generate_query_for_search(terms) find_by_sql([BASIC_SEARCH_SQL, { limit: limit, offset: offset, tsquery: tsquery }]).tap do |records| @@ -126,7 +128,7 @@ module AccountSearch end end - def advanced_search_for(terms, account, limit: 10, following: false, offset: 0) + def advanced_search_for(terms, account, limit: DEFAULT_LIMIT, following: false, offset: 0) tsquery = generate_query_for_search(terms) sql_template = following ? ADVANCED_SEARCH_WITH_FOLLOWING : ADVANCED_SEARCH_WITHOUT_FOLLOWING diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index f77ecb055..9652ea191 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -450,10 +450,11 @@ RSpec.describe Account do expect(results).to eq [match] end - it 'limits by 10 by default' do - 11.times.each { Fabricate(:account, display_name: 'Display Name') } + it 'limits via constant by default' do + stub_const('AccountSearch::DEFAULT_LIMIT', 1) + 2.times.each { Fabricate(:account, display_name: 'Display Name') } results = described_class.search_for('display') - expect(results.size).to eq 10 + expect(results.size).to eq 1 end it 'accepts arbitrary limits' do @@ -594,9 +595,10 @@ RSpec.describe Account do end it 'limits by 10 by default' do - 11.times { Fabricate(:account, display_name: 'Display Name') } + stub_const('AccountSearch::DEFAULT_LIMIT', 1) + 2.times { Fabricate(:account, display_name: 'Display Name') } results = described_class.advanced_search_for('display', account) - expect(results.size).to eq 10 + expect(results.size).to eq 1 end it 'accepts arbitrary limits' do From 371f355719378a1ecf929bc56441493f8a708b32 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 20 Nov 2023 04:08:54 -0500 Subject: [PATCH 079/255] Reduce `.times` usage in `AccountStatusesCleanupPolicy` (#27947) --- spec/models/account_statuses_cleanup_policy_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/models/account_statuses_cleanup_policy_spec.rb b/spec/models/account_statuses_cleanup_policy_spec.rb index 7405bdfa2..74fff30c9 100644 --- a/spec/models/account_statuses_cleanup_policy_spec.rb +++ b/spec/models/account_statuses_cleanup_policy_spec.rb @@ -280,10 +280,10 @@ RSpec.describe AccountStatusesCleanupPolicy do let(:account_statuses_cleanup_policy) { Fabricate(:account_statuses_cleanup_policy, account: account) } before do - 4.times { faved_primary.increment_count!(:favourites_count) } - 5.times { faved_secondary.increment_count!(:favourites_count) } - 4.times { reblogged_primary.increment_count!(:reblogs_count) } - 5.times { reblogged_secondary.increment_count!(:reblogs_count) } + faved_primary.status_stat.update(favourites_count: 4) + faved_secondary.status_stat.update(favourites_count: 5) + reblogged_primary.status_stat.update(reblogs_count: 4) + reblogged_secondary.status_stat.update(reblogs_count: 5) end context 'when passed a max_id' do From 3a8dc9a5c69a96dd11940e212416d24400c7efd9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 10:29:46 +0100 Subject: [PATCH 080/255] Update dependency nokogiri to v1.15.5 (#27939) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 56fa359c2..56b44f093 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -478,7 +478,7 @@ GEM net-smtp (0.4.0) net-protocol nio4r (2.5.9) - nokogiri (1.15.4) + nokogiri (1.15.5) mini_portile2 (~> 2.8.2) racc (~> 1.4) oj (3.16.1) From b9fb47aeb1039079793b1cf39e7c03ed38367b6d Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 20 Nov 2023 04:32:28 -0500 Subject: [PATCH 081/255] Convert `api/v1/endorsements` controller spec to request spec (#27984) --- .../api/v1/endorsements_controller_spec.rb | 17 ------ spec/requests/api/v1/endorsements_spec.rb | 61 +++++++++++++++++++ 2 files changed, 61 insertions(+), 17 deletions(-) delete mode 100644 spec/controllers/api/v1/endorsements_controller_spec.rb create mode 100644 spec/requests/api/v1/endorsements_spec.rb diff --git a/spec/controllers/api/v1/endorsements_controller_spec.rb b/spec/controllers/api/v1/endorsements_controller_spec.rb deleted file mode 100644 index 738804bb7..000000000 --- a/spec/controllers/api/v1/endorsements_controller_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Api::V1::EndorsementsController do - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } - - describe 'GET #index' do - it 'returns 200' do - allow(controller).to receive(:doorkeeper_token) { token } - get :index - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v1/endorsements_spec.rb b/spec/requests/api/v1/endorsements_spec.rb new file mode 100644 index 000000000..e267f2abd --- /dev/null +++ b/spec/requests/api/v1/endorsements_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Endorsements' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + describe 'GET /api/v1/endorsements' do + context 'when not authorized' do + it 'returns http unauthorized' do + get api_v1_endorsements_path + + expect(response) + .to have_http_status(401) + end + end + + context 'with wrong scope' do + before do + get api_v1_endorsements_path, headers: headers + end + + it_behaves_like 'forbidden for wrong scope', 'write write:accounts' + end + + context 'with correct scope' do + let(:scopes) { 'read:accounts' } + + context 'with endorsed accounts' do + let!(:account_pin) { Fabricate(:account_pin, account: user.account) } + + it 'returns http success and accounts json' do + get api_v1_endorsements_path, headers: headers + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and have_attributes( + first: include(acct: account_pin.target_account.acct) + ) + end + end + + context 'without endorsed accounts without json' do + it 'returns http success' do + get api_v1_endorsements_path, headers: headers + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to_not be_present + end + end + end + end +end From 9a01a260a0a13562aaeba80b08207b0aec2660db Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 20 Nov 2023 04:36:49 -0500 Subject: [PATCH 082/255] Convert `api/v1/scheduled_statuses` controller spec to request spec (#27986) --- .../v1/scheduled_statuses_controller_spec.rb | 23 ------- .../scheduled_status_fabricator.rb | 1 + spec/requests/api/v1/scheduled_status_spec.rb | 61 +++++++++++++++++++ 3 files changed, 62 insertions(+), 23 deletions(-) delete mode 100644 spec/controllers/api/v1/scheduled_statuses_controller_spec.rb create mode 100644 spec/requests/api/v1/scheduled_status_spec.rb diff --git a/spec/controllers/api/v1/scheduled_statuses_controller_spec.rb b/spec/controllers/api/v1/scheduled_statuses_controller_spec.rb deleted file mode 100644 index 256c4b272..000000000 --- a/spec/controllers/api/v1/scheduled_statuses_controller_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::ScheduledStatusesController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') } - let(:account) { Fabricate(:account) } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'GET #index' do - it 'returns http success' do - get :index - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/fabricators/scheduled_status_fabricator.rb b/spec/fabricators/scheduled_status_fabricator.rb index eed275ab9..d3d4f1bfd 100644 --- a/spec/fabricators/scheduled_status_fabricator.rb +++ b/spec/fabricators/scheduled_status_fabricator.rb @@ -3,4 +3,5 @@ Fabricator(:scheduled_status) do account { Fabricate.build(:account) } scheduled_at { 20.hours.from_now } + params { {} } end diff --git a/spec/requests/api/v1/scheduled_status_spec.rb b/spec/requests/api/v1/scheduled_status_spec.rb new file mode 100644 index 000000000..49ccde275 --- /dev/null +++ b/spec/requests/api/v1/scheduled_status_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Scheduled Statuses' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + describe 'GET /api/v1/scheduled_statuses' do + context 'when not authorized' do + it 'returns http unauthorized' do + get api_v1_scheduled_statuses_path + + expect(response) + .to have_http_status(401) + end + end + + context 'with wrong scope' do + before do + get api_v1_scheduled_statuses_path, headers: headers + end + + it_behaves_like 'forbidden for wrong scope', 'write write:statuses' + end + + context 'with correct scope' do + let(:scopes) { 'read:statuses' } + + context 'without scheduled statuses' do + it 'returns http success without json' do + get api_v1_scheduled_statuses_path, headers: headers + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to_not be_present + end + end + + context 'with scheduled statuses' do + let!(:scheduled_status) { Fabricate(:scheduled_status, account: user.account) } + + it 'returns http success and status json' do + get api_v1_scheduled_statuses_path, headers: headers + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and have_attributes( + first: include(id: scheduled_status.id.to_s) + ) + end + end + end + end +end From 17582d36d5c7bda151bd6e75091b511b94af4519 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 20 Nov 2023 04:39:45 -0500 Subject: [PATCH 083/255] Convert `api/v1/preferences` controller spec to request spec (#27987) --- .../api/v1/preferences_controller_spec.rb | 23 ---------- spec/requests/api/v1/preferences_spec.rb | 42 +++++++++++++++++++ 2 files changed, 42 insertions(+), 23 deletions(-) delete mode 100644 spec/controllers/api/v1/preferences_controller_spec.rb create mode 100644 spec/requests/api/v1/preferences_spec.rb diff --git a/spec/controllers/api/v1/preferences_controller_spec.rb b/spec/controllers/api/v1/preferences_controller_spec.rb deleted file mode 100644 index 79cc3066e..000000000 --- a/spec/controllers/api/v1/preferences_controller_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::PreferencesController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } - let(:account) { Fabricate(:account) } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'GET #index' do - it 'returns http success' do - get :index - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v1/preferences_spec.rb b/spec/requests/api/v1/preferences_spec.rb new file mode 100644 index 000000000..6f4188c35 --- /dev/null +++ b/spec/requests/api/v1/preferences_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Preferences' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + describe 'GET /api/v1/preferences' do + context 'when not authorized' do + it 'returns http unauthorized' do + get api_v1_preferences_path + + expect(response) + .to have_http_status(401) + end + end + + context 'with wrong scope' do + before do + get api_v1_preferences_path, headers: headers + end + + it_behaves_like 'forbidden for wrong scope', 'write write:accounts' + end + + context 'with correct scope' do + let(:scopes) { 'read:accounts' } + + it 'returns http success' do + get api_v1_preferences_path, headers: headers + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + end + end + end +end From 18cb1f9196a5d8694a58b3cf1fdd3219933e2e1d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 11:17:13 +0100 Subject: [PATCH 084/255] Update actions/setup-node action to v4 (#27996) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/actions/setup-javascript/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-javascript/action.yml b/.github/actions/setup-javascript/action.yml index 00a5c46bd..07fd4d08d 100644 --- a/.github/actions/setup-javascript/action.yml +++ b/.github/actions/setup-javascript/action.yml @@ -9,7 +9,7 @@ runs: using: 'composite' steps: - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' From c260a68f544bf8af6440dc9c47a2c8526f21de29 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Mon, 20 Nov 2023 11:46:02 +0100 Subject: [PATCH 085/255] Clean up some `Mastodon::CLI::Accounts` tests (#27473) --- spec/lib/mastodon/cli/accounts_spec.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index 0445dec6c..626cf4778 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -779,6 +779,8 @@ describe Mastodon::CLI::Accounts do let(:arguments) { [account_example_com_a.acct, account_example_com_b.acct] } before do + # NOTE: `Account.find_remote` is stubbed so that `Account#reset_avatar!` + # can be stubbed on the individual accounts. allow(Account).to receive(:find_remote).with(account_example_com_a.username, account_example_com_a.domain).and_return(account_example_com_a) allow(Account).to receive(:find_remote).with(account_example_com_b.username, account_example_com_b.domain).and_return(account_example_com_b) allow(Account).to receive(:find_remote).with(account_example_net.username, account_example_net.domain).and_return(account_example_net) @@ -978,11 +980,10 @@ describe Mastodon::CLI::Accounts do end context 'when --all option is provided' do - let(:accounts) { Fabricate.times(2, :account) } - let(:options) { { all: true } } + let!(:accounts) { Fabricate.times(2, :account) } + let(:options) { { all: true } } before do - allow(Account).to receive(:local).and_return(Account.where(id: accounts.map(&:id))) cli.options = { all: true } end @@ -1581,8 +1582,7 @@ describe Mastodon::CLI::Accounts do context 'when the specified account is redirecting to a different target account' do before do - allow(Account).to receive(:find_local).with(source_account.username).and_return(source_account) - allow(source_account).to receive(:moved_to_account_id).and_return(-1) + source_account.update(moved_to_account: Fabricate(:account)) end it 'exits with an error message' do @@ -1597,9 +1597,8 @@ describe Mastodon::CLI::Accounts do let(:options) { { target: target_account.acct, force: true } } before do + source_account.update(moved_to_account: Fabricate(:account)) target_account.aliases.create!(acct: source_account.acct) - allow(Account).to receive(:find_local).with(source_account.username).and_return(source_account) - allow(source_account).to receive(:moved_to_account_id).and_return(-1) end it_behaves_like 'a successful migration' From 718c95e7affa6b9e679ab5a5885e6a886a413a94 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 20 Nov 2023 06:05:24 -0500 Subject: [PATCH 086/255] Convert `api/v1/custom_emojis` controller spec to request spec (#27985) Co-authored-by: Claire <claire.github-309c@sitedethib.com> --- .../api/v1/custom_emojis_controller_spec.rb | 18 -------- spec/requests/api/v1/custom_emojis_spec.rb | 45 +++++++++++++++++++ 2 files changed, 45 insertions(+), 18 deletions(-) delete mode 100644 spec/controllers/api/v1/custom_emojis_controller_spec.rb create mode 100644 spec/requests/api/v1/custom_emojis_spec.rb diff --git a/spec/controllers/api/v1/custom_emojis_controller_spec.rb b/spec/controllers/api/v1/custom_emojis_controller_spec.rb deleted file mode 100644 index 08af57f40..000000000 --- a/spec/controllers/api/v1/custom_emojis_controller_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Api::V1::CustomEmojisController do - render_views - - describe 'GET #index' do - before do - Fabricate(:custom_emoji) - get :index - end - - it 'returns http success' do - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v1/custom_emojis_spec.rb b/spec/requests/api/v1/custom_emojis_spec.rb new file mode 100644 index 000000000..5de0dda0b --- /dev/null +++ b/spec/requests/api/v1/custom_emojis_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Custom Emojis' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + describe 'GET /api/v1/custom_emojis' do + before do + Fabricate(:custom_emoji, domain: nil, disabled: false, visible_in_picker: true) + end + + context 'when logged out' do + it 'returns http success and json' do + get api_v1_custom_emojis_path + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and have_attributes( + first: include(shortcode: 'coolcat') + ) + end + end + + context 'when logged in' do + it 'returns http success and json' do + get api_v1_custom_emojis_path, headers: headers + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and have_attributes( + first: include(shortcode: 'coolcat') + ) + end + end + end +end From 876f5b1d12d315fa60f18864db5516b22bcab60f Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 20 Nov 2023 06:05:28 -0500 Subject: [PATCH 087/255] Convert `/instances/*` controller specs to request specs (#27988) Co-authored-by: Claire <claire.github-309c@sitedethib.com> --- .../api/v1/instances/activity_controller.rb | 47 +++++++++++----- .../v1/instances/domain_blocks_controller.rb | 14 ++++- .../v1/instances/activity_controller_spec.rb | 21 ------- .../domain_blocks_controller_spec.rb | 16 ------ .../extended_descriptions_controller_spec.rb | 15 ----- .../api/v1/instances/peers_controller_spec.rb | 21 ------- .../privacy_policies_controller_spec.rb | 15 ----- .../api/v1/instances/rules_controller_spec.rb | 15 ----- .../translation_languages_controller_spec.rb | 30 ---------- .../api/v1/instances_controller_spec.rb | 22 -------- .../api/v2/instances_controller_spec.rb | 22 -------- spec/requests/api/v1/instance_spec.rb | 37 +++++++++++++ .../api/v1/instances/activity_spec.rb | 40 ++++++++++++++ .../api/v1/instances/domain_blocks_spec.rb | 55 +++++++++++++++++++ .../instances/extended_descriptions_spec.rb | 18 ++++++ spec/requests/api/v1/instances/peers_spec.rb | 38 +++++++++++++ .../api/v1/instances/privacy_policies_spec.rb | 18 ++++++ spec/requests/api/v1/instances/rules_spec.rb | 17 ++++++ .../instances/translation_languages_spec.rb | 43 +++++++++++++++ spec/requests/api/v2/instance_spec.rb | 37 +++++++++++++ 20 files changed, 349 insertions(+), 192 deletions(-) delete mode 100644 spec/controllers/api/v1/instances/activity_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/domain_blocks_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/extended_descriptions_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/peers_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/privacy_policies_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/rules_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/translation_languages_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances_controller_spec.rb delete mode 100644 spec/controllers/api/v2/instances_controller_spec.rb create mode 100644 spec/requests/api/v1/instance_spec.rb create mode 100644 spec/requests/api/v1/instances/activity_spec.rb create mode 100644 spec/requests/api/v1/instances/domain_blocks_spec.rb create mode 100644 spec/requests/api/v1/instances/extended_descriptions_spec.rb create mode 100644 spec/requests/api/v1/instances/peers_spec.rb create mode 100644 spec/requests/api/v1/instances/privacy_policies_spec.rb create mode 100644 spec/requests/api/v1/instances/rules_spec.rb create mode 100644 spec/requests/api/v1/instances/translation_languages_spec.rb create mode 100644 spec/requests/api/v2/instance_spec.rb diff --git a/app/controllers/api/v1/instances/activity_controller.rb b/app/controllers/api/v1/instances/activity_controller.rb index 4c17bd79c..06e4fd8b8 100644 --- a/app/controllers/api/v1/instances/activity_controller.rb +++ b/app/controllers/api/v1/instances/activity_controller.rb @@ -3,6 +3,8 @@ class Api::V1::Instances::ActivityController < Api::V1::Instances::BaseController before_action :require_enabled_api! + WEEKS_OF_ACTIVITY = 12 + def show cache_even_if_authenticated! render_with_cache json: :activity, expires_in: 1.day @@ -11,23 +13,40 @@ class Api::V1::Instances::ActivityController < Api::V1::Instances::BaseControlle private def activity - statuses_tracker = ActivityTracker.new('activity:statuses:local', :basic) - logins_tracker = ActivityTracker.new('activity:logins', :unique) - registrations_tracker = ActivityTracker.new('activity:accounts:local', :basic) - - (0...12).map do |i| - start_of_week = i.weeks.ago - end_of_week = start_of_week + 6.days - - { - week: start_of_week.to_i.to_s, - statuses: statuses_tracker.sum(start_of_week, end_of_week).to_s, - logins: logins_tracker.sum(start_of_week, end_of_week).to_s, - registrations: registrations_tracker.sum(start_of_week, end_of_week).to_s, - } + activity_weeks.map do |weeks_ago| + activity_json(*week_edge_days(weeks_ago)) end end + def activity_json(start_of_week, end_of_week) + { + week: start_of_week.to_i.to_s, + statuses: statuses_tracker.sum(start_of_week, end_of_week).to_s, + logins: logins_tracker.sum(start_of_week, end_of_week).to_s, + registrations: registrations_tracker.sum(start_of_week, end_of_week).to_s, + } + end + + def activity_weeks + 0...WEEKS_OF_ACTIVITY + end + + def week_edge_days(num) + [num.weeks.ago, num.weeks.ago + 6.days] + end + + def statuses_tracker + ActivityTracker.new('activity:statuses:local', :basic) + end + + def logins_tracker + ActivityTracker.new('activity:logins', :unique) + end + + def registrations_tracker + ActivityTracker.new('activity:accounts:local', :basic) + end + def require_enabled_api! head 404 unless Setting.activity_api_enabled && !limited_federation_mode? end diff --git a/app/controllers/api/v1/instances/domain_blocks_controller.rb b/app/controllers/api/v1/instances/domain_blocks_controller.rb index 8fb90305a..7ec94312f 100644 --- a/app/controllers/api/v1/instances/domain_blocks_controller.rb +++ b/app/controllers/api/v1/instances/domain_blocks_controller.rb @@ -19,7 +19,19 @@ class Api::V1::Instances::DomainBlocksController < Api::V1::Instances::BaseContr private def require_enabled_api! - head 404 unless Setting.show_domain_blocks == 'all' || (Setting.show_domain_blocks == 'users' && user_signed_in?) + head 404 unless api_enabled? + end + + def api_enabled? + show_domain_blocks_for_all? || show_domain_blocks_to_user? + end + + def show_domain_blocks_for_all? + Setting.show_domain_blocks == 'all' + end + + def show_domain_blocks_to_user? + Setting.show_domain_blocks == 'users' && user_signed_in? end def set_domain_blocks diff --git a/spec/controllers/api/v1/instances/activity_controller_spec.rb b/spec/controllers/api/v1/instances/activity_controller_spec.rb deleted file mode 100644 index b446a521f..000000000 --- a/spec/controllers/api/v1/instances/activity_controller_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Api::V1::Instances::ActivityController do - describe 'GET #show' do - it 'returns 200' do - get :show - expect(response).to have_http_status(200) - end - - context 'with !Setting.activity_api_enabled' do - it 'returns 404' do - Setting.activity_api_enabled = false - - get :show - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/controllers/api/v1/instances/domain_blocks_controller_spec.rb b/spec/controllers/api/v1/instances/domain_blocks_controller_spec.rb deleted file mode 100644 index 08f505c3d..000000000 --- a/spec/controllers/api/v1/instances/domain_blocks_controller_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::Instances::DomainBlocksController do - render_views - - describe 'GET #index' do - it 'returns http success' do - Setting.show_domain_blocks = 'all' - get :index - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/controllers/api/v1/instances/extended_descriptions_controller_spec.rb b/spec/controllers/api/v1/instances/extended_descriptions_controller_spec.rb deleted file mode 100644 index 58c0d4b8f..000000000 --- a/spec/controllers/api/v1/instances/extended_descriptions_controller_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::Instances::ExtendedDescriptionsController do - render_views - - describe 'GET #show' do - it 'returns http success' do - get :show - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/controllers/api/v1/instances/peers_controller_spec.rb b/spec/controllers/api/v1/instances/peers_controller_spec.rb deleted file mode 100644 index 92b101915..000000000 --- a/spec/controllers/api/v1/instances/peers_controller_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Api::V1::Instances::PeersController do - describe 'GET #index' do - it 'returns 200' do - get :index - expect(response).to have_http_status(200) - end - - context 'with !Setting.peers_api_enabled' do - it 'returns 404' do - Setting.peers_api_enabled = false - - get :index - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/controllers/api/v1/instances/privacy_policies_controller_spec.rb b/spec/controllers/api/v1/instances/privacy_policies_controller_spec.rb deleted file mode 100644 index ac0bed9dc..000000000 --- a/spec/controllers/api/v1/instances/privacy_policies_controller_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::Instances::PrivacyPoliciesController do - render_views - - describe 'GET #show' do - it 'returns http success' do - get :show - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/controllers/api/v1/instances/rules_controller_spec.rb b/spec/controllers/api/v1/instances/rules_controller_spec.rb deleted file mode 100644 index 5af50239b..000000000 --- a/spec/controllers/api/v1/instances/rules_controller_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::Instances::RulesController do - render_views - - describe 'GET #index' do - it 'returns http success' do - get :index - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/controllers/api/v1/instances/translation_languages_controller_spec.rb b/spec/controllers/api/v1/instances/translation_languages_controller_spec.rb deleted file mode 100644 index f79687df6..000000000 --- a/spec/controllers/api/v1/instances/translation_languages_controller_spec.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::Instances::TranslationLanguagesController do - describe 'GET #show' do - context 'when no translation service is configured' do - it 'returns empty language matrix', :aggregate_failures do - get :show - - expect(response).to have_http_status(200) - expect(body_as_json).to eq({}) - end - end - - context 'when a translation service is configured' do - before do - service = instance_double(TranslationService::DeepL, languages: { nil => %w(en de), 'en' => ['de'] }) - allow(TranslationService).to receive_messages(configured?: true, configured: service) - end - - it 'returns language matrix', :aggregate_failures do - get :show - - expect(response).to have_http_status(200) - expect(body_as_json).to eq({ und: %w(en de), en: ['de'] }) - end - end - end -end diff --git a/spec/controllers/api/v1/instances_controller_spec.rb b/spec/controllers/api/v1/instances_controller_spec.rb deleted file mode 100644 index fcc2c9288..000000000 --- a/spec/controllers/api/v1/instances_controller_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Api::V1::InstancesController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'GET #show' do - it 'returns http success' do - get :show - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/controllers/api/v2/instances_controller_spec.rb b/spec/controllers/api/v2/instances_controller_spec.rb deleted file mode 100644 index b7206da0a..000000000 --- a/spec/controllers/api/v2/instances_controller_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V2::InstancesController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'GET #show' do - it 'returns http success' do - get :show - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v1/instance_spec.rb b/spec/requests/api/v1/instance_spec.rb new file mode 100644 index 000000000..9cac280c4 --- /dev/null +++ b/spec/requests/api/v1/instance_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Instances' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + describe 'GET /api/v1/instance' do + context 'when not logged in' do + it 'returns http success and json' do + get api_v1_instance_path + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and include(title: 'Mastodon') + end + end + + context 'when logged in' do + it 'returns http success and json' do + get api_v1_instance_path, headers: headers + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and include(title: 'Mastodon') + end + end + end +end diff --git a/spec/requests/api/v1/instances/activity_spec.rb b/spec/requests/api/v1/instances/activity_spec.rb new file mode 100644 index 000000000..d1f92ef36 --- /dev/null +++ b/spec/requests/api/v1/instances/activity_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Activity' do + describe 'GET /api/v1/instance/activity' do + around do |example| + original = Setting.activity_api_enabled + example.run + Setting.activity_api_enabled = original + end + + context 'with activity api enabled' do + before { Setting.activity_api_enabled = true } + + it 'returns http success' do + get api_v1_instance_activity_path + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and(be_an(Array)) + .and(have_attributes(size: Api::V1::Instances::ActivityController::WEEKS_OF_ACTIVITY)) + end + end + + context 'with activity api diabled' do + before { Setting.activity_api_enabled = false } + + it 'returns not found' do + get api_v1_instance_activity_path + + expect(response) + .to have_http_status(404) + end + end + end +end diff --git a/spec/requests/api/v1/instances/domain_blocks_spec.rb b/spec/requests/api/v1/instances/domain_blocks_spec.rb new file mode 100644 index 000000000..99b5e2b6a --- /dev/null +++ b/spec/requests/api/v1/instances/domain_blocks_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Domain Blocks' do + describe 'GET /api/v1/instance/domain_blocks' do + around do |example| + original = Setting.show_domain_blocks + example.run + Setting.show_domain_blocks = original + end + + before do + Fabricate(:domain_block) + end + + context 'with domain blocks set to all' do + before { Setting.show_domain_blocks = 'all' } + + it 'returns http success' do + get api_v1_instance_domain_blocks_path + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and(be_an(Array)) + .and(have_attributes(size: 1)) + end + end + + context 'with domain blocks set to users' do + before { Setting.show_domain_blocks = 'users' } + + it 'returns http not found' do + get api_v1_instance_domain_blocks_path + + expect(response) + .to have_http_status(404) + end + end + + context 'with domain blocks set to disabled' do + before { Setting.show_domain_blocks = 'disabled' } + + it 'returns http not found' do + get api_v1_instance_domain_blocks_path + + expect(response) + .to have_http_status(404) + end + end + end +end diff --git a/spec/requests/api/v1/instances/extended_descriptions_spec.rb b/spec/requests/api/v1/instances/extended_descriptions_spec.rb new file mode 100644 index 000000000..64982de68 --- /dev/null +++ b/spec/requests/api/v1/instances/extended_descriptions_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Extended Descriptions' do + describe 'GET /api/v1/instance/extended_description' do + it 'returns http success' do + get api_v1_instance_extended_description_path + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and include(:content) + end + end +end diff --git a/spec/requests/api/v1/instances/peers_spec.rb b/spec/requests/api/v1/instances/peers_spec.rb new file mode 100644 index 000000000..d3400ae8f --- /dev/null +++ b/spec/requests/api/v1/instances/peers_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Peers' do + describe 'GET /api/v1/instance/peers' do + around do |example| + original = Setting.peers_api_enabled + example.run + Setting.peers_api_enabled = original + end + + context 'with peers api enabled' do + before { Setting.peers_api_enabled = true } + + it 'returns http success' do + get api_v1_instance_peers_path + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_an(Array) + end + end + + context 'with peers api diabled' do + before { Setting.peers_api_enabled = false } + + it 'returns http not found' do + get api_v1_instance_peers_path + + expect(response) + .to have_http_status(404) + end + end + end +end diff --git a/spec/requests/api/v1/instances/privacy_policies_spec.rb b/spec/requests/api/v1/instances/privacy_policies_spec.rb new file mode 100644 index 000000000..24de98d88 --- /dev/null +++ b/spec/requests/api/v1/instances/privacy_policies_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Privacy Policy' do + describe 'GET /api/v1/instance/privacy_policy' do + it 'returns http success' do + get api_v1_instance_privacy_policy_path + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and include(:content) + end + end +end diff --git a/spec/requests/api/v1/instances/rules_spec.rb b/spec/requests/api/v1/instances/rules_spec.rb new file mode 100644 index 000000000..65b8d78c7 --- /dev/null +++ b/spec/requests/api/v1/instances/rules_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Rules' do + describe 'GET /api/v1/instance/rules' do + it 'returns http success' do + get api_v1_instance_rules_path + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_an(Array) + end + end +end diff --git a/spec/requests/api/v1/instances/translation_languages_spec.rb b/spec/requests/api/v1/instances/translation_languages_spec.rb new file mode 100644 index 000000000..0b7dd8314 --- /dev/null +++ b/spec/requests/api/v1/instances/translation_languages_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Translation Languages' do + describe 'GET /api/v1/instances/translation_languages' do + context 'when no translation service is configured' do + it 'returns empty language matrix', :aggregate_failures do + get api_v1_instance_translation_languages_path + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to eq({}) + end + end + + context 'when a translation service is configured' do + before { configure_translation_service } + + it 'returns language matrix', :aggregate_failures do + get api_v1_instance_translation_languages_path + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to eq({ und: %w(en de), en: ['de'] }) + end + + private + + def configure_translation_service + allow(TranslationService).to receive_messages(configured?: true, configured: service_double) + end + + def service_double + instance_double(TranslationService::DeepL, languages: { nil => %w(en de), 'en' => ['de'] }) + end + end + end +end diff --git a/spec/requests/api/v2/instance_spec.rb b/spec/requests/api/v2/instance_spec.rb new file mode 100644 index 000000000..74574afbc --- /dev/null +++ b/spec/requests/api/v2/instance_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Instances' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + describe 'GET /api/v2/instance' do + context 'when logged out' do + it 'returns http success and json' do + get api_v2_instance_path + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and include(title: 'Mastodon') + end + end + + context 'when logged in' do + it 'returns http success and json' do + get api_v2_instance_path, headers: headers + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_present + .and include(title: 'Mastodon') + end + end + end +end From e1bb79718b09fcc7c6f823a2a3890e39c15ed8e2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:20:23 +0100 Subject: [PATCH 088/255] Update babel monorepo to v7.23.4 (#28004) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index 562fdc757..efbde6641 100644 --- a/yarn.lock +++ b/yarn.lock @@ -981,14 +981,14 @@ __metadata: linkType: hard "@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.3, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.23.3" + version: 7.23.4 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.23.4" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f960faed3975c8454c52d2b5d85daf0c9a27677b248d7933882e59b10202ade2a98c7b925ce0bae2b8eb4d66eb5d63a5588c1090d54eaa4cd235533d71228ff3 + checksum: bce490d22da5c87ff27fffaff6ad5a4d4979b8d7b72e30857f191e9c1e1824ba73bb8d7081166289369e388f94f0ce5383a593b1fc84d09464a062c75f824b0b languageName: node linkType: hard @@ -1200,8 +1200,8 @@ __metadata: linkType: hard "@babel/plugin-transform-runtime@npm:^7.22.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-runtime@npm:7.23.3" + version: 7.23.4 + resolution: "@babel/plugin-transform-runtime@npm:7.23.4" dependencies: "@babel/helper-module-imports": "npm:^7.22.15" "@babel/helper-plugin-utils": "npm:^7.22.5" @@ -1211,7 +1211,7 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 111fc412cc3968402183086879e1625ad4b869309f2e5aa33498a71ba700d3196c151d506977b5b535e8ff2c42c0731d59bfbfcb158ecddeeb3c49d5d4a58c0a + checksum: 6ac29012550cdd10b65ec43fef0c7f43904ec458c43d597f627d8f52807413e57ea94e3986dbace576d734e67c2d09be5e43e77c72567d18f8c4ac5e19844625 languageName: node linkType: hard @@ -1483,11 +1483,11 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.23.2 - resolution: "@babel/runtime@npm:7.23.2" + version: 7.23.4 + resolution: "@babel/runtime@npm:7.23.4" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 271fcfad8574269d9967b8a1c03f2e1eab108a52ad7c96ed136eee0b11f46156f1186637bd5e79a4207163db9a00413cd70a6428e137b982d0ee8ab85eb9f438 + checksum: db2bf183cd0119599b903ca51ca0aeea8e0ab478a16be1aae10dd90473ed614159d3e5adfdd8f8f3d840402428ce0d90b5c01aae95da9e45a2dd83e02d85ca27 languageName: node linkType: hard From a6d446e6a73abb687f8f3a2b08cf0c955b6049dc Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 21 Nov 2023 05:28:55 -0500 Subject: [PATCH 089/255] Add coverage for `remote_interaction_helper` (#28002) --- .../remote_interaction_helper_spec.rb | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 spec/requests/remote_interaction_helper_spec.rb diff --git a/spec/requests/remote_interaction_helper_spec.rb b/spec/requests/remote_interaction_helper_spec.rb new file mode 100644 index 000000000..e6364fe8c --- /dev/null +++ b/spec/requests/remote_interaction_helper_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Remote Interaction Helper' do + describe 'GET /remote_interaction_helper' do + it 'returns http success' do + get remote_interaction_helper_path + + expect(response) + .to have_http_status(200) + .and render_template(:index, layout: 'helper_frame') + .and have_attributes( + headers: include( + 'X-Frame-Options' => 'SAMEORIGIN', + 'Referrer-Policy' => 'no-referrer', + 'Content-Security-Policy' => expected_csp_headers + ) + ) + end + end + + private + + def expected_csp_headers + <<~CSP.squish + default-src 'none'; frame-ancestors 'self'; form-action 'none'; script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'; connect-src https: + CSP + end +end From 3c3e0c25ef01cb3b752ad9b9d2e6791b30688f1f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:35:02 +0100 Subject: [PATCH 090/255] New Crowdin Translations (automated) (#28015) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/cy.json | 3 + app/javascript/mastodon/locales/gl.json | 2 +- app/javascript/mastodon/locales/ko.json | 19 ++--- config/locales/de.yml | 2 +- config/locales/devise.lt.yml | 92 +++++++++++++++++++++++-- config/locales/doorkeeper.de.yml | 2 +- config/locales/eo.yml | 4 ++ config/locales/ko.yml | 4 +- config/locales/simple_form.eo.yml | 21 +++++- config/locales/simple_form.ko.yml | 4 +- 10 files changed, 131 insertions(+), 22 deletions(-) diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 6b7fb1b86..4ecf48735 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -480,6 +480,8 @@ "onboarding.follows.empty": "Yn anffodus, nid oes modd dangos unrhyw ganlyniadau ar hyn o bryd. Gallwch geisio defnyddio chwilio neu bori'r dudalen archwilio i ddod o hyd i bobl i'w dilyn, neu ceisio eto yn nes ymlaen.", "onboarding.follows.lead": "Rydych chi'n curadu eich ffrwd gartref eich hun. Po fwyaf o bobl y byddwch chi'n eu dilyn, y mwyaf egnïol a diddorol fydd hi. Gall y proffiliau hyn fod yn fan cychwyn da - gallwch chi bob amser eu dad-ddilyn yn nes ymlaen:", "onboarding.follows.title": "Yn boblogaidd ar Mastodon", + "onboarding.profile.discoverable": "Gwnewch fy mhroffil yn un y gellir ei ddarganfod", + "onboarding.profile.discoverable_hint": "Pan fyddwch yn optio i mewn i ddarganfodadwyedd ar Mastodon, gall eich postiadau ymddangos mewn canlyniadau chwilio a thueddiadau, ac efallai y bydd eich proffil yn cael ei awgrymu i bobl sydd â diddordebau tebyg i chi.", "onboarding.profile.display_name_hint": "Eich enw llawn neu'ch enw hwyl…", "onboarding.profile.note": "Bywgraffiad", "onboarding.profile.note_hint": "Gallwch @grybwyll pobl eraill neu #hashnodau…", @@ -529,6 +531,7 @@ "privacy.unlisted.short": "Heb ei restru", "privacy_policy.last_updated": "Diweddarwyd ddiwethaf ar {date}", "privacy_policy.title": "Polisi Preifatrwydd", + "recommended": "Argymhellwyd", "refresh": "Adnewyddu", "regeneration_indicator.label": "Yn llwytho…", "regeneration_indicator.sublabel": "Mae eich ffrwd cartref yn cael ei baratoi!", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 03f0318f3..83bc826a7 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -481,7 +481,7 @@ "onboarding.follows.empty": "Desgraciadamente agora mesmo non hai nada que mostrar. Podes intentalo coa busca ou na páxina descubrir para atopar persoas ás que seguir, ou intentalo máis tarde.", "onboarding.follows.lead": "Podes facer que a túa cronoloxía de inicio sexa como ti a queres. Canta máis xente sigas máis interesante será. Estes perfís poderían axudarche a comezar —sempre poderás deixar de seguilos despois!", "onboarding.follows.title": "Popular en Mastodon", - "onboarding.profile.discoverable": "Que o meu perfil sexa atopable", + "onboarding.profile.discoverable": "Que o meu perfil se poida atopar", "onboarding.profile.discoverable_hint": "Cando elixes que poidan atoparte en Mastodon as túas publicacións aparecerán nos resultados das buscas e nos temas en voga, e o teu perfil podería ser suxerido para seguimento a persoas con intereses semellantes aos teus.", "onboarding.profile.display_name": "Nome público", "onboarding.profile.display_name_hint": "O teu nome completo ou un nome divertido…", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 8d1c77fac..51189b6a9 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -326,7 +326,7 @@ "interaction_modal.no_account_yet": "Mastodon 계정이 없나요?", "interaction_modal.on_another_server": "다른 서버에", "interaction_modal.on_this_server": "이 서버에서", - "interaction_modal.sign_in": "이 서버에 로그인되어 있지 않습니다. 계정이 어디에 속해 있나요?", + "interaction_modal.sign_in": "이 서버에 로그인하지 않았습니다. 계정이 어디에 속해있습니까?", "interaction_modal.sign_in_hint": "팁: 여러분이 가입한 사이트입니다. 만약 기억이 나지 않는다면 가입환영 이메일을 찾아보는 것도 좋습니다. 전체 사용자이름(예: @mastodon@mastodon.social)을 넣어도 됩니다!", "interaction_modal.title.favourite": "{name} 님의 게시물을 좋아하기", "interaction_modal.title.follow": "{name} 님을 팔로우", @@ -482,6 +482,7 @@ "onboarding.follows.lead": "홈 피드는 마스토돈을 경험하는 주된 경로입니다. 더 많은 사람들을 팔로우 할수록 더 활발하고 흥미로워질 것입니다. 여기 시작을 위한 몇몇 추천을 드립니다:", "onboarding.follows.title": "내게 맞는 홈 피드 꾸미기", "onboarding.profile.discoverable": "내 프로필을 발견 가능하도록 설정", + "onboarding.profile.discoverable_hint": "마스토돈의 발견하기 기능에 참여하면 게시물이 검색 결과와 유행 란에 표시될 수 있고, 비슷한 관심사를 가진 사람들에게 자신의 프로필이 추천될 수 있습니다.", "onboarding.profile.display_name": "표시되는 이름", "onboarding.profile.display_name_hint": "진짜 이름 또는 재미난 이름…", "onboarding.profile.lead": "언제든지 나중에 설정 메뉴에서 마저 할 수 있고, 그곳에서 더 많은 맞춤 옵션을 고를 수 있습니다.", @@ -491,7 +492,7 @@ "onboarding.profile.title": "프로필 설정", "onboarding.profile.upload_avatar": "프로필 사진 업로드", "onboarding.profile.upload_header": "프로필 헤더 업로드", - "onboarding.share.lead": "여러 사람에게 마스토돈에서 나를 찾을 수 있는 방법을 알려주세요!", + "onboarding.share.lead": "여러 사람에게 마스토돈에서 나를 찾을 수 있는 방법을 알립니다!", "onboarding.share.message": "#마스토돈 이용하는 {username}입니다! {url} 에서 저를 팔로우 해보세요", "onboarding.share.next_steps": "할만한 다음 단계:", "onboarding.share.title": "프로필 공유하기", @@ -556,7 +557,7 @@ "report.categories.other": "기타", "report.categories.spam": "스팸", "report.categories.violation": "콘텐츠가 한 개 이상의 서버 규칙을 위반합니다", - "report.category.subtitle": "가장 알맞은 것을 선택하세요", + "report.category.subtitle": "가장 알맞은 것을 선택", "report.category.title": "이 {type}에 무슨 문제가 있는지 알려주세요", "report.category.title_account": "프로필", "report.category.title_status": "게시물", @@ -578,9 +579,9 @@ "report.reasons.spam_description": "악성 링크, 반응 스팸, 또는 반복적인 답글", "report.reasons.violation": "서버 규칙을 위반합니다", "report.reasons.violation_description": "특정 규칙을 위반합니다", - "report.rules.subtitle": "해당하는 사항을 모두 선택하세요", + "report.rules.subtitle": "해당하는 사항을 모두 선택", "report.rules.title": "어떤 규칙을 위반했나요?", - "report.statuses.subtitle": "해당하는 사항을 모두 선택하세요", + "report.statuses.subtitle": "해당하는 사항을 모두 선택", "report.statuses.title": "이 신고에 대해서 더 참고해야 할 게시물이 있나요?", "report.submit": "신고하기", "report.target": "{target} 신고하기", @@ -683,7 +684,7 @@ "status.title.with_attachments": "{user} 님이 {attachmentCount, plural, one {첨부} other {{attachmentCount}개 첨부}}하여 게시", "status.translate": "번역", "status.translated_from_with": "{provider}에 의해 {lang}에서 번역됨", - "status.uncached_media_warning": "미리보기를 사용할 수 없습니다", + "status.uncached_media_warning": "마리보기 허용되지 않음", "status.unmute_conversation": "이 대화의 뮤트 해제하기", "status.unpin": "고정 해제", "subscribed_languages.lead": "변경 후에는 선택한 언어들로 작성된 게시물들만 홈 타임라인과 리스트 타임라인에 나타나게 됩니다. 아무 것도 선택하지 않으면 모든 언어로 작성된 게시물을 받아봅니다.", @@ -709,7 +710,7 @@ "upload_area.title": "드래그 & 드롭으로 업로드", "upload_button.label": "이미지, 영상, 오디오 파일 추가", "upload_error.limit": "파일 업로드 제한에 도달했습니다.", - "upload_error.poll": "파일 업로드는 설문과 함께 쓸 수 없어요.", + "upload_error.poll": "파일 업로드는 설문과 함께 쓸 수 없습니다.", "upload_form.audio_description": "청각 장애인을 위한 설명", "upload_form.description": "시각장애인을 위한 설명", "upload_form.description_missing": "설명이 추가되지 않음", @@ -717,12 +718,12 @@ "upload_form.thumbnail": "썸네일 변경", "upload_form.undo": "삭제", "upload_form.video_description": "청각, 시각 장애인을 위한 설명", - "upload_modal.analyzing_picture": "이미지 분석 중…", + "upload_modal.analyzing_picture": "그림 분석 중…", "upload_modal.apply": "적용", "upload_modal.applying": "적용 중...", "upload_modal.choose_image": "이미지 선택", "upload_modal.description_placeholder": "다람쥐 헌 쳇바퀴 타고파", - "upload_modal.detect_text": "이미지에서 텍스트 추출", + "upload_modal.detect_text": "그림에서 문자 탐색", "upload_modal.edit_media": "미디어 수정", "upload_modal.hint": "미리보기를 클릭하거나 드래그 해서 포컬 포인트를 맞추세요. 이 점은 썸네일에 항상 보여질 부분을 나타냅니다.", "upload_modal.preparing_ocr": "OCR 준비 중…", diff --git a/config/locales/de.yml b/config/locales/de.yml index 69309737d..0d9cf8c03 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1239,7 +1239,7 @@ de: home: Startseite und Listen notifications: Benachrichtigungen public: Öffentliche Timelines - thread: Unterhaltungen + thread: Private Erwähnungen edit: add_keyword: Schlagwort hinzufügen keywords: Schlagwörter diff --git a/config/locales/devise.lt.yml b/config/locales/devise.lt.yml index aedba2498..5429b217d 100644 --- a/config/locales/devise.lt.yml +++ b/config/locales/devise.lt.yml @@ -3,8 +3,8 @@ lt: devise: confirmations: confirmed: Tavo el. pašto adresas buvo sėkmingai patvirtintas. - send_instructions: Po kelių minučių gausi el. laišką su instrukcijomis, kaip patvirtinti savo el. pašto adresą. Jei negavai šio el. laiško, patikrink šlamšto laiškų aplanką. - send_paranoid_instructions: Jei tavo el. pašto adresas yra mūsų duomenų bazėje, po kelių minučių gausi el. laišką su instrukcijomis, kaip patvirtinti savo el. pašto adresą. Jei negavai šio el. laiško, patikrink šlamšto laiškų aplanką. + send_instructions: Po kelių minučių gausi el. laišką su instrukcijomis, kaip patvirtinti savo el. pašto adresą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. + send_paranoid_instructions: Jei tavo el. pašto adresas yra mūsų duomenų bazėje, po kelių minučių gausi el. laišką su instrukcijomis, kaip patvirtinti savo el. pašto adresą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. failure: already_authenticated: Tu jau prisijungęs (-usi). inactive: Tavo paskyra dar nėra aktyvuota. @@ -22,14 +22,96 @@ lt: action_with_app: Patvirtinti ir grįžti į %{app} explanation: Šiuo el. pašto adresu sukūrei paskyrą %{host}. Iki jos aktyvavimo liko vienas paspaudimas. Jei tai buvo ne tu, ignoruok šį el. laišką. explanation_when_pending: Šiuo el. pašto adresu pateikei paraišką pakvietimui į %{host}. Kai patvirtinsi savo el. pašto adresą, mes peržiūrėsime tavo paraišką. Gali prisijungti ir pakeisti savo duomenis arba ištrinti paskyrą, tačiau negalėsi naudotis daugeliu funkcijų, kol tavo paskyra nebus patvirtinta. Jei tavo paraiška bus atmesta, duomenys bus pašalinti, todėl jokių papildomų veiksmų iš tavęs nereikės. Jei tai buvo ne tu, ignoruok šį el. laišką. + extra_html: Taip pat peržiūrėk <a href="%{terms_path}">serverio taisykles</a> ir <a href="%{policy_path}">mūsų paslaugų teikimo sąlygas</a>. + subject: 'Mastodon: patvirtinimo instrukcijos %{instance}' + title: Patvirtinti el. pašto adresą + email_changed: + explanation: 'Tavo paskyros el. pašto adresas yra keičiamas į:' + extra: Jei el. pašto nepakeitei, tikėtina, kad kažkas įgijo prieigą prie tavo paskyros. Nedelsiant pakeisk slaptažodį arba kreipkis į serverio administratorių (-ę), jei tavo paskyra užrakinta. + subject: 'Mastodon: el. paštas pakeistas' + title: Naujas el. pašto adresas + password_change: + explanation: Pakeistas tavo paskyros slaptažodis. + extra: Jei slaptažodio nepakeitei, tikėtina, kad kažkas įgijo prieigą prie tavo paskyros. Nedelsiant pakeisk slaptažodį arba kreipkis į serverio administratorių (-ę), jei tavo paskyra užrakinta. + subject: 'Mastodon: slaptažodis pakeistas' + title: Pakeistas slaptažodis + reconfirmation_instructions: + explanation: Patvirtink naująjį adresą, kad pakeistum savo el. paštą. + extra: Jei šį pakeitimą pradėjai ne tu, ignoruok šį el. laišką. Mastodon paskyros el. pašto adresas nepasikeis, kol nepasinaudosi aukščiau pateikta nuoroda. + subject: 'Mastodon: patvirtinti el. paštą %{instance}' + title: Patvirtinti el. pašto adresą + reset_password_instructions: + action: Keisti slaptažodį + explanation: Paprašei naujo paskyros slaptažodžio. + extra: Jei to neprašei, ignoruok šį el. laišką. Tavo slaptažodis nepasikeis, kol nepasinaudosi aukščiau esančia nuoroda ir nesusikursi naują. + subject: 'Mastodon: slaptažodžio keitimo instrukcijos' + title: Slaptažodžio keitimas + two_factor_disabled: + explanation: Dviejų tapatybės patikrinimas tavo paskyrai buvo išjungtas. Prisijungimas dabar galimas naudojant tik el. pašto adresą ir slaptažodį. + subject: 'Mastodon: dviejų tapatybės patikrinimas išjungtas' + title: 2FA išjungta + two_factor_enabled: + explanation: Tavo paskyrai įgalintas dvejų tapatybės patikrinimas. Prisijungiant reikės susietos TOTP programėlės sugeneruoto priegos rakto. + subject: 'Mastodon: dviejų tapatybės patikrinimas įgalintas' + title: 2FA įgalinta + two_factor_recovery_codes_changed: + explanation: Ankstesnieji atkūrimo kodai yra negaliojantys ir sugeneruojami nauji. + subject: 'Mastodon: dviejų tapatybės atkūrimo kodai iš naujo sugeneruoti' + title: Pakeisti 2FA atkūrimo kodai unlock_instructions: subject: 'Mastodon: atrakinimo instrukcijos' + webauthn_credential: + added: + explanation: Į tavo paskyrą buvo pridėtas šis saugumo raktas + subject: 'Mastodon: naujas saugumo raktas' + title: Pridėtas naujas saugumo raktas + deleted: + explanation: Iš tavo paskyros buvo ištrintas šis saugumo raktas + subject: 'Mastodon: saugumo raktas ištrintas' + title: Vienas iš tavo saugumo raktų buvo ištrintas + webauthn_disabled: + explanation: Tavo paskyrai buvo išjungtas tapatybės nustatymas naudojant saugumo raktus. Prisijungimas dabar galimas naudojant tik susietos TOTP programėlės sugeneruotą prieigos raktą. + subject: 'Mastodon: tapatybės nustatymas naudojant saugumo raktai išjungta' + title: Saugumo raktai išjungti + webauthn_enabled: + explanation: Saugumo rakto tapatybės nustatymas tavo paskyrai įgalintas. Dabar prisijungimui galima naudoti saugumo raktą. + subject: 'Mastodon: saugumo rakto tapatybės nustatymas įgalintas' + title: Saugumo raktai įgalinti + omniauth_callbacks: + failure: Nepavyko nustatyti tapatybės iš %{kind}, nes „%{reason}“. + success: Sėkmingai nustatyta tapatybė iš %{kind} paskyros. passwords: - no_token: Į šį puslapį gali patekti tik gavęs (-usi) slaptažodžio atstatymo el. laišką. Jei atėjai iš slaptažodžio atstatymo el. laiško, įsitikink, kad naudojai visą pateiktą URL adresą. + no_token: Į šį puslapį gali patekti tik gavęs (-usi) slaptažodžio keitimo el. laišką. Jei atėjai iš slaptažodžio keitimo el. laiško, įsitikink, kad naudojai visą pateiktą URL adresą. + send_instructions: Jei tavo el. pašto adresas egzistuoja mūsų duomenų bazėje, po kelių minučių į savo el. pašto adresą gausi slaptažodžio atkūrimo nuorodą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. + send_paranoid_instructions: Jei tavo el. pašto adresas egzistuoja mūsų duomenų bazėje, po kelių minučių į savo el. pašto adresą gausi slaptažodžio atkūrimo nuorodą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. + updated: Tavo slaptažodis buvo sėkmingai pakeistas. Dabar esi prisijungęs (-usi). + updated_not_active: Tavo slaptažodis buvo sėkmingai pakeistas. registrations: - destroyed: Iki pasimatymo! Tavo paskyra sėkmingai atšaukta. Tikimės, kad netrukus vėl pasimatysime. + destroyed: Iki pasimatymo! Tavo paskyra sėkmingai atšaukta. Tikimės, kad netrukus vėl pamatysime tave. + signed_up: Sveiki! Tu sėkmingai užsiregistravai. + signed_up_but_inactive: Sėkmingai užsiregistravai. Tačiau negalėjome tavęs prijungti, nes tavo paskyra dar nėra aktyvuota. + signed_up_but_locked: Sėkmingai užsiregistravai. Tačiau negalėjome tavęs prijungti, nes tavo paskyra dar užrakinta. + signed_up_but_pending: Į tavo el. pašto adresą buvo išsiųstas laiškas su patvirtinimo nuoroda. Paspaudęs (-usi) nuorodą, peržiūrėsime tavo paraišką. Tau bus pranešta, jei ji patvirtinta. + signed_up_but_unconfirmed: Į tavo el. pašto adresą buvo išsiųstas laiškas su patvirtinimo nuoroda. Paspausk nuorodą, kad aktyvuotum savo paskyrą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. + update_needs_confirmation: Sėkmingai atnaujinai savo paskyrą, bet mums reikia patvirtinti naująjį el. pašto adresą. Patikrink savo el. paštą ir paspausk patvirtinimo nuorodą, kad patvirtintum savo naują el. pašto adresą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. + updated: Tavo paskyra buvo sėkmingai atnaujinta. + sessions: + already_signed_out: Atsijungta sėkmingai. + signed_in: Prisijungta sėkmingai. + signed_out: Atjungta sėkmingai. + unlocks: + send_instructions: Po kelių minučių gausi el. laišką su instrukcijomis, kaip atrakinti paskyrą. Jei negavai šio el. laiško, patikrink šlamšto aplanką. + send_paranoid_instructions: Jei paskyra egzistuoja, po kelių minučių gausi el. laišką su instrukcijomis, kaip ją atrakinti. Jei negavai šio el. laiško, patikrink šlamšto aplanką. + unlocked: Tavo paskyra sėkmingai atrakinta. Norėdamas (-a) tęsti, prisijunk. errors: messages: - expired: nustojo galioti, prašyk naujos. + already_confirmed: jau buvo patvirtintas, pabandyk prisijungti. + confirmation_period_expired: turi būti patvirtintas per %{period}, paprašyk naujo. + expired: nustojo galioti, paprašyk naujos. not_found: nerasta. not_locked: nebuvo užrakintas. + not_saved: + few: "%{count} klaidos neleido išsaugoti šio %{resource}:" + many: "%{count} klaido neleido išsaugoti šio %{resource}:" + one: '1 klaida neleido išsaugoti šio %{resource}:' + other: "%{count} klaidų neleido išsaugoti šio %{resource}:" diff --git a/config/locales/doorkeeper.de.yml b/config/locales/doorkeeper.de.yml index cc7b88a28..552dfeba3 100644 --- a/config/locales/doorkeeper.de.yml +++ b/config/locales/doorkeeper.de.yml @@ -125,7 +125,7 @@ de: all: Voller Zugriff auf dein Mastodon-Konto blocks: Blockierungen bookmarks: Lesezeichen - conversations: Unterhaltungen + conversations: Private Erwähnungen crypto: Ende-zu-Ende-Verschlüsselung favourites: Favoriten filters: Filter diff --git a/config/locales/eo.yml b/config/locales/eo.yml index 12c646145..30c1e0d4e 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -773,6 +773,8 @@ eo: site_uploads: delete: Forigi elŝutitan dosieron destroyed_msg: Reteja alŝuto sukcese forigita! + software_updates: + documentation_link: Lerni pli statuses: account: Skribanto application: Aplikaĵo @@ -994,6 +996,8 @@ eo: help_html: Se vi havas problemojn solvi la CAPTCHA, vi povas kontakti nin per %{email} kaj ni povas helpi vin. title: Sekureckontrolo confirmations: + login_link: ensaluti + welcome_title: Bonvenon, %{name}! wrong_email_hint: Se tiu retpoŝtadreso ne estas ĝusta, vi povas ŝanĝi ĝin en la agordoj pri la konto. delete_account: Forigi konton delete_account_html: Se vi deziras forigi vian konton, vi povas <a href="%{path}">fari tion ĉi tie</a>. Vi bezonos konfirmi vian peton. diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 7dcb5d632..767c54ed1 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -763,7 +763,7 @@ ko: open: 누구나 가입 할 수 있음 security: authorized_fetch: 연합된 서버들에게서 인증 필수 - authorized_fetch_hint: 연합된 서버들에게서 인증을 요구하는 것은 사용자 레벨과 서버 레벨의 차단을 좀 더 확실하게 해줍니다. 한편으로는 성능적인 페널티, 답글의 전달 범위 감소, 몇몇 연합된 서비스들과의 호환성 문제가 있을 가능성이 있습니다. 추가적으로 이 기능은 전용 액터가 공개돤 게시물이나 계정을 페치하는 것은 막지 않습니다. + authorized_fetch_hint: 연합된 서버들에게서 인증을 요구하는 것은 사용자 레벨과 서버 레벨의 차단을 좀 더 확실하게 해줍니다. 한편으로는 성능적인 페널티, 답글의 전달 범위 감소, 몇몇 연합된 서비스들과의 호환성 문제가 있을 가능성이 있습니다. 추가적으로 이 기능은 전용 액터가 공개된 게시물이나 계정을 페치하는 것은 막지 않습니다. authorized_fetch_overridden_hint: 현재 이 값은 환경변수에 의해 설정되어 있기에 설정을 변경할 수 없습니다. federation_authentication: 연합 인증 필수 title: 서버 설정 @@ -1177,7 +1177,7 @@ ko: invalid_domain: 올바른 도메인 네임이 아닙니다 edit_profile: basic_information: 기본 정보 - hint_html: "<strong>내 공개 프로필과 게시물 옆에 보이는 부분을 꾸미세요.</strong> 다른 사람들은 프로필 내용과 사진이 채워진 계정과 더 상호작용하고 팔로우를 하고 싶어합니다." + hint_html: "<strong>사람들이 공개 프로필을 보고서 게시물을 볼 때를 위한 프로필을 꾸밉니다.</strong> 프로필과 프로필 그림을 채우면 다른 사람들이 나를 팔로우하고 나와 교류할 기회가 더 많아집니다." other: 기타 errors: '400': 제출한 요청이 올바르지 않습니다. diff --git a/config/locales/simple_form.eo.yml b/config/locales/simple_form.eo.yml index 3504b3953..d25412561 100644 --- a/config/locales/simple_form.eo.yml +++ b/config/locales/simple_form.eo.yml @@ -8,6 +8,8 @@ eo: fields: Via retpaĝo, pronomoj, aĝo, ĉio, kion vi volas. indexable: Viaj publikaj afiŝoj povas aperi en serĉrezultoj ĉe Mastodon. Homoj, kiuj interagis kun viaj afiŝoj, eble povos serĉi ilin sendepende. note: 'Vi povas @mencii aliajn homojn aŭ #haŝetikedoj.' + show_collections: Homoj povos foliumi viajn sekvatojn kaj sekvantojn. Homoj, kiujn vi sekvas, vidos, ke vi sekvas ilin ĉiaokaze. + unlocked: Homoj povos sekvi vin sen peto de aprobo. Malelektu se vi volas kontroli petojn de sekvado kaj elekti, ĉu akcepti aŭ malakcepti novajn sekvantojn. account_alias: acct: Specifu la uzantnomon@domajnon de la konto el kiu vi volas translokiĝi account_migration: @@ -118,6 +120,9 @@ eo: sessions: otp: 'Enmetu la kodon de dufaktora aŭtentigo el via telefono aŭ uzu unu el viaj realiraj kodoj:' webauthn: Se ĝi estas USB-ŝlosilo, certu enmeti ĝin kaj, se necese, frapi ĝin. + settings: + indexable: Via profila paĝo povas aperi en serĉrezultoj en Google, Bing kaj aliaj. + show_application: Vi ĉiam povos vidi kiu aplikaĵo publikigis vian afiŝon ĉiaokaze. tag: name: Vi povas ŝanĝi nur la majuskladon de la literoj, ekzemple, por igi ĝin pli legebla user: @@ -135,9 +140,13 @@ eo: url: Kien eventoj sendotas labels: account: + discoverable: Elstarigi profilon kaj afiŝojn en eltrovantaj algoritmoj fields: name: Etikedo value: Enhavo + indexable: Inkludi publikajn afiŝojn en serĉrezultoj + show_collections: Montri sekvatojn kaj sekvantojn en la profilo + unlocked: Aŭtomate akcepti novajn sekvantojn account_alias: acct: Tenilo de la malnovan konton account_migration: @@ -221,7 +230,7 @@ eo: username_or_email: Uzantnomo aŭ Retadreso whole_word: Tuta vorto email_domain_block: - with_dns_records: Inkluzu MX-rekordojn kaj IP de la domajno + with_dns_records: Inkludi MX-rekordojn kaj IP-jn de la domajno featured_tag: name: Kradvorto filters: @@ -282,9 +291,18 @@ eo: pending_account: Sendi retmesaĝon kiam nova konto bezonas kontrolon reblog: Sendi retmesaĝon kiam iu diskonigas vian mesaĝon report: Nova raporto estas proponita + software_updates: + all: Sciigi pri ĉiuj ĝisdatigoj + critical: Sciigi nur pri gravaj ĝisdatigoj + label: Nova Mastodon-versio disponeblas + none: Neniam sciigi pri ĝisdatigoj (malrekomendita) + patch: Sciigi pri cimoriparaj ĝisdatigoj trending_tag: Nova furoro bezonas kontrolon rule: text: Regulo + settings: + indexable: Inkludi profilan paĝon en serĉiloj + show_application: Montri el kiu aplikaĵo vi sendis afiŝon tag: listable: Permesi ĉi tiun kradvorton aperi en serĉoj kaj sugestoj name: Kradvorto @@ -305,6 +323,7 @@ eo: url: Finpunkto-URL 'no': Ne not_recommended: Nerekomendita + overridden: Anstataŭigita recommended: Rekomendita required: mark: "*" diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml index 720012a31..7372be719 100644 --- a/config/locales/simple_form.ko.yml +++ b/config/locales/simple_form.ko.yml @@ -176,7 +176,7 @@ ko: text: 이 결정을 번복해야만 하는 이유가 무엇입니까 defaults: autofollow: 초대를 통한 팔로우 - avatar: 프로필 사진 + avatar: 프로필 그림 bot: 이것은 자동화된 계정입니다 chosen_languages: 언어 필터링 confirm_new_password: 암호 다시 입력 @@ -188,7 +188,7 @@ ko: email: 이메일 주소 expires_in: 만기 fields: 부가 필드 - header: 헤더 + header: 헤더 그림 honeypot: "%{label} (채우지 마시오)" inbox_url: 릴레이 서버의 inbox URL irreversible: 숨기는 대신 삭제 From 6d51ac246b1902feea59d35a7c7f534724d59d20 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 21 Nov 2023 05:52:20 -0500 Subject: [PATCH 091/255] Update partials for the `AdminMailer.new_trends` mailer (#28011) --- app/views/admin_mailer/_new_trending_links.text.erb | 2 +- .../admin_mailer/_new_trending_statuses.text.erb | 2 +- app/views/admin_mailer/_new_trending_tags.text.erb | 8 +------- app/views/admin_mailer/new_trends.text.erb | 12 +++--------- config/locales/an.yml | 2 -- config/locales/ar.yml | 2 -- config/locales/be.yml | 2 -- config/locales/bg.yml | 2 -- config/locales/ca.yml | 2 -- config/locales/cs.yml | 2 -- config/locales/cy.yml | 2 -- config/locales/da.yml | 2 -- config/locales/de.yml | 2 -- config/locales/el.yml | 2 -- config/locales/en-GB.yml | 2 -- config/locales/en.yml | 2 -- config/locales/eo.yml | 2 -- config/locales/es-AR.yml | 2 -- config/locales/es-MX.yml | 2 -- config/locales/es.yml | 2 -- config/locales/et.yml | 2 -- config/locales/eu.yml | 2 -- config/locales/fa.yml | 1 - config/locales/fi.yml | 2 -- config/locales/fo.yml | 2 -- config/locales/fr-QC.yml | 2 -- config/locales/fr.yml | 2 -- config/locales/fy.yml | 2 -- config/locales/gd.yml | 2 -- config/locales/gl.yml | 2 -- config/locales/he.yml | 2 -- config/locales/hu.yml | 2 -- config/locales/id.yml | 2 -- config/locales/io.yml | 2 -- config/locales/is.yml | 2 -- config/locales/it.yml | 2 -- config/locales/ja.yml | 2 -- config/locales/ko.yml | 2 -- config/locales/ku.yml | 2 -- config/locales/lv.yml | 2 -- config/locales/ms.yml | 2 -- config/locales/my.yml | 2 -- config/locales/nl.yml | 2 -- config/locales/nn.yml | 2 -- config/locales/no.yml | 2 -- config/locales/pl.yml | 2 -- config/locales/pt-BR.yml | 2 -- config/locales/pt-PT.yml | 2 -- config/locales/ru.yml | 2 -- config/locales/sco.yml | 2 -- config/locales/si.yml | 2 -- config/locales/sl.yml | 2 -- config/locales/sq.yml | 1 - config/locales/sr-Latn.yml | 2 -- config/locales/sr.yml | 2 -- config/locales/sv.yml | 2 -- config/locales/th.yml | 2 -- config/locales/tr.yml | 2 -- config/locales/uk.yml | 2 -- config/locales/vi.yml | 2 -- config/locales/zh-CN.yml | 2 -- config/locales/zh-HK.yml | 2 -- config/locales/zh-TW.yml | 2 -- spec/mailers/admin_mailer_spec.rb | 13 +++++++++---- 64 files changed, 15 insertions(+), 138 deletions(-) diff --git a/app/views/admin_mailer/_new_trending_links.text.erb b/app/views/admin_mailer/_new_trending_links.text.erb index 85f3f8039..0e2a6a20a 100644 --- a/app/views/admin_mailer/_new_trending_links.text.erb +++ b/app/views/admin_mailer/_new_trending_links.text.erb @@ -1,6 +1,6 @@ <%= raw t('admin_mailer.new_trends.new_trending_links.title') %> -<% @links.each do |link| %> +<% new_trending_links.each do |link| %> - <%= link.title %> · <%= link.url %> <%= standard_locale_name(link.language) %> · <%= raw t('admin.trends.links.usage_comparison', today: link.history.get(Time.now.utc).accounts, yesterday: link.history.get(Time.now.utc - 1.day).accounts) %> · <%= t('admin.trends.tags.current_score', score: link.trend.score.round(2)) %> <% end %> diff --git a/app/views/admin_mailer/_new_trending_statuses.text.erb b/app/views/admin_mailer/_new_trending_statuses.text.erb index eedbfff9d..05bb9733f 100644 --- a/app/views/admin_mailer/_new_trending_statuses.text.erb +++ b/app/views/admin_mailer/_new_trending_statuses.text.erb @@ -1,6 +1,6 @@ <%= raw t('admin_mailer.new_trends.new_trending_statuses.title') %> -<% @statuses.each do |status| %> +<% new_trending_statuses.each do |status| %> - <%= ActivityPub::TagManager.instance.url_for(status) %> <%= standard_locale_name(status.language) %> · <%= raw t('admin.trends.tags.current_score', score: status.trend.score.round(2)) %> <% end %> diff --git a/app/views/admin_mailer/_new_trending_tags.text.erb b/app/views/admin_mailer/_new_trending_tags.text.erb index d528ab8eb..f738caaf3 100644 --- a/app/views/admin_mailer/_new_trending_tags.text.erb +++ b/app/views/admin_mailer/_new_trending_tags.text.erb @@ -1,14 +1,8 @@ <%= raw t('admin_mailer.new_trends.new_trending_tags.title') %> -<% @tags.each do |tag| %> +<% new_trending_tags.each do |tag| %> - #<%= tag.display_name %> <%= raw t('admin.trends.tags.usage_comparison', today: tag.history.get(Time.now.utc).accounts, yesterday: tag.history.get(Time.now.utc - 1.day).accounts) %> · <%= t('admin.trends.tags.current_score', score: Trends.tags.score(tag.id).round(2)) %> <% end %> -<% if @lowest_trending_tag %> -<%= raw t('admin_mailer.new_trends.new_trending_tags.requirements', lowest_tag_name: @lowest_trending_tag.display_name, lowest_tag_score: Trends.tags.score(@lowest_trending_tag.id).round(2), rank: Trends.tags.options[:review_threshold]) %> -<% else %> -<%= raw t('admin_mailer.new_trends.new_trending_tags.no_approved_tags') %> -<% end %> - <%= raw t('application_mailer.view')%> <%= admin_trends_tags_url(status: 'pending_review') %> diff --git a/app/views/admin_mailer/new_trends.text.erb b/app/views/admin_mailer/new_trends.text.erb index 13b296846..10b10e604 100644 --- a/app/views/admin_mailer/new_trends.text.erb +++ b/app/views/admin_mailer/new_trends.text.erb @@ -2,12 +2,6 @@ <%= raw t('admin_mailer.new_trends.body') %> -<% unless @links.empty? %> -<%= render 'new_trending_links' %> -<% end %> -<% unless @tags.empty? %> -<%= render 'new_trending_tags' unless @tags.empty? %> -<% end %> -<% unless @statuses.empty? %> -<%= render 'new_trending_statuses' unless @statuses.empty? %> -<% end %> +<%= render partial: 'new_trending_links', object: @links unless @links.empty? %> +<%= render partial: 'new_trending_tags', object: @tags unless @tags.empty? %> +<%= render partial: 'new_trending_statuses', object: @statuses unless @statuses.empty? %> diff --git a/config/locales/an.yml b/config/locales/an.yml index 7922ccf58..de791679b 100644 --- a/config/locales/an.yml +++ b/config/locales/an.yml @@ -900,8 +900,6 @@ an: new_trending_statuses: title: Publicacions en tendencia new_trending_tags: - no_approved_tags: Actualment no i hai garra etiqueta en tendencia aprebada. - requirements: 'Qualsequiera d''estes candidatos podría superar lo hashtag en tendencia aprebau per #%{rank}, que actualment ye #%{lowest_tag_name} con una puntuación de %{lowest_tag_score}.' title: Etiquetas en tendencia subject: Nuevas tendencias asperando estar revisadas en %{instance} aliases: diff --git a/config/locales/ar.yml b/config/locales/ar.yml index f43d1ad2a..c1b2677dc 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -1068,8 +1068,6 @@ ar: new_trending_statuses: title: المنشورات الشائعة new_trending_tags: - no_approved_tags: لا توجد حاليًا وسوم شائعة موافق عليها. - requirements: 'يمكن لأي من هؤلاء المرشحين أن يتجاوز علامة #%{rank} من الوسوم الموافق عليها، وهي حاليا #%{lowest_tag_name} مع نتيجة %{lowest_tag_score}.' title: الوسوم المتداولة subject: تداولات جديدة في انتظار المراجعة على %{instance} aliases: diff --git a/config/locales/be.yml b/config/locales/be.yml index fa43373f6..d8703b799 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -1033,8 +1033,6 @@ be: new_trending_statuses: title: Папулярныя допісы new_trending_tags: - no_approved_tags: Зараз няма зацверджаных папулярных хэштэгаў. - requirements: 'Кожны з гэтых кандыдатаў можа перавысіць #%{rank} зацверджаных папулярных хэштэгаў. Зараз гэта #%{lowest_tag_name} з лікам %{lowest_tag_score}.' title: Папулярныя хэштэгі subject: Новае ў папулярным для разгляду %{instance} aliases: diff --git a/config/locales/bg.yml b/config/locales/bg.yml index 4c2bf0fa3..b06c5404c 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -997,8 +997,6 @@ bg: new_trending_statuses: title: Налагащи се публикации new_trending_tags: - no_approved_tags: Сега няма одобрени налагащи се хаштагове. - requirements: 'Всеки от тези кандидати може да надмине #%{rank} одобрен актуален хаштаг, който в момента е #%{lowest_tag_name} с резултат %{lowest_tag_score}.' title: Налагащи се хаштагове subject: Нови нашумели, готови за преглед в %{instance} aliases: diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 03b3ff3c2..4dc3202a0 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -995,8 +995,6 @@ ca: new_trending_statuses: title: Tuts en tendència new_trending_tags: - no_approved_tags: Actualment no hi ha etiquetes en tendència aprovades. - requirements: 'Qualsevol d''aquests candidats podria superar el #%{rank} de la etiqueta en tendència aprovada, que actualment és "%{lowest_tag_name}" amb una puntuació de %{lowest_tag_score}.' title: Etiquetes en tendència subject: Noves tendències pendents de revisar a %{instance} aliases: diff --git a/config/locales/cs.yml b/config/locales/cs.yml index a04682a44..e3e804172 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -1029,8 +1029,6 @@ cs: new_trending_statuses: title: Populární příspěvky new_trending_tags: - no_approved_tags: Momentálně nejsou žádné schválené populární hashtagy. - requirements: 'Kterýkoliv z těchto kandidátů by mohl předehnat schválený populární hashtag #%{rank}, kterým je momentálně #%{lowest_tag_name} se skóre %{lowest_tag_score}.' title: Populární hashtagy subject: Nové trendy k posouzení na %{instance} aliases: diff --git a/config/locales/cy.yml b/config/locales/cy.yml index c9d5b8828..7f60e9342 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -1068,8 +1068,6 @@ cy: new_trending_statuses: title: Postiadau sy'n trendio new_trending_tags: - no_approved_tags: Ar hyn o bryd nid oes unrhyw hashnodau trendio cymeradwy. - requirements: 'Gallai unrhyw un o''r ymgeiswyr hyn ragori ar yr hashnod trendio cymeradwy #%{rank}, sef #%{lowest_tag_name} gyda sgôr o %{lowest_tag_score} ar hyn o bryd.' title: Hashnodau sy'n trendio subject: Trendiau newydd i'w hadolygu ar %{instance} aliases: diff --git a/config/locales/da.yml b/config/locales/da.yml index 7344d789f..6403ac1cc 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -997,8 +997,6 @@ da: new_trending_statuses: title: Populære opslag new_trending_tags: - no_approved_tags: Der er pt. ingen godkendte populære hashtags. - requirements: 'Enhver af disse kandidater vil kunne overgå #%{rank} godkendte populære hastag, der med en score på #%{lowest_tag_score} pt. er %{lowest_tag_name}.' title: Populære hashtags subject: Nye tendenser klar til revision på %{instance} aliases: diff --git a/config/locales/de.yml b/config/locales/de.yml index 0d9cf8c03..e084fdf70 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -997,8 +997,6 @@ de: new_trending_statuses: title: Angesagte Beiträge new_trending_tags: - no_approved_tags: Es gibt keine genehmigten Hashtags, die gerade im Trend liegen. - requirements: 'Jeder dieser Kandidaten könnte den #%{rank} genehmigten angesagten Hashtag übertreffen, der derzeit #%{lowest_tag_name} mit einer Punktzahl von %{lowest_tag_score} ist.' title: Angesagte Hashtags subject: Neue Trends zur Überprüfung auf %{instance} aliases: diff --git a/config/locales/el.yml b/config/locales/el.yml index c4c3d3939..4c58bfda0 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -938,8 +938,6 @@ el: new_trending_statuses: title: Αναρτήσεις σε τάση new_trending_tags: - no_approved_tags: Προς το παρόν δεν υπάρχουν εγκεκριμένες ετικέτεςσε τάση. - requirements: 'Οποιοσδήποτε από αυτούς τους υποψηφίους θα μπορούσε να ξεπεράσει την #%{rank} εγκεκριμένη ετικέτα σε τάση, που επί του παρόντος είναι #%{lowest_tag_name} με βαθμολογία %{lowest_tag_score}.' title: Ετικέτες σε τάση subject: Νέες τάσεις προς αξιολόγηση στο %{instance} aliases: diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 98a40c45c..987788a7a 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -995,8 +995,6 @@ en-GB: new_trending_statuses: title: Trending posts new_trending_tags: - no_approved_tags: There are currently no approved trending hashtags. - requirements: 'Any of these candidates could surpass the #%{rank} approved trending hashtag, which is currently #%{lowest_tag_name} with a score of %{lowest_tag_score}.' title: Trending hashtags subject: New trends up for review on %{instance} aliases: diff --git a/config/locales/en.yml b/config/locales/en.yml index 057f7a584..15d682d17 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -997,8 +997,6 @@ en: new_trending_statuses: title: Trending posts new_trending_tags: - no_approved_tags: There are currently no approved trending hashtags. - requirements: 'Any of these candidates could surpass the #%{rank} approved trending hashtag, which is currently #%{lowest_tag_name} with a score of %{lowest_tag_score}.' title: Trending hashtags subject: New trends up for review on %{instance} aliases: diff --git a/config/locales/eo.yml b/config/locales/eo.yml index 30c1e0d4e..9ae595394 100644 --- a/config/locales/eo.yml +++ b/config/locales/eo.yml @@ -952,8 +952,6 @@ eo: new_trending_statuses: title: Popularaĝaj mesaĝoj new_trending_tags: - no_approved_tags: Nun ne havas aprobitajn popularajn kradvortojn. - requirements: Ajn ĉi tiu eroj povas superi la %{rank}an kradvorton kiu estas %{lowest_tag_name} kun %{lowest_tag_score} puentoj. title: Tendencantaj kradvortoj subject: Novaj popularaĵoj bezonas kontrolitis ĉe %{instance} aliases: diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml index 88248d098..0000c297a 100644 --- a/config/locales/es-AR.yml +++ b/config/locales/es-AR.yml @@ -997,8 +997,6 @@ es-AR: new_trending_statuses: title: Mensajes en tendencia new_trending_tags: - no_approved_tags: Actualmente no hay etiquetas en tendencia aprobadas. - requirements: 'Cualquiera de estos candidatos podría superar la etiqueta en tendencia aprobada de #%{rank}, que actualmente es #%{lowest_tag_name} con una puntuación de %{lowest_tag_score}.' title: Etiquetas en tendencia subject: Nuevas tendencias para revisar en %{instance} aliases: diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index 4ecb666b0..424262ca1 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -997,8 +997,6 @@ es-MX: new_trending_statuses: title: Publicaciones en tendencia new_trending_tags: - no_approved_tags: Actualmente no hay ninguna etiqueta en tendencia aprobada. - requirements: 'Cualquiera de estos candidatos podría superar el hashtag en tendencia aprobado por #%{rank}, que actualmente es #%{lowest_tag_name} con una puntuación de %{lowest_tag_score}.' title: Etiquetas en tendencia subject: Nuevas tendencias esperando ser revisadas en %{instance} aliases: diff --git a/config/locales/es.yml b/config/locales/es.yml index 72a36250f..f4a70e5e5 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -997,8 +997,6 @@ es: new_trending_statuses: title: Publicaciones en tendencia new_trending_tags: - no_approved_tags: Actualmente no hay ninguna etiqueta en tendencia aprobada. - requirements: 'Cualquiera de estos candidatos podría superar el hashtag en tendencia aprobado por #%{rank}, que actualmente es #%{lowest_tag_name} con una puntuación de %{lowest_tag_score}.' title: Etiquetas en tendencia subject: Nuevas tendencias esperando ser revisadas en %{instance} aliases: diff --git a/config/locales/et.yml b/config/locales/et.yml index 4f5a83624..20f79bdd3 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -981,8 +981,6 @@ et: new_trending_statuses: title: Trendikad postitused new_trending_tags: - no_approved_tags: Hetkel ei ole ühtegi heaks kiidetud populaarset silti. - requirements: 'Need on siltide kandidaadid mille hulgast ükskõik milline võib järjekorras mööda jõuda #%{rank} kohal olevast heaks kiidetud sildist. See on hetkel #%{lowest_tag_name} mille seis on %{lowest_tag_score}.' title: Trendikad sildid subject: Uued %{instance} trendid ülevaatuseks aliases: diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 6aa92c2d1..e3062d9df 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -994,8 +994,6 @@ eu: new_trending_statuses: title: Bidalketen joerak new_trending_tags: - no_approved_tags: Ez dago onartutako traolen joerarik une honetan. - requirements: 'Hautagai hauek joeretan onartutako %{rank}. traola gainditu dezakete: une honetan #%{lowest_tag_name} da, %{lowest_tag_score} puntuazioarekin.' title: Traolak joeran subject: Joera berriak daude berrikusteko %{instance} instantzian aliases: diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 04fb52e75..f93aac603 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -848,7 +848,6 @@ fa: new_trending_statuses: title: فرستههای داغ new_trending_tags: - no_approved_tags: در حال حاضر هیچ برچسب پرطرفداری پذیرفته نشده است. title: برچسبهای داغ subject: موضوغ داغ تازهای در %{instance} نیازمند بررسی است aliases: diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 73442396f..d48653edc 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -997,8 +997,6 @@ fi: new_trending_statuses: title: Suositut julkaisut new_trending_tags: - no_approved_tags: Tällä hetkellä ei ole hyväksyttyjä suosittuja aihetunnisteita. - requirements: 'Mikä tahansa näistä ehdokkaista voisi ylittää #%{rank} hyväksytyn suositun aihetunnisteen, joka on tällä hetkellä #%{lowest_tag_name} %{lowest_tag_score} pisteellä.' title: Suositut aihetunnisteet subject: Uusia trendejä tarkistettavaksi instanssissa %{instance} aliases: diff --git a/config/locales/fo.yml b/config/locales/fo.yml index ffa54f588..726c9607e 100644 --- a/config/locales/fo.yml +++ b/config/locales/fo.yml @@ -996,8 +996,6 @@ fo: new_trending_statuses: title: Vælumtóktir postar new_trending_tags: - no_approved_tags: Í løtuni eru eingi góðkend vælumtókt frámerki. - requirements: 'Einhvør av hesum kandidatum kunnu fara framum #%{rank} góðkenda vælumtókta frámerki, sum í løtuni er #%{lowest_tag_name} við stigatali %{lowest_tag_score}.' title: Vælumtókt frámerki subject: Nýggj rák til gjøgnumgongd á %{instance} aliases: diff --git a/config/locales/fr-QC.yml b/config/locales/fr-QC.yml index f7425ea32..3aba8713f 100644 --- a/config/locales/fr-QC.yml +++ b/config/locales/fr-QC.yml @@ -996,8 +996,6 @@ fr-QC: new_trending_statuses: title: Messages tendance new_trending_tags: - no_approved_tags: Il n'y a pas de hashtag tendance approuvé actuellement. - requirements: 'N''importe quel élément de la sélection pourrait surpasser le hashtag tendance approuvé n°%{rank}, qui est actuellement #%{lowest_tag_name} avec un résultat de %{lowest_tag_score}.' title: Hashtags tendance subject: Nouvelles tendances à examiner sur %{instance} aliases: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 289afb226..a69a5b535 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -996,8 +996,6 @@ fr: new_trending_statuses: title: Messages tendance new_trending_tags: - no_approved_tags: Il n'y a pas de hashtag tendance approuvé actuellement. - requirements: 'N''importe quel élément de la sélection pourrait surpasser le hashtag tendance approuvé n°%{rank}, qui est actuellement #%{lowest_tag_name} avec un résultat de %{lowest_tag_score}.' title: Hashtags tendance subject: Nouvelles tendances à examiner sur %{instance} aliases: diff --git a/config/locales/fy.yml b/config/locales/fy.yml index de609a14d..6a7cb3551 100644 --- a/config/locales/fy.yml +++ b/config/locales/fy.yml @@ -996,8 +996,6 @@ fy: new_trending_statuses: title: Trending berjochten new_trending_tags: - no_approved_tags: Op dit stuit binne der gjin goedkarre hashtags. - requirements: 'Elk fan dizze kandidaten kin de #%{rank} goedkarre trending hashtag oertreffe, dy’t op dit stuit #%{lowest_tag_name} is mei in skoare fan %{lowest_tag_score}.' title: Trending hashtags subject: Nije trends te beoardielen op %{instance} aliases: diff --git a/config/locales/gd.yml b/config/locales/gd.yml index b2ccdd4d9..965447d4f 100644 --- a/config/locales/gd.yml +++ b/config/locales/gd.yml @@ -1032,8 +1032,6 @@ gd: new_trending_statuses: title: Postaichean a’ treandadh new_trending_tags: - no_approved_tags: Chan eil taga hais a’ treandadh le aontachadh ann. - requirements: "’S urrainn do ghin dhe na tagraichean seo dol thairis air #%{rank} a tha aig an taga hais #%{lowest_tag_name} a’ treandadh as ìsle le aontachadh agus sgòr de %{lowest_tag_score} air." title: Tagaichean hais a’ treandadh subject: Tha treandaichean ùra a’ feitheamh air lèirmheas air %{instance} aliases: diff --git a/config/locales/gl.yml b/config/locales/gl.yml index c1e4b78a2..c0e76842f 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -997,8 +997,6 @@ gl: new_trending_statuses: title: Publicacións en voga new_trending_tags: - no_approved_tags: Non hai etiquetas en voga aprobadas. - requirements: 'Calquera destos candidatos podería superar o #%{rank} dos cancelos en voga aprobados, que actualmente é #%{lowest_tag_name} cunha puntuación de %{lowest_tag_score}.' title: Cancelos en voga subject: Novas tendencias para revisar en %{instance} aliases: diff --git a/config/locales/he.yml b/config/locales/he.yml index 1e04af93b..f2cc88214 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -1033,8 +1033,6 @@ he: new_trending_statuses: title: הודעות חמות new_trending_tags: - no_approved_tags: אין כרגע שום תגיות חמות מאושרות. - requirements: כל אחת מהמועמדות האלו עשויה לעבור את התגית החמה המאושרת מדרגה %{rank}, שהיא כרגע %{lowest_tag_name} עם ציון של %{lowest_tag_score}. title: תגיות חמות subject: נושאים חמים חדשים מוכנים לסקירה ב-%{instance} aliases: diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 60016c935..7057883e1 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -997,8 +997,6 @@ hu: new_trending_statuses: title: Felkapott bejegyzések new_trending_tags: - no_approved_tags: Jelenleg nincsenek jóváhagyott felkapott hashtagek. - requirements: 'Ezek közül bármelyik jelölt lehagyná a %{rank}. jóváhagyott felkapott hashtaget, amely jelenleg a(z) #%{lowest_tag_name} ezzel a pontszámmal: %{lowest_tag_score}.' title: Felkapott hashtagek subject: 'Új jóváhagyandó trendek ezen: %{instance}' aliases: diff --git a/config/locales/id.yml b/config/locales/id.yml index 0e8f2b9b0..c231fea57 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -878,8 +878,6 @@ id: new_trending_statuses: title: Kiriman yang sedang tren new_trending_tags: - no_approved_tags: Saat ini tidak ada tagar tren yang disetujui. - requirements: 'Kandidat yang ada di sini bisa saja melewati peringkat #%{rank} tagar sedang tren yang disetujui, yang kini #%{lowest_tag_name} memiliki nilai %{lowest_tag_score}.' title: Tagar sedang tren subject: Tren baru yang perlu ditinjau di %{instance} aliases: diff --git a/config/locales/io.yml b/config/locales/io.yml index d09dfed70..c9a0dcd73 100644 --- a/config/locales/io.yml +++ b/config/locales/io.yml @@ -857,8 +857,6 @@ io: new_trending_statuses: title: Tendencoza posti new_trending_tags: - no_approved_tags: Nun ne existas aprobita tendencoza hashtagi. - requirements: 'Irga ca probanti povas ecesar la #%{rank} aprobita tendencoligilo, quale nun esas %{lowest_tag_name} kun punto %{lowest_tag_score}.' title: Tendencoza hashtagi subject: Nova tendenci bezonas kontrolesar che %{instance} aliases: diff --git a/config/locales/is.yml b/config/locales/is.yml index a4706ee51..bf16d877d 100644 --- a/config/locales/is.yml +++ b/config/locales/is.yml @@ -999,8 +999,6 @@ is: new_trending_statuses: title: Vinsælar færslur new_trending_tags: - no_approved_tags: Það eru í augnablikinu engin samþykkt vinsæl myllumerki. - requirements: 'Hver af þessum tillögum gætu farið yfir samþykkta vinsæla myllumerkið númer #%{rank}, sem í augnablikinu er %{lowest_tag_name} með %{lowest_tag_score} stig' title: Vinsæl myllumerki subject: Nýtt vinsælt til yfirferðar á %{instance} aliases: diff --git a/config/locales/it.yml b/config/locales/it.yml index 82bbf7251..3637313c0 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -997,8 +997,6 @@ it: new_trending_statuses: title: Post di tendenza new_trending_tags: - no_approved_tags: Attualmente non ci sono hashtag di tendenza approvati. - requirements: 'Ognuno di questi candidati potrebbe superare il #%{rank} hashtag di tendenza approvato, che è attualmente "%{lowest_tag_name}" con un punteggio di %{lowest_tag_score}.' title: Hashtag di tendenza subject: Nuove tendenze in attesa di controllo su %{instance} aliases: diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 7be072463..f7a2c2817 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -979,8 +979,6 @@ ja: new_trending_statuses: title: トレンド投稿 new_trending_tags: - no_approved_tags: 承認されたトレンドハッシュタグはありません。 - requirements: 'これらの候補はいずれも %{rank} 位の承認済みトレンドハッシュタグのスコアを上回ります。現在 #%{lowest_tag_name} のスコアは %{lowest_tag_score} です。' title: トレンドハッシュタグ subject: "%{instance}で新しいトレンドが審査待ちです" aliases: diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 767c54ed1..a30540fac 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -981,8 +981,6 @@ ko: new_trending_statuses: title: 유행하는 게시물 new_trending_tags: - no_approved_tags: 현재 승인된 유행 중인 해시태그가 없습니다. - requirements: '이 후보들 중 어떤 것이라도 #%{rank}위의 승인된 유행 중인 해시태그를 앞지를 수 있으며, 이것은 현재 #%{lowest_tag_name}이고 %{lowest_tag_score}점을 기록하고 있습니다.' title: 유행하는 해시태그 subject: 새 트렌드가 %{instance}에서 심사 대기 중입니다 aliases: diff --git a/config/locales/ku.yml b/config/locales/ku.yml index 58c1885df..b9cc5fe77 100644 --- a/config/locales/ku.yml +++ b/config/locales/ku.yml @@ -897,8 +897,6 @@ ku: new_trending_statuses: title: Şandiyên rojevê new_trending_tags: - no_approved_tags: Niha hashtagên rojevê pejirandî tune ne. - requirements: 'Yek ji namzedên li jêr dikare ji #%{rank} hashtagaa diyarkirî ya pejirandî derbas bibe, niha ku #%{lowest_tag_name} bi %{lowest_tag_score} puan e.' title: Hashtagên rojevê subject: Rojevên nû ji bo nirxandinê li ser %{instance} derdikevin aliases: diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 4bcf23de4..c532b84e2 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -1014,8 +1014,6 @@ lv: new_trending_statuses: title: Populārākās ziņas new_trending_tags: - no_approved_tags: Pašlaik nav apstiprinātu tendenču tēmturu. - requirements: 'Jebkurš no šiem kandidātiem varētu pārspēt #%{rank} apstiprināto populāro tēmturi, kas pašlaik ir #%{lowest_tag_name} ar rezultātu %{lowest_tag_score}.' title: Populārākie tēmturi subject: Tiek pārskatītas jaunas tendences %{instance} aliases: diff --git a/config/locales/ms.yml b/config/locales/ms.yml index 951b04194..74acf8755 100644 --- a/config/locales/ms.yml +++ b/config/locales/ms.yml @@ -977,8 +977,6 @@ ms: new_trending_statuses: title: Pos sohor kini new_trending_tags: - no_approved_tags: Pada masa ini tiada hashtag sohor kini yang diluluskan. - requirements: 'Mana-mana calon ini boleh melepasi hashtag arah aliran #%{rank} yang diluluskan, yang pada masa ini ialah #%{lowest_tag_name} dengan markah %{lowest_tag_score}.' title: Hashtag sohor kini subject: Trend baharu untuk kesemakan pada %{instance} aliases: diff --git a/config/locales/my.yml b/config/locales/my.yml index d8e83543c..03ed771a4 100644 --- a/config/locales/my.yml +++ b/config/locales/my.yml @@ -962,8 +962,6 @@ my: new_trending_statuses: title: လက်ရှိခေတ်စားနေသော ပို့စ်များ new_trending_tags: - no_approved_tags: လက်ရှိတွင် အတည်ပြုထားသော ခေတ်စားနေသည့် hashtag များမရှိပါ။ - requirements: 'ဤလူများမှာ %{lowest_tag_score} ရမှတ်ဖြင့် လက်ရှိ #%{lowest_tag_name} ဖြစ်သည့် ခေတ်စားနေသော hashtag #%{rank} ကို ကျော်သွားနိုင်သည်။' title: လက်ရှိခေတ်စားနေသော hashtag များ subject: "%{instance} တွင် ပြန်လည်သုံးသပ်ရမည့် ခေတ်စားနေသောပို့စ်အသစ်များ" aliases: diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 4147078d3..6ad414b3e 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -997,8 +997,6 @@ nl: new_trending_statuses: title: Trending berichten new_trending_tags: - no_approved_tags: Op dit moment zijn er geen goedgekeurde hashtags. - requirements: 'Elk van deze kandidaten kan de #%{rank} goedgekeurde trending hashtag overtreffen, die momenteel #%{lowest_tag_name} is met een score van %{lowest_tag_score}.' title: Trending hashtags subject: Nieuwe trends te beoordelen op %{instance} aliases: diff --git a/config/locales/nn.yml b/config/locales/nn.yml index ad2acdda8..3ee02863d 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -997,8 +997,6 @@ nn: new_trending_statuses: title: Populære innlegg new_trending_tags: - no_approved_tags: Det er ingen godkjende populære emneknaggar no. - requirements: 'Alle desse kandidatane kan stiga høgare enn den godkjende populære emneknaggen #%{rank}, som er #%{lowest_tag_name} med ei plassering på %{lowest_tag_score}.' title: Populære emneknaggar subject: Nye trendar å sjå gjennom på %{instance} aliases: diff --git a/config/locales/no.yml b/config/locales/no.yml index 42bd6193c..f791c7151 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -997,8 +997,6 @@ new_trending_statuses: title: Populære innlegg new_trending_tags: - no_approved_tags: Det er for øyeblikket ingen godkjente populære emneknagger. - requirements: 'Enhver av disse kandidatene kan overgå #%{rank} godkjent populære emneknagger, som for øyeblikket er #%{lowest_tag_name} med en poengsum på %{lowest_tag_score}.' title: Populære emneknagger subject: Ny trender for gjennomsyn av %{instance} aliases: diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 4ff81e11e..79de3b519 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -1033,8 +1033,6 @@ pl: new_trending_statuses: title: Popularne teraz new_trending_tags: - no_approved_tags: Obecnie nie ma żadnych zatwierdzonych popularnych hasztagów. - requirements: 'Każdy z tych kandydatów może przekroczyć #%{rank} zatwierdzonych popularnych teraz hasztagów, który wynosi obecnie %{lowest_tag_name} z wynikiem %{lowest_tag_score}.' title: Popularne hasztagi subject: Nowe popularne do przeglądu na %{instance} aliases: diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index e42481120..c8060ad80 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -997,8 +997,6 @@ pt-BR: new_trending_statuses: title: Publicações em alta new_trending_tags: - no_approved_tags: No momento, não há hashtags de tendências aprovadas. - requirements: 'Qualquer um desses candidatos poderia ultrapassar a hashtag de tendência aprovada #%{rank} , que é atualmente #%{lowest_tag_name} com uma pontuação de %{lowest_tag_score}.' title: Hashtags em alta subject: Novas tendências para revisão em %{instance} aliases: diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index 8e147ce4c..89da6b480 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -997,8 +997,6 @@ pt-PT: new_trending_statuses: title: Publicações em alta new_trending_tags: - no_approved_tags: 'Neste momento, não existem #etiquetas aprovadas para destaque.' - requirements: 'Qualquer um destes candidatos pode ultrapassar a #%{rank} etiqueta aprovada em destaque, que é atualmente #%{lowest_tag_name} com uma pontuação de %{lowest_tag_score}.' title: Etiquetas em alta subject: Novas tendências para revisão em %{instance} aliases: diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 7bfccb9a0..c380776b5 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -1032,8 +1032,6 @@ ru: new_trending_statuses: title: Популярные посты new_trending_tags: - no_approved_tags: На данный момент популярные подтвержденные хэштеги отсутствуют. - requirements: 'Каждый из этих кандидатов может превысить #%{rank} одобренных популярных хештегов. Сейчас это #%{lowest_tag_name} с числом %{lowest_tag_score}.' title: Популярные хэштеги subject: Новые тренды для проверки на %{instance} aliases: diff --git a/config/locales/sco.yml b/config/locales/sco.yml index 2199c5dbf..f77c4c797 100644 --- a/config/locales/sco.yml +++ b/config/locales/sco.yml @@ -890,8 +890,6 @@ sco: new_trending_statuses: title: Trendin posts new_trending_tags: - no_approved_tags: There nae approved trendin hashtags the noo. - requirements: 'Onie o thir candidates cuid surpass the #%{rank} approved trendin hashtag, thit''s #%{lowest_tag_name} the noo, wi a score o %{lowest_tag_score}.' title: Trendin hashtags subject: New trends up fir luikin ower on %{instance} aliases: diff --git a/config/locales/si.yml b/config/locales/si.yml index 2c2a8ae82..70aefafc1 100644 --- a/config/locales/si.yml +++ b/config/locales/si.yml @@ -768,8 +768,6 @@ si: new_trending_statuses: title: නැගී එන ලිපි new_trending_tags: - no_approved_tags: දැනට අනුමත ප්රවණතා හැෂ් ටැග් නොමැත. - requirements: 'මෙම ඕනෑම අපේක්ෂකයෙකුට #%{rank} අනුමත ප්රවණතා හැෂ් ටැගය අභිබවා යා හැකිය, එය දැනට ලකුණු %{lowest_tag_score}ක් සමඟ #%{lowest_tag_name} වේ.' title: ප්රවණතා හැෂ් ටැග් subject: "%{instance}හි සමාලෝචනය සඳහා නව ප්රවණතා" aliases: diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 65d09cf1b..ecff5a667 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -1033,8 +1033,6 @@ sl: new_trending_statuses: title: Trendne objave new_trending_tags: - no_approved_tags: Trenutno ni odobrenih ključnikov v trendu. - requirements: Vsak od teh kandidatov bi lahko presegel odobreni ključnik v trendu št. %{rank}, ki je trenutno %{lowest_tag_name} z rezultatom %{lowest_tag_score}. title: Ključniki v trendu subject: Novi trendi za pregled na %{instance} aliases: diff --git a/config/locales/sq.yml b/config/locales/sq.yml index b6a7736df..af1bb4644 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -993,7 +993,6 @@ sq: new_trending_statuses: title: Postime në modë new_trending_tags: - no_approved_tags: Aktualisht s’ka hashtag-ë në modë të miratuar. title: Hashtag-ë në modë subject: Gjëra të reja në modë për shqyrtim te %{instance} aliases: diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index 426440a1a..e8760697e 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -1015,8 +1015,6 @@ sr-Latn: new_trending_statuses: title: Objave u trendu new_trending_tags: - no_approved_tags: Trenutno nema odobrenih heš oznaka u trendu. - requirements: 'Bilo koji od sledećih kandidata bi mogao prevazići #%{rank} odobrenu heš oznaku u trendu, koja je trenutno #%{lowest_tag_name} sa vrednošću %{lowest_tag_score}.' title: Heš oznake u trendu subject: Novi trendovi za pregled na %{instance} aliases: diff --git a/config/locales/sr.yml b/config/locales/sr.yml index b271b15f1..b32d86f65 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -1015,8 +1015,6 @@ sr: new_trending_statuses: title: Објаве у тренду new_trending_tags: - no_approved_tags: Тренутно нема одобрених хеш ознака у тренду. - requirements: 'Било који од следећих кандидата би могао превазићи #%{rank} одобрену хеш ознаку у тренду, која је тренутно #%{lowest_tag_name} са вредношћу %{lowest_tag_score}.' title: Хеш ознаке у тренду subject: Нови трендови за преглед на %{instance} aliases: diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 8126455f4..f7a6f33a0 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -996,8 +996,6 @@ sv: new_trending_statuses: title: Trendande inlägg new_trending_tags: - no_approved_tags: Det finns för närvarande inga godkända trendande hashtaggar. - requirements: 'Någon av dessa kandidater skulle kunna överträffa #%{rank} godkända trendande hashtaggar, som för närvarande är #%{lowest_tag_name} med en poäng på %{lowest_tag_score}.' title: Trendande hashtaggar subject: Nya trender tillgängliga för granskning på %{instance} aliases: diff --git a/config/locales/th.yml b/config/locales/th.yml index a8f047cc7..59a6b2c4f 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -979,8 +979,6 @@ th: new_trending_statuses: title: โพสต์ที่กำลังนิยม new_trending_tags: - no_approved_tags: ไม่มีแฮชแท็กที่กำลังนิยมที่ได้รับอนุมัติในปัจจุบัน - requirements: 'ตัวเลือกใดก็ตามนี้สามารถแซงหน้าแฮชแท็กที่กำลังนิยมที่ได้รับอนุมัติ #%{rank} ซึ่งคือ #%{lowest_tag_name} ในปัจจุบันด้วยคะแนน %{lowest_tag_score}' title: แฮชแท็กที่กำลังนิยม subject: แนวโน้มใหม่สำหรับตรวจทานใน %{instance} aliases: diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 5882eae31..098719eb7 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -997,8 +997,6 @@ tr: new_trending_statuses: title: Öne çıkan gönderiler new_trending_tags: - no_approved_tags: Şu anda onaylanmış öne çıkan etiket yok. - requirements: 'Aşağıdaki adaylardan herhangi biri, şu anda %{lowest_tag_score} skoruna sahip "%{lowest_tag_name}" olan #%{rank} onaylanmış öne çıkan etiketi geçebilir.' title: Öne çıkan etiketler subject: "%{instance}, inceleme bekleyen yeni öne çıkan öğelere sahip" aliases: diff --git a/config/locales/uk.yml b/config/locales/uk.yml index e9eee14a1..139b8be30 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -1033,8 +1033,6 @@ uk: new_trending_statuses: title: Популярні дописи new_trending_tags: - no_approved_tags: На цей час немає схвалених популярних хештегів. - requirements: 'Кожен з цих кандидатів може перевершити #%{rank} затвердженого популярного хештеґу, який зараз на #%{lowest_tag_name} з рейтингом %{lowest_tag_score}.' title: Популярні хештеги subject: Нове популярне до розгляду на %{instance} aliases: diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 0cd9e0e17..c06a84b97 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -979,8 +979,6 @@ vi: new_trending_statuses: title: Tút nổi bật new_trending_tags: - no_approved_tags: Hiện tại không có hashtag nổi bật nào được duyệt. - requirements: 'Bất kỳ ứng cử viên nào vượt qua #%{rank} duyệt hashtag nổi bật, với hiện tại là "%{lowest_tag_name}" với điểm số %{lowest_tag_score}.' title: Hashtag nổi bật subject: Nội dung nổi bật chờ duyệt trên %{instance} aliases: diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index b788b53e1..ec4d71423 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -979,8 +979,6 @@ zh-CN: new_trending_statuses: title: 热门嘟文 new_trending_tags: - no_approved_tags: 目前没有经批准的热门标签。 - requirements: '这些候选人都可能会超过#%{rank} 批准的热门标签,目前是 #%{lowest_tag_name} ,分数为 %{lowest_tag_score}。' title: 热门标签 subject: "%{instance} 上有新热门等待审核" aliases: diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml index 5dd0d2e61..01a0a026a 100644 --- a/config/locales/zh-HK.yml +++ b/config/locales/zh-HK.yml @@ -979,8 +979,6 @@ zh-HK: new_trending_statuses: title: 熱門帖文 new_trending_tags: - no_approved_tags: 目前沒有經核准的熱門標籤。 - requirements: '任何一個候選都可能超過 #%{rank} 被核准的標籤。目前是 %{lowest_tag_name} 標籤,得分為 %{lowest_tag_score}。' title: 熱門標籤 subject: "%{instance} 上有待審核的新熱門" aliases: diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 2f65855fc..b8cbf6e80 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -981,8 +981,6 @@ zh-TW: new_trending_statuses: title: 熱門嘟文 new_trending_tags: - no_approved_tags: 這些是目前仍未被審核之熱門主題標籤。 - requirements: '這些候選中的任何一個都可能超過 #%{rank} 已批准的熱門主題標籤,該主題標籤目前是 #%{lowest_tag_name},得分為 %{lowest_tag_score}。' title: 熱門主題標籤 subject: "%{instance} 有待審核之新熱門" aliases: diff --git a/spec/mailers/admin_mailer_spec.rb b/spec/mailers/admin_mailer_spec.rb index 9f0d89996..88ad7aa02 100644 --- a/spec/mailers/admin_mailer_spec.rb +++ b/spec/mailers/admin_mailer_spec.rb @@ -63,12 +63,14 @@ RSpec.describe AdminMailer do describe '.new_trends' do let(:recipient) { Fabricate(:account, username: 'Snurf') } - let(:links) { [] } - let(:statuses) { [] } - let(:tags) { [] } - let(:mail) { described_class.with(recipient: recipient).new_trends(links, tags, statuses) } + let(:link) { Fabricate(:preview_card, trendable: true, language: 'en') } + let(:status) { Fabricate(:status) } + let(:tag) { Fabricate(:tag) } + let(:mail) { described_class.with(recipient: recipient).new_trends([link], [tag], [status]) } before do + PreviewCardTrend.create!(preview_card: link) + StatusTrend.create!(status: status, account: Fabricate(:account)) recipient.user.update(locale: :en) end @@ -79,6 +81,9 @@ RSpec.describe AdminMailer do .and(deliver_from('notifications@localhost')) .and(have_subject('New trends up for review on cb6e6126.ngrok.io')) .and(have_body_text('The following items need a review before they can be displayed publicly')) + .and(have_body_text(ActivityPub::TagManager.instance.url_for(status))) + .and(have_body_text(link.title)) + .and(have_body_text(tag.display_name)) end end From b2e8af88894bc3e8151198c7846c1f5b5ca9e475 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 21 Nov 2023 06:00:22 -0500 Subject: [PATCH 092/255] Add coverage for `settings/verifications` controller (#28001) --- .../settings/verifications_controller_spec.rb | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 spec/controllers/settings/verifications_controller_spec.rb diff --git a/spec/controllers/settings/verifications_controller_spec.rb b/spec/controllers/settings/verifications_controller_spec.rb new file mode 100644 index 000000000..1a8df485b --- /dev/null +++ b/spec/controllers/settings/verifications_controller_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Settings::VerificationsController do + render_views + + let!(:user) { Fabricate(:user) } + + before do + sign_in user, scope: :user + end + + describe 'GET #show' do + before do + get :show + end + + it 'returns http success with private cache control headers', :aggregate_failures do + expect(response) + .to have_http_status(200) + .and have_attributes( + headers: include( + 'Cache-Control' => 'private, no-store' + ) + ) + end + end +end From c836e712188cb178fcb64b0fac48c915b54b6c46 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:05:41 +0000 Subject: [PATCH 093/255] Update dependency aws-sdk-s3 to v1.137.0 (#27961) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 56b44f093..b992188d1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -131,20 +131,20 @@ GEM attr_required (1.0.1) awrence (1.2.1) aws-eventstream (1.2.0) - aws-partitions (1.828.0) - aws-sdk-core (3.183.1) + aws-partitions (1.853.0) + aws-sdk-core (3.187.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.71.0) - aws-sdk-core (~> 3, >= 3.177.0) + aws-sdk-kms (1.72.0) + aws-sdk-core (~> 3, >= 3.184.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.136.0) + aws-sdk-s3 (1.137.0) aws-sdk-core (~> 3, >= 3.181.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.6) - aws-sigv4 (1.6.0) + aws-sigv4 (1.6.1) aws-eventstream (~> 1, >= 1.0.2) azure-storage-blob (2.0.3) azure-storage-common (~> 2.0) From 32319187ee076146ca1153632f78e7ccfedb003e Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Tue, 21 Nov 2023 12:16:16 +0100 Subject: [PATCH 094/255] Fix error when muting users from Web UI (#28016) --- app/javascript/mastodon/reducers/notifications.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/reducers/notifications.js b/app/javascript/mastodon/reducers/notifications.js index 4a7a822a3..2ca301b19 100644 --- a/app/javascript/mastodon/reducers/notifications.js +++ b/app/javascript/mastodon/reducers/notifications.js @@ -281,7 +281,7 @@ export default function notifications(state = initialState, action) { case blockAccountSuccess.type: return filterNotifications(state, [action.payload.relationship.id]); case muteAccountSuccess.type: - return action.relationship.muting_notifications ? filterNotifications(state, [action.payload.relationship.id]) : state; + return action.payload.relationship.muting_notifications ? filterNotifications(state, [action.payload.relationship.id]) : state; case blockDomainSuccess.type: return filterNotifications(state, action.payload.accounts); case authorizeFollowRequestSuccess.type: From f7cb64a184f641d063ae973c64e30b72f1b92c45 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 21 Nov 2023 08:02:37 -0500 Subject: [PATCH 095/255] Add coverage for `settings/privacy` controller (#28000) --- .../settings/privacy_controller_spec.rb | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 spec/controllers/settings/privacy_controller_spec.rb diff --git a/spec/controllers/settings/privacy_controller_spec.rb b/spec/controllers/settings/privacy_controller_spec.rb new file mode 100644 index 000000000..59fd34219 --- /dev/null +++ b/spec/controllers/settings/privacy_controller_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Settings::PrivacyController do + render_views + + let!(:user) { Fabricate(:user) } + let(:account) { user.account } + + before do + sign_in user, scope: :user + end + + describe 'GET #show' do + before do + get :show + end + + it 'returns http success with private cache control headers', :aggregate_failures do + expect(response) + .to have_http_status(200) + .and have_attributes( + headers: include( + 'Cache-Control' => 'private, no-store' + ) + ) + end + end + + describe 'PUT #update' do + context 'when update succeeds' do + before do + allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async) + end + + it 'updates the user profile' do + put :update, params: { account: { discoverable: '1', settings: { indexable: '1' } } } + + expect(account.reload.discoverable) + .to be(true) + + expect(response) + .to redirect_to(settings_privacy_path) + + expect(ActivityPub::UpdateDistributionWorker) + .to have_received(:perform_async).with(account.id) + end + end + + context 'when update fails' do + before do + allow(UpdateAccountService).to receive(:new).and_return(failing_update_service) + allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async) + end + + it 'updates the user profile' do + put :update, params: { account: { discoverable: '1', settings: { indexable: '1' } } } + + expect(response) + .to render_template(:show) + + expect(ActivityPub::UpdateDistributionWorker) + .to_not have_received(:perform_async) + end + + private + + def failing_update_service + instance_double(UpdateAccountService, call: false) + end + end + end +end From 32e19e3af65d9e3f539210aea3fd802a00724701 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 21 Nov 2023 08:05:59 -0500 Subject: [PATCH 096/255] Reduce `.times` usage in request and controller specs (#27949) --- spec/controllers/admin/invites_controller_spec.rb | 2 +- spec/requests/api/v1/admin/domain_allows_spec.rb | 4 ++-- spec/requests/api/v1/bookmarks_spec.rb | 4 ++-- spec/requests/api/v1/favourites_spec.rb | 4 ++-- spec/requests/api/v1/featured_tags_spec.rb | 4 ++-- spec/requests/api/v1/follow_requests_spec.rb | 4 ++-- spec/requests/api/v1/followed_tags_spec.rb | 6 +++--- spec/requests/api/v1/lists/accounts_spec.rb | 2 +- spec/requests/api/v1/mutes_spec.rb | 12 ++++++------ spec/requests/api/v1/notifications_spec.rb | 2 +- spec/requests/api/v1/statuses_spec.rb | 2 +- spec/requests/api/v2/filters_spec.rb | 2 +- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/spec/controllers/admin/invites_controller_spec.rb b/spec/controllers/admin/invites_controller_spec.rb index ca8741730..c8f566f68 100644 --- a/spec/controllers/admin/invites_controller_spec.rb +++ b/spec/controllers/admin/invites_controller_spec.rb @@ -45,7 +45,7 @@ describe Admin::InvitesController do describe 'POST #deactivate_all' do it 'expires all invites, then redirects to admin_invites_path' do - invites = Fabricate.times(2, :invite, expires_at: nil) + invites = Fabricate.times(1, :invite, expires_at: nil) post :deactivate_all diff --git a/spec/requests/api/v1/admin/domain_allows_spec.rb b/spec/requests/api/v1/admin/domain_allows_spec.rb index 6db1ab6e3..662a8f9a8 100644 --- a/spec/requests/api/v1/admin/domain_allows_spec.rb +++ b/spec/requests/api/v1/admin/domain_allows_spec.rb @@ -35,7 +35,7 @@ RSpec.describe 'Domain Allows' do end context 'when there are allowed domains' do - let!(:domain_allows) { Fabricate.times(5, :domain_allow) } + let!(:domain_allows) { Fabricate.times(2, :domain_allow) } let(:expected_response) do domain_allows.map do |domain_allow| { @@ -53,7 +53,7 @@ RSpec.describe 'Domain Allows' do end context 'with limit param' do - let(:params) { { limit: 2 } } + let(:params) { { limit: 1 } } it 'returns only the requested number of allowed domains' do subject diff --git a/spec/requests/api/v1/bookmarks_spec.rb b/spec/requests/api/v1/bookmarks_spec.rb index 1f1cd35ca..18f4fddc2 100644 --- a/spec/requests/api/v1/bookmarks_spec.rb +++ b/spec/requests/api/v1/bookmarks_spec.rb @@ -14,7 +14,7 @@ RSpec.describe 'Bookmarks' do end let(:params) { {} } - let!(:bookmarks) { Fabricate.times(3, :bookmark, account: user.account) } + let!(:bookmarks) { Fabricate.times(2, :bookmark, account: user.account) } let(:expected_response) do bookmarks.map do |bookmark| @@ -37,7 +37,7 @@ RSpec.describe 'Bookmarks' do end context 'with limit param' do - let(:params) { { limit: 2 } } + let(:params) { { limit: 1 } } it 'paginates correctly', :aggregate_failures do subject diff --git a/spec/requests/api/v1/favourites_spec.rb b/spec/requests/api/v1/favourites_spec.rb index 713990592..2d8a42e71 100644 --- a/spec/requests/api/v1/favourites_spec.rb +++ b/spec/requests/api/v1/favourites_spec.rb @@ -14,7 +14,7 @@ RSpec.describe 'Favourites' do end let(:params) { {} } - let!(:favourites) { Fabricate.times(3, :favourite, account: user.account) } + let!(:favourites) { Fabricate.times(2, :favourite, account: user.account) } let(:expected_response) do favourites.map do |favourite| @@ -37,7 +37,7 @@ RSpec.describe 'Favourites' do end context 'with limit param' do - let(:params) { { limit: 2 } } + let(:params) { { limit: 1 } } it 'returns only the requested number of favourites' do subject diff --git a/spec/requests/api/v1/featured_tags_spec.rb b/spec/requests/api/v1/featured_tags_spec.rb index 6c171f6e4..c4aa2c0a2 100644 --- a/spec/requests/api/v1/featured_tags_spec.rb +++ b/spec/requests/api/v1/featured_tags_spec.rb @@ -32,7 +32,7 @@ RSpec.describe 'FeaturedTags' do end context 'when the requesting user has no featured tag' do - before { Fabricate.times(3, :featured_tag) } + before { Fabricate(:featured_tag) } it 'returns an empty body' do get '/api/v1/featured_tags', headers: headers @@ -44,7 +44,7 @@ RSpec.describe 'FeaturedTags' do end context 'when the requesting user has featured tags' do - let!(:user_featured_tags) { Fabricate.times(5, :featured_tag, account: user.account) } + let!(:user_featured_tags) { Fabricate.times(1, :featured_tag, account: user.account) } it 'returns only the featured tags belonging to the requesting user' do get '/api/v1/featured_tags', headers: headers diff --git a/spec/requests/api/v1/follow_requests_spec.rb b/spec/requests/api/v1/follow_requests_spec.rb index 1d78c9be1..a8898ccb3 100644 --- a/spec/requests/api/v1/follow_requests_spec.rb +++ b/spec/requests/api/v1/follow_requests_spec.rb @@ -13,7 +13,7 @@ RSpec.describe 'Follow requests' do get '/api/v1/follow_requests', headers: headers, params: params end - let(:accounts) { Fabricate.times(5, :account) } + let(:accounts) { Fabricate.times(2, :account) } let(:params) { {} } let(:expected_response) do @@ -40,7 +40,7 @@ RSpec.describe 'Follow requests' do end context 'with limit param' do - let(:params) { { limit: 2 } } + let(:params) { { limit: 1 } } it 'returns only the requested number of follow requests' do subject diff --git a/spec/requests/api/v1/followed_tags_spec.rb b/spec/requests/api/v1/followed_tags_spec.rb index 9391c7bdc..52ed1ba4b 100644 --- a/spec/requests/api/v1/followed_tags_spec.rb +++ b/spec/requests/api/v1/followed_tags_spec.rb @@ -13,7 +13,7 @@ RSpec.describe 'Followed tags' do get '/api/v1/followed_tags', headers: headers, params: params end - let!(:tag_follows) { Fabricate.times(5, :tag_follow, account: user.account) } + let!(:tag_follows) { Fabricate.times(2, :tag_follow, account: user.account) } let(:params) { {} } let(:expected_response) do @@ -41,7 +41,7 @@ RSpec.describe 'Followed tags' do end context 'with limit param' do - let(:params) { { limit: 3 } } + let(:params) { { limit: 1 } } it 'returns only the requested number of follow tags' do subject @@ -58,7 +58,7 @@ RSpec.describe 'Followed tags' do it 'sets the correct pagination header for the next path' do subject - expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], max_id: tag_follows[2].id)) + expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_followed_tags_url(limit: params[:limit], max_id: tag_follows.last.id)) end end end diff --git a/spec/requests/api/v1/lists/accounts_spec.rb b/spec/requests/api/v1/lists/accounts_spec.rb index 4d2a168b3..de4998235 100644 --- a/spec/requests/api/v1/lists/accounts_spec.rb +++ b/spec/requests/api/v1/lists/accounts_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Accounts' do let(:params) { { limit: 0 } } let(:list) { Fabricate(:list, account: user.account) } - let(:accounts) { Fabricate.times(3, :account) } + let(:accounts) { Fabricate.times(2, :account) } let(:expected_response) do accounts.map do |account| diff --git a/spec/requests/api/v1/mutes_spec.rb b/spec/requests/api/v1/mutes_spec.rb index 9a1d16200..b2782a0c2 100644 --- a/spec/requests/api/v1/mutes_spec.rb +++ b/spec/requests/api/v1/mutes_spec.rb @@ -13,7 +13,7 @@ RSpec.describe 'Mutes' do get '/api/v1/mutes', headers: headers, params: params end - let!(:mutes) { Fabricate.times(3, :mute, account: user.account) } + let!(:mutes) { Fabricate.times(2, :mute, account: user.account) } let(:params) { {} } it_behaves_like 'forbidden for wrong scope', 'write write:mutes' @@ -33,7 +33,7 @@ RSpec.describe 'Mutes' do end context 'with limit param' do - let(:params) { { limit: 2 } } + let(:params) { { limit: 1 } } it 'returns only the requested number of muted accounts' do subject @@ -46,8 +46,8 @@ RSpec.describe 'Mutes' do headers = response.headers['Link'] - expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_mutes_url(limit: params[:limit], since_id: mutes[2].id.to_s)) - expect(headers.find_link(%w(rel next)).href).to eq(api_v1_mutes_url(limit: params[:limit], max_id: mutes[1].id.to_s)) + expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_mutes_url(limit: params[:limit], since_id: mutes.last.id.to_s)) + expect(headers.find_link(%w(rel next)).href).to eq(api_v1_mutes_url(limit: params[:limit], max_id: mutes.last.id.to_s)) end end @@ -72,8 +72,8 @@ RSpec.describe 'Mutes' do body = body_as_json - expect(body.size).to eq 2 - expect(body[0][:id]).to eq mutes[2].target_account_id.to_s + expect(body.size).to eq 1 + expect(body[0][:id]).to eq mutes[1].target_account_id.to_s end end diff --git a/spec/requests/api/v1/notifications_spec.rb b/spec/requests/api/v1/notifications_spec.rb index 7a879c35b..7a904816e 100644 --- a/spec/requests/api/v1/notifications_spec.rb +++ b/spec/requests/api/v1/notifications_spec.rb @@ -168,7 +168,7 @@ RSpec.describe 'Notifications' do end before do - Fabricate.times(3, :notification, account: user.account) + Fabricate(:notification, account: user.account) end it_behaves_like 'forbidden for wrong scope', 'read read:notifications' diff --git a/spec/requests/api/v1/statuses_spec.rb b/spec/requests/api/v1/statuses_spec.rb index 1b2dd2b5d..201674fcc 100644 --- a/spec/requests/api/v1/statuses_spec.rb +++ b/spec/requests/api/v1/statuses_spec.rb @@ -156,7 +156,7 @@ describe '/api/v1/statuses' do context 'when exceeding rate limit' do before do rate_limiter = RateLimiter.new(user.account, family: :statuses) - 300.times { rate_limiter.record! } + RateLimiter::FAMILIES[:statuses][:limit].times { rate_limiter.record! } end it 'returns rate limit headers', :aggregate_failures do diff --git a/spec/requests/api/v2/filters_spec.rb b/spec/requests/api/v2/filters_spec.rb index 2ee24d809..fd0483abb 100644 --- a/spec/requests/api/v2/filters_spec.rb +++ b/spec/requests/api/v2/filters_spec.rb @@ -23,7 +23,7 @@ RSpec.describe 'Filters' do get '/api/v2/filters', headers: headers end - let!(:filters) { Fabricate.times(3, :custom_filter, account: user.account) } + let!(:filters) { Fabricate.times(2, :custom_filter, account: user.account) } it_behaves_like 'forbidden for wrong scope', 'write write:filters' it_behaves_like 'unauthorized for invalid token' From f91e751383556c625e581db04272f1ad6c7b4803 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:23:23 +0100 Subject: [PATCH 097/255] Update dependency rspec-rails to v6.1.0 (#28017) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index b992188d1..aafef71b1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -154,7 +154,7 @@ GEM faraday_middleware (~> 1.0, >= 1.0.0.rc1) net-http-persistent (~> 4.0) nokogiri (~> 1, >= 1.10.8) - base64 (0.1.1) + base64 (0.2.0) bcp47_spec (0.2.1) bcrypt (3.1.19) better_errors (2.10.1) @@ -248,7 +248,7 @@ GEM dotenv-rails (2.8.1) dotenv (= 2.8.1) railties (>= 3.2) - drb (2.1.1) + drb (2.2.0) ruby2_keywords ed25519 (1.3.0) elasticsearch (7.13.3) @@ -374,7 +374,7 @@ GEM terminal-table (>= 1.5.1) idn-ruby (0.1.5) io-console (0.6.0) - irb (1.8.3) + irb (1.9.1) rdoc reline (>= 0.3.8) jmespath (1.6.2) @@ -436,7 +436,7 @@ GEM activesupport (>= 4) railties (>= 4) request_store (~> 1.0) - loofah (2.21.4) + loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.8.1) @@ -462,7 +462,7 @@ GEM msgpack (1.7.2) multi_json (1.15.0) multipart-post (2.3.0) - mutex_m (0.1.2) + mutex_m (0.2.0) net-http (0.4.0) uri net-http-persistent (4.0.2) @@ -599,13 +599,13 @@ GEM thor (~> 1.0, >= 1.2.2) zeitwerk (~> 2.6) rainbow (3.1.1) - rake (13.0.6) + rake (13.1.0) rdf (3.3.1) bcp47_spec (~> 0.2) link_header (~> 0.0, >= 0.0.8) rdf-normalize (0.6.1) rdf (~> 3.2) - rdoc (6.5.0) + rdoc (6.6.0) psych (>= 4.0.0) redcarpet (3.6.0) redis (4.8.1) @@ -614,7 +614,7 @@ GEM redlock (1.3.2) redis (>= 3.0.0, < 6.0) regexp_parser (2.8.2) - reline (0.3.9) + reline (0.4.0) io-console (~> 0.5) request_store (1.5.1) rack (>= 1.4) @@ -639,7 +639,7 @@ GEM rspec-mocks (3.12.6) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.12.0) - rspec-rails (6.0.3) + rspec-rails (6.1.0) actionpack (>= 6.1) activesupport (>= 6.1) railties (>= 6.1) From 30ee4aaff44784fb901e0a934e7416de30a4edf0 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 21 Nov 2023 09:25:07 -0500 Subject: [PATCH 098/255] Convert measurement `api/v1/admin/*` controller specs to request specs (#28005) --- .../v1/admin/dimensions_controller_spec.rb | 23 ------------ .../api/v1/admin/measures_controller_spec.rb | 23 ------------ .../api/v1/admin/retention_controller_spec.rb | 23 ------------ spec/requests/api/v1/admin/dimensions_spec.rb | 35 +++++++++++++++++++ spec/requests/api/v1/admin/measures_spec.rb | 35 +++++++++++++++++++ spec/requests/api/v1/admin/retention_spec.rb | 35 +++++++++++++++++++ 6 files changed, 105 insertions(+), 69 deletions(-) delete mode 100644 spec/controllers/api/v1/admin/dimensions_controller_spec.rb delete mode 100644 spec/controllers/api/v1/admin/measures_controller_spec.rb delete mode 100644 spec/controllers/api/v1/admin/retention_controller_spec.rb create mode 100644 spec/requests/api/v1/admin/dimensions_spec.rb create mode 100644 spec/requests/api/v1/admin/measures_spec.rb create mode 100644 spec/requests/api/v1/admin/retention_spec.rb diff --git a/spec/controllers/api/v1/admin/dimensions_controller_spec.rb b/spec/controllers/api/v1/admin/dimensions_controller_spec.rb deleted file mode 100644 index ea18efe38..000000000 --- a/spec/controllers/api/v1/admin/dimensions_controller_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::Admin::DimensionsController do - render_views - - let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'admin:read') } - let(:account) { Fabricate(:account) } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'POST #create' do - it 'returns http success' do - post :create, params: { account_id: account.id, limit: 2 } - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/controllers/api/v1/admin/measures_controller_spec.rb b/spec/controllers/api/v1/admin/measures_controller_spec.rb deleted file mode 100644 index 03727a632..000000000 --- a/spec/controllers/api/v1/admin/measures_controller_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::Admin::MeasuresController do - render_views - - let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'admin:read') } - let(:account) { Fabricate(:account) } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'POST #create' do - it 'returns http success' do - post :create, params: { account_id: account.id, limit: 2 } - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/controllers/api/v1/admin/retention_controller_spec.rb b/spec/controllers/api/v1/admin/retention_controller_spec.rb deleted file mode 100644 index 2381dbcb4..000000000 --- a/spec/controllers/api/v1/admin/retention_controller_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::Admin::RetentionController do - render_views - - let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'admin:read') } - let(:account) { Fabricate(:account) } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'POST #create' do - it 'returns http success' do - post :create, params: { account_id: account.id, limit: 2 } - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v1/admin/dimensions_spec.rb b/spec/requests/api/v1/admin/dimensions_spec.rb new file mode 100644 index 000000000..87534a74b --- /dev/null +++ b/spec/requests/api/v1/admin/dimensions_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Admin Dimensions' do + let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + let(:account) { Fabricate(:account) } + + describe 'GET /api/v1/admin/dimensions' do + context 'when not authorized' do + it 'returns http forbidden' do + post '/api/v1/admin/dimensions', params: { account_id: account.id, limit: 2 } + + expect(response) + .to have_http_status(403) + end + end + + context 'with correct scope' do + let(:scopes) { 'admin:read' } + + it 'returns http success and status json' do + post '/api/v1/admin/dimensions', params: { account_id: account.id, limit: 2 }, headers: headers + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_an(Array) + end + end + end +end diff --git a/spec/requests/api/v1/admin/measures_spec.rb b/spec/requests/api/v1/admin/measures_spec.rb new file mode 100644 index 000000000..15f2df84c --- /dev/null +++ b/spec/requests/api/v1/admin/measures_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Admin Measures' do + let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + let(:account) { Fabricate(:account) } + + describe 'GET /api/v1/admin/measures' do + context 'when not authorized' do + it 'returns http forbidden' do + post '/api/v1/admin/measures', params: { account_id: account.id, limit: 2 } + + expect(response) + .to have_http_status(403) + end + end + + context 'with correct scope' do + let(:scopes) { 'admin:read' } + + it 'returns http success and status json' do + post '/api/v1/admin/measures', params: { account_id: account.id, limit: 2 }, headers: headers + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_an(Array) + end + end + end +end diff --git a/spec/requests/api/v1/admin/retention_spec.rb b/spec/requests/api/v1/admin/retention_spec.rb new file mode 100644 index 000000000..9178335ba --- /dev/null +++ b/spec/requests/api/v1/admin/retention_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Admin Retention' do + let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + let(:account) { Fabricate(:account) } + + describe 'GET /api/v1/admin/retention' do + context 'when not authorized' do + it 'returns http forbidden' do + post '/api/v1/admin/retention', params: { account_id: account.id, limit: 2 } + + expect(response) + .to have_http_status(403) + end + end + + context 'with correct scope' do + let(:scopes) { 'admin:read' } + + it 'returns http success and status json' do + post '/api/v1/admin/retention', params: { account_id: account.id, limit: 2 }, headers: headers + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_an(Array) + end + end + end +end From 67fd3187b3cf626d836506431169c627ec066730 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 21 Nov 2023 10:51:40 -0500 Subject: [PATCH 099/255] Update rspec fixture path config to silence deprecation warning (#28018) --- spec/rails_helper.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 7deab6c7f..1ca91c6cd 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -60,7 +60,9 @@ RSpec.configure do |config| # By default, skip the elastic search integration specs config.filter_run_excluding search: true - config.fixture_path = Rails.root.join('spec', 'fixtures') + config.fixture_paths = [ + Rails.root.join('spec', 'fixtures'), + ] config.use_transactional_fixtures = true config.order = 'random' config.infer_spec_type_from_file_location! From c9ffdcbaa244e231fe1358051ce7ae13c1d4c43b Mon Sep 17 00:00:00 2001 From: Emelia Smith <ThisIsMissEm@users.noreply.github.com> Date: Tue, 21 Nov 2023 17:41:04 +0100 Subject: [PATCH 100/255] Add debug + irb gems to assist with debugging in development and tests (#27960) --- Gemfile | 6 ++++++ Gemfile.lock | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/Gemfile b/Gemfile index 74672ad06..e3fb39e16 100644 --- a/Gemfile +++ b/Gemfile @@ -9,6 +9,9 @@ gem 'sprockets', '~> 3.7.2' gem 'thor', '~> 1.2' gem 'rack', '~> 2.2.7' +# For why irb is in the Gemfile, see: https://ruby.social/@st0012/111444685161478182 +gem 'irb', '~> 1.8' + gem 'haml-rails', '~>2.0' gem 'pg', '~> 1.5' gem 'pghero' @@ -179,6 +182,9 @@ group :development do end group :development, :test do + # Interactive Debugging tools + gem 'debug', '~> 1.8' + # Profiling tools gem 'memory_profiler', require: false gem 'ruby-prof', require: false diff --git a/Gemfile.lock b/Gemfile.lock index aafef71b1..22d74d515 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -220,6 +220,9 @@ GEM database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) date (3.3.4) + debug (1.8.0) + irb (>= 1.5.0) + reline (>= 0.3.1) debug_inspector (1.1.0) devise (4.9.3) bcrypt (~> 3.0) @@ -851,6 +854,7 @@ DEPENDENCIES concurrent-ruby connection_pool database_cleaner-active_record + debug (~> 1.8) devise (~> 4.9) devise-two-factor (~> 4.1) devise_pam_authenticatable2 (~> 9.2) @@ -876,6 +880,7 @@ DEPENDENCIES httplog (~> 1.6.2) i18n-tasks (~> 1.0) idn-ruby + irb (~> 1.8) json-ld json-ld-preloaded (~> 3.2) json-schema (~> 4.0) From cdc57c74b7c387d5183c20ab31ddb937346c174f Mon Sep 17 00:00:00 2001 From: Eugen Rochko <eugen@zeonfederated.com> Date: Wed, 22 Nov 2023 12:38:07 +0100 Subject: [PATCH 101/255] Fix unsupported time zone or locale preventing sign-up (#28035) Co-authored-by: Claire <claire.github-309c@sitedethib.com> --- app/models/user.rb | 14 ++++++++++---- .../preferences/appearance_controller_spec.rb | 6 ------ spec/models/user_spec.rb | 18 ++++++++++++------ 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index ef621e1bc..5185343af 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -96,11 +96,9 @@ class User < ApplicationRecord accepts_nested_attributes_for :invite_request, reject_if: ->(attributes) { attributes['text'].blank? && !Setting.require_invite_text } validates :invite_request, presence: true, on: :create, if: :invite_text_required? - validates :locale, inclusion: I18n.available_locales.map(&:to_s), if: :locale? validates_with BlacklistedEmailValidator, if: -> { ENV['EMAIL_DOMAIN_LISTS_APPLY_AFTER_CONFIRMATION'] == 'true' || !confirmed? } validates_with EmailMxValidator, if: :validate_email_dns? validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create - validates :time_zone, inclusion: { in: ActiveSupport::TimeZone.all.map { |tz| tz.tzinfo.name } }, allow_blank: true # Honeypot/anti-spam fields attr_accessor :registration_form_time, :website, :confirm_password @@ -124,6 +122,8 @@ class User < ApplicationRecord before_validation :sanitize_languages before_validation :sanitize_role + before_validation :sanitize_time_zone + before_validation :sanitize_locale before_create :set_approved after_commit :send_pending_devise_notifications after_create_commit :trigger_webhooks @@ -451,9 +451,15 @@ class User < ApplicationRecord end def sanitize_role - return if role.nil? + self.role = nil if role.present? && role.everyone? + end - self.role = nil if role.everyone? + def sanitize_time_zone + self.time_zone = nil if time_zone.present? && ActiveSupport::TimeZone[time_zone].nil? + end + + def sanitize_locale + self.locale = nil if locale.present? && I18n.available_locales.exclude?(locale.to_sym) end def prepare_new_user! diff --git a/spec/controllers/settings/preferences/appearance_controller_spec.rb b/spec/controllers/settings/preferences/appearance_controller_spec.rb index ee0ded1b9..261c426ac 100644 --- a/spec/controllers/settings/preferences/appearance_controller_spec.rb +++ b/spec/controllers/settings/preferences/appearance_controller_spec.rb @@ -28,11 +28,5 @@ describe Settings::Preferences::AppearanceController do expect(response).to redirect_to(settings_preferences_appearance_path) end - - it 'renders show on failure' do - put :update, params: { user: { locale: 'fake option' } } - - expect(response).to render_template('preferences/appearance/show') - end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index faf7fabf1..a2f8d2ca4 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -27,12 +27,6 @@ RSpec.describe User do expect(user).to model_have_error_on_field(:account) end - it 'is invalid without a valid locale' do - user = Fabricate.build(:user, locale: 'toto') - user.valid? - expect(user).to model_have_error_on_field(:locale) - end - it 'is invalid without a valid email' do user = Fabricate.build(:user, email: 'john@') user.valid? @@ -45,6 +39,18 @@ RSpec.describe User do expect(user.valid?).to be true end + it 'cleans out invalid locale' do + user = Fabricate.build(:user, locale: 'toto') + expect(user.valid?).to be true + expect(user.locale).to be_nil + end + + it 'cleans out invalid timezone' do + user = Fabricate.build(:user, time_zone: 'toto') + expect(user.valid?).to be true + expect(user.time_zone).to be_nil + end + it 'cleans out empty string from languages' do user = Fabricate.build(:user, chosen_languages: ['']) user.valid? From c3d3ada07b966c64484e44043186ee8fa9f4514d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 22 Nov 2023 16:27:54 +0100 Subject: [PATCH 102/255] Update dependency test-prof to v1.3.0 (#28032) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 22d74d515..c83247cf6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -760,7 +760,7 @@ GEM unicode-display_width (>= 1.1.1, < 3) terrapin (0.6.0) climate_control (>= 0.0.3, < 1.0) - test-prof (1.2.3) + test-prof (1.3.0) thor (1.3.0) tilt (2.3.0) timeout (0.4.1) From 183afc246536a80ba2437379239e95f7b35a9366 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 22 Nov 2023 16:28:14 +0100 Subject: [PATCH 103/255] Update dependency aws-sdk-s3 to v1.138.0 (#28031) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c83247cf6..3903464c3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -131,8 +131,8 @@ GEM attr_required (1.0.1) awrence (1.2.1) aws-eventstream (1.2.0) - aws-partitions (1.853.0) - aws-sdk-core (3.187.0) + aws-partitions (1.855.0) + aws-sdk-core (3.187.1) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) @@ -140,7 +140,7 @@ GEM aws-sdk-kms (1.72.0) aws-sdk-core (~> 3, >= 3.184.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.137.0) + aws-sdk-s3 (1.138.0) aws-sdk-core (~> 3, >= 3.181.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.6) From 9742bccbe76fbd32cc3db8ad889ea7b5b77b8733 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 22 Nov 2023 10:39:34 -0500 Subject: [PATCH 104/255] Add coverage for `api/v2/media` endpoint (#28027) --- app/controllers/api/v2/media_controller.rb | 14 +++- spec/requests/api/v2/media_spec.rb | 80 ++++++++++++++++++++-- 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/v2/media_controller.rb b/app/controllers/api/v2/media_controller.rb index 72bc69442..36c15165d 100644 --- a/app/controllers/api/v2/media_controller.rb +++ b/app/controllers/api/v2/media_controller.rb @@ -2,12 +2,22 @@ class Api::V2::MediaController < Api::V1::MediaController def create - @media_attachment = current_account.media_attachments.create!({ delay_processing: true }.merge(media_attachment_params)) - render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: @media_attachment.not_processed? ? 202 : 200 + @media_attachment = current_account.media_attachments.create!(media_and_delay_params) + render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_from_media_processing rescue Paperclip::Errors::NotIdentifiedByImageMagickError render json: file_type_error, status: 422 rescue Paperclip::Error => e Rails.logger.error "#{e.class}: #{e.message}" render json: processing_error, status: 500 end + + private + + def media_and_delay_params + { delay_processing: true }.merge(media_attachment_params) + end + + def status_from_media_processing + @media_attachment.not_processed? ? 202 : 200 + end end diff --git a/spec/requests/api/v2/media_spec.rb b/spec/requests/api/v2/media_spec.rb index fc6946be5..990fa5d0b 100644 --- a/spec/requests/api/v2/media_spec.rb +++ b/spec/requests/api/v2/media_spec.rb @@ -9,10 +9,82 @@ RSpec.describe 'Media API', :paperclip_processing do let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } describe 'POST /api/v2/media' do - it 'returns http success' do - post '/api/v2/media', headers: headers, params: { file: fixture_file_upload('attachment-jpg.123456_abcd', 'image/jpeg') } - expect(File.exist?(user.account.media_attachments.first.file.path(:small))).to be true - expect(response).to have_http_status(200) + context 'when small media format attachment is processed immediately' do + let(:params) { { file: fixture_file_upload('attachment-jpg.123456_abcd', 'image/jpeg') } } + + it 'returns http success' do + post '/api/v2/media', headers: headers, params: params + + expect(File.exist?(user.account.media_attachments.first.file.path(:small))) + .to be true + + expect(response) + .to have_http_status(200) + + expect(body_as_json) + .to be_a(Hash) + end + end + + context 'when large format media attachment has not been processed' do + let(:params) { { file: fixture_file_upload('attachment.webm', 'video/webm') } } + + it 'returns http accepted' do + post '/api/v2/media', headers: headers, params: params + + expect(File.exist?(user.account.media_attachments.first.file.path(:small))) + .to be true + + expect(response) + .to have_http_status(202) + + expect(body_as_json) + .to be_a(Hash) + end + end + + describe 'when paperclip errors occur' do + let(:media_attachments) { double } + let(:params) { { file: fixture_file_upload('attachment.jpg', 'image/jpeg') } } + + before do + allow(User).to receive(:find).with(token.resource_owner_id).and_return(user) + allow(user.account).to receive(:media_attachments).and_return(media_attachments) + end + + context 'when imagemagick cannot identify the file type' do + before do + allow(media_attachments).to receive(:create!).and_raise(Paperclip::Errors::NotIdentifiedByImageMagickError) + end + + it 'returns http unprocessable entity' do + post '/api/v2/media', headers: headers, params: params + + expect(response) + .to have_http_status(422) + + expect(body_as_json) + .to be_a(Hash) + .and include(error: /File type/) + end + end + + context 'when there is a generic error' do + before do + allow(media_attachments).to receive(:create!).and_raise(Paperclip::Error) + end + + it 'returns http 500' do + post '/api/v2/media', headers: headers, params: params + + expect(response) + .to have_http_status(500) + + expect(body_as_json) + .to be_a(Hash) + .and include(error: /processing/) + end + end end end end From d3ed03fd6bd8107b3bfe97e32b66b40a8c69fe1b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 Nov 2023 16:48:12 +0100 Subject: [PATCH 105/255] New Crowdin Translations (automated) (#28036) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/bg.json | 5 +++ app/javascript/mastodon/locales/fr-QC.json | 2 +- app/javascript/mastodon/locales/fr.json | 2 +- app/javascript/mastodon/locales/is.json | 2 +- config/locales/simple_form.lt.yml | 45 ++++++++++++++++++++-- 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 339ba6011..ccbd1042d 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -21,6 +21,7 @@ "account.blocked": "Блокирани", "account.browse_more_on_origin_server": "Разглеждане на още в оригиналния профил", "account.cancel_follow_request": "Оттегляне на заявката за последване", + "account.copy": "Копиране на връзка към профила", "account.direct": "Частно споменаване на @{name}", "account.disable_notifications": "Сприране на известия при публикуване от @{name}", "account.domain_blocked": "Блокиран домейн", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Маркиране като прочетено", "conversation.open": "Преглед на разговора", "conversation.with": "С {names}", + "copy_icon_button.copied": "Копиранo в буферната памет", "copypaste.copied": "Копирано", "copypaste.copy_to_clipboard": "Копиране в буферната памет", "directory.federated": "От позната федивселена", @@ -479,6 +481,8 @@ "onboarding.follows.empty": "За съжаление, в момента не могат да се показват резултати. Може да опитате да употребявате търсене или да прегледате страницата за изследване, за да намерите страница за последване, или да опитате пак по-късно.", "onboarding.follows.lead": "Може да бъдете куратор на началния си инфоканал. Последвайки повече хора, по-деен и по-интересен ще става. Тези профили може да са добра начална точка, от която винаги по-късно да спрете да следвате!", "onboarding.follows.title": "Популярно в Mastodon", + "onboarding.profile.discoverable": "Правене на моя профил откриваем", + "onboarding.profile.discoverable_hint": "Включвайки откриваемостта в Mastodon, вашите публикации може да се появят при резултатите от търсене и изгряващи неща, и вашия профил може да бъде предложен на хора с подобни интереси като вашите.", "onboarding.profile.display_name": "Името на показ", "onboarding.profile.display_name_hint": "Вашето пълно име или псевдоним…", "onboarding.profile.lead": "Винаги може да завършите това по-късно в настройките, където дори има повече възможности за настройване.", @@ -531,6 +535,7 @@ "privacy.unlisted.short": "Несписъчно", "privacy_policy.last_updated": "Последно осъвременяване на {date}", "privacy_policy.title": "Политика за поверителност", + "recommended": "Препоръчано", "refresh": "Опресняване", "regeneration_indicator.label": "Зареждане…", "regeneration_indicator.sublabel": "Подготовка на началния ви инфоканал!", diff --git a/app/javascript/mastodon/locales/fr-QC.json b/app/javascript/mastodon/locales/fr-QC.json index aeb1bf6b0..94ab5333c 100644 --- a/app/javascript/mastodon/locales/fr-QC.json +++ b/app/javascript/mastodon/locales/fr-QC.json @@ -308,7 +308,7 @@ "home.column_settings.basic": "Basique", "home.column_settings.show_reblogs": "Afficher boosts", "home.column_settings.show_replies": "Afficher réponses", - "home.explore_prompt.body": "Votre fil d'actualité aura un mélange de messages depuis les hashtags que vous avez choisi de suivre, les personnes que vous avez choisi de suivre, et les messages qu'ils boostent. Si ça vous semble trop calme à votre goût, n’hésitez pas à :", + "home.explore_prompt.body": "Votre fil d'actualité aura un mélange de messages depuis les hashtags que vous avez choisi de suivre, les personnes que vous avez choisi de suivre, et les messages qu'elles boostent. Si ça vous semble trop calme à votre goût, n’hésitez pas à :", "home.explore_prompt.title": "C'est votre page d'accueil dans Mastodon.", "home.hide_announcements": "Masquer les annonces", "home.pending_critical_update.body": "Veuillez mettre à jour votre serveur Mastodon dès que possible !", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 95026531e..f7b3fc1f0 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -308,7 +308,7 @@ "home.column_settings.basic": "Basique", "home.column_settings.show_reblogs": "Afficher les partages", "home.column_settings.show_replies": "Afficher les réponses", - "home.explore_prompt.body": "Votre fil d'actualité aura un mélange de messages depuis les hashtags que vous avez choisi de suivre, les personnes que vous avez choisi de suivre, et les messages qu'ils boostent. Si ça vous semble trop calme à votre goût, n’hésitez pas à :", + "home.explore_prompt.body": "Votre fil d'actualité aura un mélange de messages depuis les hashtags que vous avez choisi de suivre, les personnes que vous avez choisi de suivre, et les messages qu'elles boostent. Si ça vous semble trop calme à votre goût, n’hésitez pas à :", "home.explore_prompt.title": "C'est votre page d'accueil dans Mastodon.", "home.hide_announcements": "Masquer les annonces", "home.pending_critical_update.body": "Veuillez mettre à jour votre serveur Mastodon dès que possible !", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 4c9ca12d9..42d2c9811 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -305,7 +305,7 @@ "hashtag.follow": "Fylgjast með myllumerki", "hashtag.unfollow": "Hætta að fylgjast með myllumerki", "hashtags.and_other": "…og {count, plural, other {# til viðbótar}}", - "home.actions.go_to_explore": "Sjáðu hvað er í umræðunni", + "home.actions.go_to_explore": "Sjá hvað er í umræðunni", "home.actions.go_to_suggestions": "Finna fólk til að fylgjast með", "home.column_settings.basic": "Einfalt", "home.column_settings.show_reblogs": "Sýna endurbirtingar", diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index 69a6b86dd..39caaf6ba 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -10,17 +10,36 @@ lt: note: 'Gali @paminėti kitus žmones arba #saitažodžius.' show_collections: Žmonės galės peržiūrėti tavo sekimus ir sekėjus. Žmonės, kuriuos seki, matys, kad juos seki, nepaisant to. unlocked: Žmonės galės tave sekti nepaprašę patvirtinimo. Panaikink žymėjimą, jei nori peržiūrėti sekimo prašymus ir pasirinkti, ar priimti, ar atmesti naujus sekėjus. + account_alias: + acct: Nurodyk paskyros, iš kurios nori perkelti, naudotojo vardą@domeną + account_migration: + acct: Nurodyk paskyros, į kurią nori perkelti, naudotojo vardą@domeną account_warning_preset: - text: Gali naudoti įrašų sintaksę, pavyzdžiui, URL adresus, saitažodus ir paminėjimus + text: Gali naudoti įrašų sintaksę, pavyzdžiui, URL adresus, saitažodžius ir paminėjimus + title: Pasirinktinai. Gavėjui nematomas + admin_account_action: + include_statuses: Naudotojas (-a) matys, dėl kurių įrašų buvo atliktas prižiūrimo arba įspėjimo veiksmas + send_email_notification: Naudotojas (-a) gaus paaiškinimą, kas nutiko su jo (-s) paskyra + text_html: Pasirinktinai. Gali naudoti įrašo sintaksę. Taupydamas (-a) laiką gali <a href="%{path}">pridėti įspėjimo išankstinius nustatymus</a> + type_html: Pasirink, ką daryti su <strong>%{acct}</strong> + types: + disable: Neleisk naudotojui naudotis savo paskyra, bet nepanaikink ir nepaslėpk jos turinio. + none: Naudok šią parinktį norėdamas (-a) išsiųsti įspėjimą naudotojui, nesukeldamas (-a) jokio kito veiksmo. + sensitive: Priversk visus šio naudotojo medijos priedus pažymėti kaip jautrius. + silence: Neleisk naudotojui skelbti viešai matomų įrašų, paslėpk jų įrašus ir pranešimus nuo žmonių, kurie neseka jo. Uždaro visus su šia paskyra susijusius ataskaitas. defaults: + avatar: PNG, GIF arba JPG. Ne daugiau kaip %{size}. Bus sumažintas iki %{dimensions} tšk. header: PNG, GIF arba JPG. Ne daugiau kaip %{size}. Bus sumažintas iki %{dimensions}tšk. inbox_url: Nukopijuok URL adresą iš pradinio puslapio perdavėjo, kurį nori naudoti irreversible: Filtruoti įrašai išnyks negrįžtamai, net jei vėliau filtras bus pašalintas locale: Naudotojo sąsajos kalba, el. laiškai ir stumiamieji pranešimai password: Naudok bent 8 simbolius phrase: Bus suderinta, neatsižvelgiant į teksto korpusą arba įrašo turinio įspėjimą - setting_display_media_hide_all: Visada slėpti žiniasklaidą - setting_display_media_show_all: Visada rodyti žiniasklaidą + setting_always_send_emails: Paprastai pranešimai el. paštu nebus siunčiami, kai aktyviai naudoji Mastodon + setting_default_sensitive: Jautrioji medija pagal numatytuosius nustatymus yra paslėpta ir gali būti atskleista paspaudus + setting_display_media_default: Slėpti mediją, pažymėtą kaip jautrią + setting_display_media_hide_all: Visada slėpti mediją + setting_display_media_show_all: Visada rodyti mediją setting_use_blurhash: Gradientai pagrįsti paslėptų vaizdų spalvomis, tačiau užgožia bet kokias detales setting_use_pending_items: Slėpti laiko skalės naujienas po paspaudimo, vietoj automatinio kanalo slinkimo featured_tag: @@ -43,3 +62,23 @@ lt: name: Saitažodis trendable: Leisti šį saitažodį rodyti pagal trendus usable: Leisti įrašams naudoti šį saitažodį + user: + role: Vaidmuo + user_role: + permissions_as_keys: Leidimai + position: Prioritetas + webhook: + events: Įgalinti įvykiai + template: Naudingosios apkrovos šablonas + url: Galutinio taško URL + 'no': Ne + not_recommended: Nerekomenduojama + overridden: Pakeista + recommended: Rekomenduojama + required: + mark: "*" + text: privalomas + title: + sessions: + webauthn: Prisijungimui naudoti vieną iš saugumo raktų + 'yes': Taip From 990c63b4407115dad5f69af24094987a52501507 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 10:24:48 +0100 Subject: [PATCH 106/255] Update dependency aws-sdk-s3 to v1.139.0 (#28047) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3903464c3..abd1b8499 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -130,21 +130,21 @@ GEM encryptor (~> 3.0.0) attr_required (1.0.1) awrence (1.2.1) - aws-eventstream (1.2.0) + aws-eventstream (1.3.0) aws-partitions (1.855.0) - aws-sdk-core (3.187.1) + aws-sdk-core (3.188.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.72.0) - aws-sdk-core (~> 3, >= 3.184.0) + aws-sdk-kms (1.73.0) + aws-sdk-core (~> 3, >= 3.188.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.138.0) - aws-sdk-core (~> 3, >= 3.181.0) + aws-sdk-s3 (1.139.0) + aws-sdk-core (~> 3, >= 3.188.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.6) - aws-sigv4 (1.6.1) + aws-sigv4 (1.7.0) aws-eventstream (~> 1, >= 1.0.2) azure-storage-blob (2.0.3) azure-storage-common (~> 2.0) From 4be12791e6f1b4488920b66ded35310cc34477cc Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 23 Nov 2023 04:26:11 -0500 Subject: [PATCH 107/255] Remove `default_scope` from `StatusEdit` class (#28042) --- app/controllers/admin/statuses_controller.rb | 2 +- app/controllers/api/v1/statuses/histories_controller.rb | 2 +- app/models/status_edit.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/admin/statuses_controller.rb b/app/controllers/admin/statuses_controller.rb index 5712dea88..e53b22dca 100644 --- a/app/controllers/admin/statuses_controller.rb +++ b/app/controllers/admin/statuses_controller.rb @@ -32,7 +32,7 @@ module Admin private def batched_ordered_status_edits - @status.edits.reorder(nil).includes(:account, status: [:account]).find_each(order: :asc) + @status.edits.includes(:account, status: [:account]).find_each(order: :asc) end helper_method :batched_ordered_status_edits diff --git a/app/controllers/api/v1/statuses/histories_controller.rb b/app/controllers/api/v1/statuses/histories_controller.rb index dcb21ef04..e381ea2c6 100644 --- a/app/controllers/api/v1/statuses/histories_controller.rb +++ b/app/controllers/api/v1/statuses/histories_controller.rb @@ -11,6 +11,6 @@ class Api::V1::Statuses::HistoriesController < Api::V1::Statuses::BaseController private def status_edits - @status.edits.includes(:account, status: [:account]).to_a.presence || [@status.build_snapshot(at_time: @status.edited_at || @status.created_at)] + @status.edits.ordered.includes(:account, status: [:account]).to_a.presence || [@status.build_snapshot(at_time: @status.edited_at || @status.created_at)] end end diff --git a/app/models/status_edit.rb b/app/models/status_edit.rb index 2b3248bb2..50dabb91f 100644 --- a/app/models/status_edit.rb +++ b/app/models/status_edit.rb @@ -39,7 +39,7 @@ class StatusEdit < ApplicationRecord belongs_to :status belongs_to :account, optional: true - default_scope { order(id: :asc) } + scope :ordered, -> { order(id: :asc) } delegate :local?, :application, :edited?, :edited_at, :discarded?, :visibility, to: :status From c810b197ad48b404a49a516565781634ea500b98 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 10:34:50 +0100 Subject: [PATCH 108/255] New Crowdin Translations (automated) (#28050) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/ko.json | 8 +++---- app/javascript/mastodon/locales/sr-Latn.json | 15 ++++++++++++ config/locales/doorkeeper.ko.yml | 2 +- config/locales/ko.yml | 24 ++++++++++---------- config/locales/simple_form.ko.yml | 4 ++-- 5 files changed, 34 insertions(+), 19 deletions(-) diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 51189b6a9..9947d1d8c 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -25,7 +25,7 @@ "account.direct": "@{name} 님에게 개인적으로 멘션", "account.disable_notifications": "@{name} 의 게시물 알림 끄기", "account.domain_blocked": "도메인 차단함", - "account.edit_profile": "프로필 수정", + "account.edit_profile": "프로필 편집", "account.enable_notifications": "@{name} 의 게시물 알림 켜기", "account.endorse": "프로필에 추천하기", "account.featured_tags.last_status_at": "{date}에 마지막으로 게시", @@ -176,7 +176,7 @@ "confirmations.domain_block.confirm": "도메인 전체를 차단", "confirmations.domain_block.message": "정말로 {domain} 전체를 차단하시겠습니까? 대부분의 경우 개별 차단이나 뮤트로 충분합니다. 모든 공개 타임라인과 알림에서 해당 도메인에서 작성된 콘텐츠를 보지 못합니다. 해당 도메인에 속한 팔로워와의 관계가 사라집니다.", "confirmations.edit.confirm": "수정", - "confirmations.edit.message": "지금 수정하면 작성 중인 메시지를 덮어쓰게 됩니다. 정말 진행합니까?", + "confirmations.edit.message": "지금 편집하면 작성 중인 메시지를 덮어씁니다. 진행이 확실한가요?", "confirmations.logout.confirm": "로그아웃", "confirmations.logout.message": "정말로 로그아웃 하시겠습니까?", "confirmations.mute.confirm": "뮤트", @@ -718,12 +718,12 @@ "upload_form.thumbnail": "썸네일 변경", "upload_form.undo": "삭제", "upload_form.video_description": "청각, 시각 장애인을 위한 설명", - "upload_modal.analyzing_picture": "그림 분석 중…", + "upload_modal.analyzing_picture": "사진 분석 중…", "upload_modal.apply": "적용", "upload_modal.applying": "적용 중...", "upload_modal.choose_image": "이미지 선택", "upload_modal.description_placeholder": "다람쥐 헌 쳇바퀴 타고파", - "upload_modal.detect_text": "그림에서 문자 탐색", + "upload_modal.detect_text": "사진에서 문자 탐색", "upload_modal.edit_media": "미디어 수정", "upload_modal.hint": "미리보기를 클릭하거나 드래그 해서 포컬 포인트를 맞추세요. 이 점은 썸네일에 항상 보여질 부분을 나타냅니다.", "upload_modal.preparing_ocr": "OCR 준비 중…", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index ea6e188cb..762ac68d9 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -21,6 +21,7 @@ "account.blocked": "Blokiran", "account.browse_more_on_origin_server": "Pregledajte još na originalnom profilu", "account.cancel_follow_request": "Povuci zahtev za praćenje", + "account.copy": "Kopiraj vezu u profil", "account.direct": "Privatno pomeni @{name}", "account.disable_notifications": "Zaustavi obaveštavanje za objave korisnika @{name}", "account.domain_blocked": "Domen je blokiran", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Označi kao pročitano", "conversation.open": "Prikaži razgovor", "conversation.with": "Sa {names}", + "copy_icon_button.copied": "Kopirano", "copypaste.copied": "Kopirano", "copypaste.copy_to_clipboard": "Kopiraj", "directory.federated": "Sa znanog fediverzuma", @@ -390,6 +392,7 @@ "lists.search": "Pretraži među ljudima koje pratite", "lists.subheading": "Vaše liste", "load_pending": "{count, plural, one {# nova stavka} few {# nove stavke} other {# novih stavki}}", + "loading_indicator.label": "Učitavanje…", "media_gallery.toggle_visible": "{number, plural, one {Sakrij sliku} few {Sakrij slike} other {Sakrij slike}}", "moved_to_account_banner.text": "Vaš nalog {disabledAccount} je trenutno onemogućen jer ste prešli na {movedToAccount}.", "mute_modal.duration": "Trajanje", @@ -478,6 +481,17 @@ "onboarding.follows.empty": "Nažalost, trenutno se ne mogu prikazati rezultati. Možete pokušati sa korišćenjem pretrage ili pregledanjem stranice za istraživanje da biste pronašli ljude koje ćete pratiti ili pokušajte ponovo kasnije.", "onboarding.follows.lead": "Vi sami birate svoju početnu stranicu. Što više ljudi pratite, to će biti aktivnije i zanimljivije. Ovi profili mogu biti dobra polazna tačka—uvek možete da ih prestanete pratiti kasnije!", "onboarding.follows.title": "Personalizujte svoju početnu stranicu", + "onboarding.profile.discoverable": "Neka se moj profil može otkriti drugima", + "onboarding.profile.discoverable_hint": "Kada omogućite mogućnost otkrivanja na Mastodon-u, vaše objave se mogu pojaviti u rezultatima pretrage i u trendu, a vaš profil može biti predložen ljudima sa sličnim interesovanjima.", + "onboarding.profile.display_name": "Ime za prikaz", + "onboarding.profile.display_name_hint": "Vaše puno ime ili nadimak…", + "onboarding.profile.lead": "Ovo možete uvek dovršiti kasnije u podešavanjima, gde je dostupno još više opcija prilagođavanja.", + "onboarding.profile.note": "Biografija", + "onboarding.profile.note_hint": "Možete da @pomenete druge ljude ili #heš oznake…", + "onboarding.profile.save_and_continue": "Sačuvaj i nastavi", + "onboarding.profile.title": "Podešavanje profila", + "onboarding.profile.upload_avatar": "Otpremi sliku profila", + "onboarding.profile.upload_header": "Otpremi zaglavlje profila", "onboarding.share.lead": "Neka ljudi znaju kako mogu da vas pronađu na Mastodon-u!", "onboarding.share.message": "Ja sam {username} na #Mastodon-u! Pratite me na {url}", "onboarding.share.next_steps": "Mogući sledeći koraci:", @@ -521,6 +535,7 @@ "privacy.unlisted.short": "Neizlistano", "privacy_policy.last_updated": "Poslednje ažuriranje {date}", "privacy_policy.title": "Politika privatnosti", + "recommended": "Preporučeno", "refresh": "Osveži", "regeneration_indicator.label": "Učitavanje…", "regeneration_indicator.sublabel": "Vaša početna stranica se priprema!", diff --git a/config/locales/doorkeeper.ko.yml b/config/locales/doorkeeper.ko.yml index 8e6e4b8aa..4721e3acd 100644 --- a/config/locales/doorkeeper.ko.yml +++ b/config/locales/doorkeeper.ko.yml @@ -27,7 +27,7 @@ ko: confirmations: destroy: 확실합니까? edit: - title: 애플리케이션 수정 + title: 애플리케이션 편집 form: error: 이런! 오류를 확인하세요 help: diff --git a/config/locales/ko.yml b/config/locales/ko.yml index a30540fac..e6187f4d8 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -32,7 +32,7 @@ ko: add_email_domain_block: 이 이메일 도메인을 차단하기 approve: 허가 approved_msg: 성공적으로 %{username}의 가입 신청서를 승인했습니다 - are_you_sure: 정말로 실행하시겠습니까? + are_you_sure: 확실합니까? avatar: 아바타 by_domain: 도메인 change_email: @@ -55,16 +55,16 @@ ko: deleted: 삭제됨 demote: 강등 destroyed_msg: "%{username}의 데이터는 곧 삭제되도록 대기열에 들어갔습니다" - disable: 비활성화 + disable: 동결 disable_sign_in_token_auth: 이메일 토큰 인증 비활성화 disable_two_factor_authentication: 2단계 인증을 비활성화 - disabled: 비활성화됨 + disabled: 동결됨 display_name: 표시되는 이름 domain: 도메인 edit: 수정 email: 이메일 email_status: 이메일 상태 - enable: 활성화 + enable: 동결 해제 enable_sign_in_token_auth: 이메일 토큰 인증 활성화 enabled: 활성 enabled_msg: "%{username}의 계정을 성공적으로 얼리기 해제하였습니다" @@ -292,7 +292,7 @@ ko: announcements: destroyed_msg: 공지가 성공적으로 삭제되었습니다! edit: - title: 공지사항 수정 + title: 공지사항 편집 empty: 공지를 찾을 수 없습니다. live: 진행 중 new: @@ -586,7 +586,7 @@ ko: actions_description_html: 이 신고를 해결하기 위해 취해야 할 조치를 지정해주세요. 신고된 계정에 대해 처벌 조치를 취하면, <strong>스팸</strong> 카테고리가 선택된 경우를 제외하고 해당 계정으로 이메일 알림이 전송됩니다. actions_description_remote_html: 이 신고를 해결하기 위해 실행할 행동을 결정하세요. 이 결정은 이 원격 계정과 그 콘텐츠를 다루는 방식에 대해 <strong>이 서버</strong>에서만 영향을 끼칩니다 add_to_report: 신고에 더 추가하기 - are_you_sure: 정말로 실행하시겠습니까? + are_you_sure: 확실합니까? assign_to_self: 나에게 할당하기 assigned: 할당된 중재자 by_target_domain: 신고된 계정의 도메인 @@ -926,7 +926,7 @@ ko: warning_presets: add_new: 새로 추가 delete: 삭제 - edit_preset: 경고 틀 수정 + edit_preset: 경고 프리셋 편집 empty: 아직 어떤 경고 틀도 정의되지 않았습니다. title: 경고 틀 관리 webhooks: @@ -1175,7 +1175,7 @@ ko: invalid_domain: 올바른 도메인 네임이 아닙니다 edit_profile: basic_information: 기본 정보 - hint_html: "<strong>사람들이 공개 프로필을 보고서 게시물을 볼 때를 위한 프로필을 꾸밉니다.</strong> 프로필과 프로필 그림을 채우면 다른 사람들이 나를 팔로우하고 나와 교류할 기회가 더 많아집니다." + hint_html: "<strong>사람들이 공개 프로필을 보고서 게시물을 볼 때를 위한 프로필을 꾸밉니다.</strong> 프로필과 프로필 사진을 채우면 다른 사람들이 나를 팔로우하고 나와 교류할 기회가 더 많아집니다." other: 기타 errors: '400': 제출한 요청이 올바르지 않습니다. @@ -1227,7 +1227,7 @@ ko: keywords: 키워드 statuses: 개별 게시물 statuses_hint_html: 이 필터는 아래의 키워드에 매칭되는지 여부와 관계 없이 몇몇개의 게시물들에 별개로 적용되었습니다. <a href="%{path}">검토하거나 필터에서 삭제하세요</a> - title: 필터 수정 + title: 필터 편집 errors: deprecated_api_multiple_keywords: 이 파라미터들은 하나를 초과하는 필터 키워드에 적용되기 때문에 이 응용프로그램에서 수정될 수 없습니다. 더 최신의 응용프로그램이나 웹 인터페이스를 사용하세요. invalid_context: 컨텍스트가 없거나 올바르지 않습니다 @@ -1613,7 +1613,7 @@ ko: back: 마스토돈으로 돌아가기 delete: 계정 삭제 development: 개발 - edit_profile: 프로필 수정 + edit_profile: 프로필 편집 export: 데이터 내보내기 featured_tags: 추천 해시태그 import: 데이터 가져오기 @@ -1779,7 +1779,7 @@ ko: statuses: '인용된 게시물:' subject: delete_statuses: 당신의 계정 %{acct}에서 작성한 게시물이 삭제되었습니다 - disable: 당신의 계정 %{acct}가 동결 되었습니다 + disable: "%{acct} 계정은 동결되었습니다." mark_statuses_as_sensitive: "%{acct}로 작성한 당신의 게시물은 민감한 것으로 표시되었습니다" none: "%{acct}에게의 경고" sensitive: "%{acct}로 작성되는 당신의 게시물은 이제부터 민감한 것으로 표시됩니다" @@ -1787,7 +1787,7 @@ ko: suspend: 당신의 계정 %{acct}가 정지 되었습니다 title: delete_statuses: 게시물 삭제됨 - disable: 계정 동결 됨 + disable: 계정 동결됨 mark_statuses_as_sensitive: 게시물이 민감함으로 표시됨 none: 경고 sensitive: 계정이 민감함으로 표시됨 diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml index 7372be719..4da58e6c6 100644 --- a/config/locales/simple_form.ko.yml +++ b/config/locales/simple_form.ko.yml @@ -176,7 +176,7 @@ ko: text: 이 결정을 번복해야만 하는 이유가 무엇입니까 defaults: autofollow: 초대를 통한 팔로우 - avatar: 프로필 그림 + avatar: 프로필 사진 bot: 이것은 자동화된 계정입니다 chosen_languages: 언어 필터링 confirm_new_password: 암호 다시 입력 @@ -188,7 +188,7 @@ ko: email: 이메일 주소 expires_in: 만기 fields: 부가 필드 - header: 헤더 그림 + header: 헤더 사진 honeypot: "%{label} (채우지 마시오)" inbox_url: 릴레이 서버의 inbox URL irreversible: 숨기는 대신 삭제 From 973597c6f1e25b16c592e5573304319aeaa375e1 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 23 Nov 2023 04:43:43 -0500 Subject: [PATCH 109/255] Consolidate configuration of `Sidekiq::Testing.fake!` setup (#28046) --- .../api/v1/statuses/reblogs_controller_spec.rb | 8 +------- .../settings/exports_controller_spec.rb | 10 ++++------ spec/lib/activitypub/activity/create_spec.rb | 9 +-------- spec/models/admin/account_action_spec.rb | 10 ++++------ spec/rails_helper.rb | 7 +++++++ .../api/v1/statuses/favourites_spec.rb | 8 +------- spec/services/bulk_import_service_spec.rb | 9 +-------- spec/services/update_status_service_spec.rb | 6 ++---- spec/workers/move_worker_spec.rb | 18 ++++++------------ .../poll_expiration_notify_worker_spec.rb | 8 +------- 10 files changed, 28 insertions(+), 65 deletions(-) diff --git a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb index 2f2b30b07..e3a9bdb50 100644 --- a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb @@ -9,13 +9,7 @@ describe Api::V1::Statuses::ReblogsController do let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:statuses', application: app) } - context 'with an oauth token' do - around do |example| - Sidekiq::Testing.fake! do - example.run - end - end - + context 'with an oauth token', :sidekiq_fake do before do allow(controller).to receive(:doorkeeper_token) { token } end diff --git a/spec/controllers/settings/exports_controller_spec.rb b/spec/controllers/settings/exports_controller_spec.rb index c8c11c3be..0bd1e80c3 100644 --- a/spec/controllers/settings/exports_controller_spec.rb +++ b/spec/controllers/settings/exports_controller_spec.rb @@ -38,12 +38,10 @@ describe Settings::ExportsController do expect(response).to redirect_to(settings_export_path) end - it 'queues BackupWorker job by 1' do - Sidekiq::Testing.fake! do - expect do - post :create - end.to change(BackupWorker.jobs, :size).by(1) - end + it 'queues BackupWorker job by 1', :sidekiq_fake do + expect do + post :create + end.to change(BackupWorker.jobs, :size).by(1) end end end diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index 7594efd59..bdc1c45ea 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -23,7 +23,7 @@ RSpec.describe ActivityPub::Activity::Create do stub_request(:get, 'http://example.com/emojib.png').to_return(body: attachment_fixture('emojo.png'), headers: { 'Content-Type' => 'application/octet-stream' }) end - describe 'processing posts received out of order' do + describe 'processing posts received out of order', :sidekiq_fake do let(:follower) { Fabricate(:account, username: 'bob') } let(:object_json) do @@ -77,13 +77,6 @@ RSpec.describe ActivityPub::Activity::Create do follower.follow!(sender) end - around do |example| - Sidekiq::Testing.fake! do - example.run - Sidekiq::Worker.clear_all - end - end - it 'correctly processes posts and inserts them in timelines', :aggregate_failures do # Simulate a temporary failure preventing from fetching the parent post stub_request(:get, object_json[:id]).to_return(status: 500) diff --git a/spec/models/admin/account_action_spec.rb b/spec/models/admin/account_action_spec.rb index 604fe7318..5d64d565f 100644 --- a/spec/models/admin/account_action_spec.rb +++ b/spec/models/admin/account_action_spec.rb @@ -46,12 +46,10 @@ RSpec.describe Admin::AccountAction do expect(target_account).to be_suspended end - it 'queues Admin::SuspensionWorker by 1' do - Sidekiq::Testing.fake! do - expect do - subject - end.to change { Admin::SuspensionWorker.jobs.size }.by 1 - end + it 'queues Admin::SuspensionWorker by 1', :sidekiq_fake do + expect do + subject + end.to change { Admin::SuspensionWorker.jobs.size }.by 1 end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 1ca91c6cd..d30e7201c 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -95,6 +95,13 @@ RSpec.configure do |config| self.use_transactional_tests = true end + config.around(:each, :sidekiq_fake) do |example| + Sidekiq::Testing.fake! do + example.run + Sidekiq::Worker.clear_all + end + end + config.before :each, type: :cli do stub_stdout stub_reset_connection_pools diff --git a/spec/requests/api/v1/statuses/favourites_spec.rb b/spec/requests/api/v1/statuses/favourites_spec.rb index ac5e86f29..8f3e6e5c4 100644 --- a/spec/requests/api/v1/statuses/favourites_spec.rb +++ b/spec/requests/api/v1/statuses/favourites_spec.rb @@ -70,19 +70,13 @@ RSpec.describe 'Favourites' do end end - describe 'POST /api/v1/statuses/:status_id/unfavourite' do + describe 'POST /api/v1/statuses/:status_id/unfavourite', :sidekiq_fake do subject do post "/api/v1/statuses/#{status.id}/unfavourite", headers: headers end let(:status) { Fabricate(:status) } - around do |example| - Sidekiq::Testing.fake! do - example.run - end - end - it_behaves_like 'forbidden for wrong scope', 'read read:favourites' context 'with public status' do diff --git a/spec/services/bulk_import_service_spec.rb b/spec/services/bulk_import_service_spec.rb index 16d718815..3a3f95ccc 100644 --- a/spec/services/bulk_import_service_spec.rb +++ b/spec/services/bulk_import_service_spec.rb @@ -12,14 +12,7 @@ RSpec.describe BulkImportService do import.update(total_items: import.rows.count) end - describe '#call' do - around do |example| - Sidekiq::Testing.fake! do - example.run - Sidekiq::Worker.clear_all - end - end - + describe '#call', :sidekiq_fake do context 'when importing follows' do let(:import_type) { 'following' } let(:overwrite) { false } diff --git a/spec/services/update_status_service_spec.rb b/spec/services/update_status_service_spec.rb index eb38230b0..7f9f746c2 100644 --- a/spec/services/update_status_service_spec.rb +++ b/spec/services/update_status_service_spec.rb @@ -111,7 +111,7 @@ RSpec.describe UpdateStatusService, type: :service do end end - context 'when poll changes' do + context 'when poll changes', :sidekiq_fake do let(:account) { Fabricate(:account) } let!(:status) { Fabricate(:status, text: 'Foo', account: account, poll_attributes: { options: %w(Foo Bar), account: account, multiple: false, hide_totals: false, expires_at: 7.days.from_now }) } let!(:poll) { status.poll } @@ -120,9 +120,7 @@ RSpec.describe UpdateStatusService, type: :service do before do status.update(poll: poll) VoteService.new.call(voter, poll, [0]) - Sidekiq::Testing.fake! do - subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i }) - end + subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i }) end it 'updates poll' do diff --git a/spec/workers/move_worker_spec.rb b/spec/workers/move_worker_spec.rb index 774296fda..34b342710 100644 --- a/spec/workers/move_worker_spec.rb +++ b/spec/workers/move_worker_spec.rb @@ -159,12 +159,9 @@ describe MoveWorker do describe '#perform' do context 'when both accounts are distant' do - it 'calls UnfollowFollowWorker' do - Sidekiq::Testing.fake! do - subject.perform(source_account.id, target_account.id) - expect(UnfollowFollowWorker).to have_enqueued_sidekiq_job(local_follower.id, source_account.id, target_account.id, false) - Sidekiq::Worker.drain_all - end + it 'calls UnfollowFollowWorker', :sidekiq_fake do + subject.perform(source_account.id, target_account.id) + expect(UnfollowFollowWorker).to have_enqueued_sidekiq_job(local_follower.id, source_account.id, target_account.id, false) end include_examples 'common tests' @@ -173,12 +170,9 @@ describe MoveWorker do context 'when target account is local' do let(:target_account) { Fabricate(:account) } - it 'calls UnfollowFollowWorker' do - Sidekiq::Testing.fake! do - subject.perform(source_account.id, target_account.id) - expect(UnfollowFollowWorker).to have_enqueued_sidekiq_job(local_follower.id, source_account.id, target_account.id, true) - Sidekiq::Worker.clear_all - end + it 'calls UnfollowFollowWorker', :sidekiq_fake do + subject.perform(source_account.id, target_account.id) + expect(UnfollowFollowWorker).to have_enqueued_sidekiq_job(local_follower.id, source_account.id, target_account.id, true) end include_examples 'common tests' diff --git a/spec/workers/poll_expiration_notify_worker_spec.rb b/spec/workers/poll_expiration_notify_worker_spec.rb index 78cbc1ee4..ca36a3759 100644 --- a/spec/workers/poll_expiration_notify_worker_spec.rb +++ b/spec/workers/poll_expiration_notify_worker_spec.rb @@ -10,13 +10,7 @@ describe PollExpirationNotifyWorker do let(:remote?) { false } let(:poll_vote) { Fabricate(:poll_vote, poll: poll) } - describe '#perform' do - around do |example| - Sidekiq::Testing.fake! do - example.run - end - end - + describe '#perform', :sidekiq_fake do it 'runs without error for missing record' do expect { worker.perform(nil) }.to_not raise_error end From 7877fcd83ce13309b5752a7766b93f65e71313bc Mon Sep 17 00:00:00 2001 From: Kevin Bongart <154600+KevinBongart@users.noreply.github.com> Date: Thu, 23 Nov 2023 05:00:09 -0500 Subject: [PATCH 110/255] Deduplicate IDs in relationships and familiar_followers APIs (#27982) --- .../v1/accounts/familiar_followers_controller.rb | 2 +- .../api/v1/accounts/relationships_controller.rb | 7 ++----- .../familiar_followers_controller_spec.rb | 12 ++++++++++++ .../api/v1/accounts/relationships_spec.rb | 16 ++++++++++++++++ 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/v1/accounts/familiar_followers_controller.rb b/app/controllers/api/v1/accounts/familiar_followers_controller.rb index b0bd8018a..a49eb2eb2 100644 --- a/app/controllers/api/v1/accounts/familiar_followers_controller.rb +++ b/app/controllers/api/v1/accounts/familiar_followers_controller.rb @@ -12,7 +12,7 @@ class Api::V1::Accounts::FamiliarFollowersController < Api::BaseController private def set_accounts - @accounts = Account.without_suspended.where(id: account_ids).select('id, hide_collections').index_by(&:id).values_at(*account_ids).compact + @accounts = Account.without_suspended.where(id: account_ids).select('id, hide_collections') end def familiar_followers diff --git a/app/controllers/api/v1/accounts/relationships_controller.rb b/app/controllers/api/v1/accounts/relationships_controller.rb index 320084efb..e5ae5b007 100644 --- a/app/controllers/api/v1/accounts/relationships_controller.rb +++ b/app/controllers/api/v1/accounts/relationships_controller.rb @@ -5,11 +5,8 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController before_action :require_user! def index - scope = Account.where(id: account_ids).select('id') - scope.merge!(Account.without_suspended) unless truthy_param?(:with_suspended) - # .where doesn't guarantee that our results are in the same order - # we requested them, so return the "right" order to the requestor. - @accounts = scope.index_by(&:id).values_at(*account_ids).compact + @accounts = Account.where(id: account_ids).select('id') + @accounts.merge!(Account.without_suspended) unless truthy_param?(:with_suspended) render json: @accounts, each_serializer: REST::RelationshipSerializer, relationships: relationships end diff --git a/spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb b/spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb index bb075261f..226177309 100644 --- a/spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb @@ -19,5 +19,17 @@ describe Api::V1::Accounts::FamiliarFollowersController do expect(response).to have_http_status(200) end + + context 'when there are duplicate account IDs in the params' do + let(:account_a) { Fabricate(:account) } + let(:account_b) { Fabricate(:account) } + + it 'removes duplicate account IDs from params' do + account_ids = [account_a, account_b, account_b, account_a, account_a].map { |a| a.id.to_s } + get :index, params: { id: account_ids } + + expect(body_as_json.pluck(:id)).to eq [account_a.id.to_s, account_b.id.to_s] + end + end end end diff --git a/spec/requests/api/v1/accounts/relationships_spec.rb b/spec/requests/api/v1/accounts/relationships_spec.rb index e06ffdfae..cea45168a 100644 --- a/spec/requests/api/v1/accounts/relationships_spec.rb +++ b/spec/requests/api/v1/accounts/relationships_spec.rb @@ -79,6 +79,22 @@ describe 'GET /api/v1/accounts/relationships' do end end + context 'when there are duplicate IDs in the params' do + let(:params) { { id: [simon.id, lewis.id, lewis.id, lewis.id, simon.id] } } + + it 'removes duplicate account IDs from params' do + subject + + expect(body_as_json) + .to be_an(Enumerable) + .and have_attributes( + size: 2, + first: include(simon_item), + second: include(lewis_item) + ) + end + end + def simon_item { id: simon.id.to_s, From 1ee3314f58d2e3d33a819080d6b9f44bd9497fdc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 11:28:52 +0100 Subject: [PATCH 111/255] Update dependency @types/npmlog to v7 (#28048) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- streaming/package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/streaming/package.json b/streaming/package.json index a474e6226..aecc5752e 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -28,7 +28,7 @@ }, "devDependencies": { "@types/express": "^4.17.17", - "@types/npmlog": "^4.1.4", + "@types/npmlog": "^7.0.0", "@types/pg": "^8.6.6", "@types/uuid": "^9.0.0" }, diff --git a/yarn.lock b/yarn.lock index efbde6641..3275d1235 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2466,7 +2466,7 @@ __metadata: resolution: "@mastodon/streaming@workspace:streaming" dependencies: "@types/express": "npm:^4.17.17" - "@types/npmlog": "npm:^4.1.4" + "@types/npmlog": "npm:^7.0.0" "@types/pg": "npm:^8.6.6" "@types/uuid": "npm:^9.0.0" bufferutil: "npm:^4.0.7" @@ -3276,12 +3276,12 @@ __metadata: languageName: node linkType: hard -"@types/npmlog@npm:^4.1.4": - version: 4.1.6 - resolution: "@types/npmlog@npm:4.1.6" +"@types/npmlog@npm:^7.0.0": + version: 7.0.0 + resolution: "@types/npmlog@npm:7.0.0" dependencies: "@types/node": "npm:*" - checksum: 432bfb14b29a383e095e099b2ddff4266051b43bc6c7ea242d10194acde2f1181a1e967bbb543f07979dd77743ead1954abac1128ec78cc2b86a5f7ea841ddcb + checksum: e94cb1d7dc6b1251d58d0a3cbf0c5b9e9b7c7649774cf816b9277fc10e1a09e65f2854357c4972d04d477f8beca3c8accb5e8546d594776e59e35ddfee79aff2 languageName: node linkType: hard From bf7e8e81de77d0091667102d77dee608ad1f8788 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 11:37:05 +0100 Subject: [PATCH 112/255] Update dependency doorkeeper to v5.6.7 (#28051) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index abd1b8499..1c4f628f1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -245,7 +245,7 @@ GEM docile (1.4.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - doorkeeper (5.6.6) + doorkeeper (5.6.7) railties (>= 5) dotenv (2.8.1) dotenv-rails (2.8.1) From 19baf2268359fdcaa1af3fa707ca0cc899db24a5 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 23 Nov 2023 07:32:50 -0500 Subject: [PATCH 113/255] Add missing email previews for `AdminMailer` (#28044) --- spec/mailers/previews/admin_mailer_preview.rb | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/spec/mailers/previews/admin_mailer_preview.rb b/spec/mailers/previews/admin_mailer_preview.rb index bc8f0193b..942d40d56 100644 --- a/spec/mailers/previews/admin_mailer_preview.rb +++ b/spec/mailers/previews/admin_mailer_preview.rb @@ -3,6 +3,16 @@ # Preview all emails at http://localhost:3000/rails/mailers/admin_mailer class AdminMailerPreview < ActionMailer::Preview + # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_report + def new_report + AdminMailer.with(recipient: Account.first).new_report(Report.first) + end + + # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_appeal + def new_appeal + AdminMailer.with(recipient: Account.first).new_appeal(Appeal.first) + end + # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_pending_account def new_pending_account AdminMailer.with(recipient: Account.first).new_pending_account(User.pending.first) @@ -13,8 +23,13 @@ class AdminMailerPreview < ActionMailer::Preview AdminMailer.with(recipient: Account.first).new_trends(PreviewCard.joins(:trend).limit(3), Tag.limit(3), Status.joins(:trend).where(reblog_of_id: nil).limit(3)) end - # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_appeal - def new_appeal - AdminMailer.with(recipient: Account.first).new_appeal(Appeal.first) + # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_software_updates + def new_software_updates + AdminMailer.with(recipient: Account.first).new_software_updates + end + + # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_critical_software_updates + def new_critical_software_updates + AdminMailer.with(recipient: Account.first).new_critical_software_updates end end From 6e7081984004accad08042f2391236129059a548 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Fri, 24 Nov 2023 10:27:54 +0100 Subject: [PATCH 114/255] Change search popout to not list unusable search options when logged out (#27918) --- .../mastodon/features/compose/components/search.jsx | 11 ++++++++--- app/javascript/mastodon/locales/en.json | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/features/compose/components/search.jsx b/app/javascript/mastodon/features/compose/components/search.jsx index caae965a6..5d55330dc 100644 --- a/app/javascript/mastodon/features/compose/components/search.jsx +++ b/app/javascript/mastodon/features/compose/components/search.jsx @@ -275,6 +275,7 @@ class Search extends PureComponent { } _calculateOptions (value) { + const { signedIn } = this.context.identity; const trimmedValue = value.trim(); const options = []; @@ -299,7 +300,7 @@ class Search extends PureComponent { const couldBeStatusSearch = searchEnabled; - if (couldBeStatusSearch) { + if (couldBeStatusSearch && signedIn) { options.push({ key: 'status-search', label: <FormattedMessage id='search.quick_action.status_search' defaultMessage='Posts matching {x}' values={{ x: <mark>{trimmedValue}</mark> }} />, action: this.handleStatusSearch }); } @@ -376,7 +377,7 @@ class Search extends PureComponent { <h4><FormattedMessage id='search_popout.options' defaultMessage='Search options' /></h4> - {searchEnabled ? ( + {searchEnabled && signedIn ? ( <div className='search__popout__menu'> {this.defaultOptions.map(({ key, label, action }, i) => ( <button key={key} onMouseDown={action} className={classNames('search__popout__menu__item', { selected: selectedOption === ((options.length || recent.size) + i) })}> @@ -386,7 +387,11 @@ class Search extends PureComponent { </div> ) : ( <div className='search__popout__menu__message'> - <FormattedMessage id='search_popout.full_text_search_disabled_message' defaultMessage='Not available on {domain}.' values={{ domain }} /> + {searchEnabled ? ( + <FormattedMessage id='search_popout.full_text_search_logged_out_message' defaultMessage='Only available when logged in.' /> + ) : ( + <FormattedMessage id='search_popout.full_text_search_disabled_message' defaultMessage='Not available on {domain}.' values={{ domain }} /> + )} </div> )} </div> diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index ed8bfe166..05d7d1656 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Posts matching {x}", "search.search_or_paste": "Search or paste URL", "search_popout.full_text_search_disabled_message": "Not available on {domain}.", + "search_popout.full_text_search_logged_out_message": "Only available when logged in.", "search_popout.language_code": "ISO language code", "search_popout.options": "Search options", "search_popout.quick_actions": "Quick actions", From 3a24754229cf1d34972bdbbdea22d86ef6ed8291 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Fri, 24 Nov 2023 10:31:28 +0100 Subject: [PATCH 115/255] Change GIF max matrix size error to explicitly mention GIF files (#27927) --- app/models/concerns/attachmentable.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/models/concerns/attachmentable.rb b/app/models/concerns/attachmentable.rb index c0ee1bdce..4cdbdeb47 100644 --- a/app/models/concerns/attachmentable.rb +++ b/app/models/concerns/attachmentable.rb @@ -52,9 +52,13 @@ module Attachmentable return if attachment.blank? || !/image.*/.match?(attachment.content_type) || attachment.queued_for_write[:original].blank? width, height = FastImage.size(attachment.queued_for_write[:original].path) - matrix_limit = attachment.content_type == 'image/gif' ? GIF_MATRIX_LIMIT : MAX_MATRIX_LIMIT + return unless width.present? && height.present? - raise Mastodon::DimensionsValidationError, "#{width}x#{height} images are not supported" if width.present? && height.present? && (width * height > matrix_limit) + if attachment.content_type == 'image/gif' && width * height > GIF_MATRIX_LIMIT + raise Mastodon::DimensionsValidationError, "#{width}x#{height} GIF files are not supported" + elsif width * height > MAX_MATRIX_LIMIT + raise Mastodon::DimensionsValidationError, "#{width}x#{height} images are not supported" + end end def appropriate_extension(attachment) From 852123867768e23410af5bd07ac0327bead0d9b2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:25:39 +0100 Subject: [PATCH 116/255] New Crowdin Translations (automated) (#28060) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/ca.json | 16 +++++++++++++++- app/javascript/mastodon/locales/es-MX.json | 4 ++-- config/locales/ca.yml | 6 ++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 926343f67..9ea2ab33c 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -21,6 +21,7 @@ "account.blocked": "Blocat", "account.browse_more_on_origin_server": "Explora'n més al perfil original", "account.cancel_follow_request": "Cancel·la el seguiment", + "account.copy": "Copia l'enllaç al perfil", "account.direct": "Menciona privadament @{name}", "account.disable_notifications": "Deixa de notificar-me els tuts de @{name}", "account.domain_blocked": "Domini blocat", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marca com a llegida", "conversation.open": "Mostra la conversa", "conversation.with": "Amb {names}", + "copy_icon_button.copied": "Copiat al porta-retalls", "copypaste.copied": "Copiat", "copypaste.copy_to_clipboard": "Copia al porta-retalls", "directory.federated": "Del fedivers conegut", @@ -222,7 +224,7 @@ "emoji_button.search_results": "Resultats de la cerca", "emoji_button.symbols": "Símbols", "emoji_button.travel": "Viatges i llocs", - "empty_column.account_hides_collections": "Aquest usuari ha elegit no mostrar aquesta informació", + "empty_column.account_hides_collections": "Aquest usuari ha decidit no mostrar aquesta informació", "empty_column.account_suspended": "Compte suspès", "empty_column.account_timeline": "No hi ha tuts aquí!", "empty_column.account_unavailable": "Perfil no disponible", @@ -390,6 +392,7 @@ "lists.search": "Cerca entre les persones que segueixes", "lists.subheading": "Les teves llistes", "load_pending": "{count, plural, one {# element nou} other {# elements nous}}", + "loading_indicator.label": "Es carrega…", "media_gallery.toggle_visible": "{number, plural, one {Amaga la imatge} other {Amaga les imatges}}", "moved_to_account_banner.text": "El teu compte {disabledAccount} està desactivat perquè l'has mogut a {movedToAccount}.", "mute_modal.duration": "Durada", @@ -478,6 +481,16 @@ "onboarding.follows.empty": "Malauradament, cap resultat pot ser mostrat ara mateix. Pots provar de fer servir la cerca o visitar la pàgina Explora per a trobar gent a qui seguir o provar-ho de nou més tard.", "onboarding.follows.lead": "La teva línia de temps inici només està a les teves mans. Com més gent segueixis, més activa i interessant serà. Aquests perfils poden ser un bon punt d'inici—sempre pots acabar deixant de seguir-los!:", "onboarding.follows.title": "Personalitza la pantalla d'inci", + "onboarding.profile.discoverable": "Fes el meu perfil descobrible", + "onboarding.profile.display_name": "Nom que es mostrarà", + "onboarding.profile.display_name_hint": "El teu nom complet o el teu malnom…", + "onboarding.profile.lead": "Sempre ho pots completar més endavant a la configuració, on hi ha encara més opcions disponibles.", + "onboarding.profile.note": "Biografia", + "onboarding.profile.note_hint": "Pots @mencionar altra gent o #etiquetes…", + "onboarding.profile.save_and_continue": "Desa i continua", + "onboarding.profile.title": "Configuració del perfil", + "onboarding.profile.upload_avatar": "Importa una foto de perfil", + "onboarding.profile.upload_header": "Importa una capçalera de perfil", "onboarding.share.lead": "Permet que la gent sàpiga com trobar-te a Mastodon!", "onboarding.share.message": "Sóc {username} a #Mastodon! Vine i segueix-me a {url}", "onboarding.share.next_steps": "Possibles passes següents:", @@ -521,6 +534,7 @@ "privacy.unlisted.short": "No llistada", "privacy_policy.last_updated": "Darrera actualització {date}", "privacy_policy.title": "Política de Privacitat", + "recommended": "Recomanat", "refresh": "Actualitza", "regeneration_indicator.label": "Es carrega…", "regeneration_indicator.sublabel": "Es prepara la teva línia de temps d'Inici!", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 448a3ae91..83ff3debb 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -481,8 +481,8 @@ "onboarding.follows.empty": "Desafortunadamente, no se pueden mostrar resultados en este momento. Puedes intentar usar la búsqueda o navegar por la página de exploración para encontrar gente a la que seguir, o inténtalo de nuevo más tarde.", "onboarding.follows.lead": "Tienes que personalizar tu inicio. Cuantas más personas sigas, más activo e interesante será. Estos perfiles pueden ser un buen punto de partida, ¡pero siempre puedes dejar de seguirlos más adelante!", "onboarding.follows.title": "Popular en Mastodon", - "onboarding.profile.discoverable": "Hacer que mi perfil aparezca en búsquedas", - "onboarding.profile.discoverable_hint": "Cuando permites que tu perfil aparezca en búsquedas en Mastodon, tus publicaciones podrán aparecer en los resultados de búsqueda y en tendencias, y tu perfil podrá recomendarse a gente con intereses similares a los tuyos.", + "onboarding.profile.discoverable": "Make my profile discoverable", + "onboarding.profile.discoverable_hint": "Cuando aceptas ser descubierto en Mastodon, tus publicaciones pueden aparecer en resultados de búsqueda y tendencias, y tu perfil puede ser sugerido a personas con intereses similares a los tuyos.", "onboarding.profile.display_name": "Nombre a mostrar", "onboarding.profile.display_name_hint": "Tu nombre completo o tu apodo…", "onboarding.profile.lead": "Siempre puedes completar esto más tarde en los ajustes, donde hay aún más opciones de personalización disponibles.", diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 4dc3202a0..85b444c28 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -1038,6 +1038,10 @@ ca: hint_html: Una cosa més! Necessitem confirmar que ets una persona humana (és així com mantenim a ratlla l'spam). Resolt el CAPTCHA inferior i clica a "Segueix". title: Revisió de seguretat confirmations: + clicking_this_link: en clicar aquest enllaç + login_link: inici de sessió + proceed_to_login_html: Ara pots passar a %{login_link}. + welcome_title: Hola, %{name}! wrong_email_hint: Si aquesta adreça de correu electrònic no és correcte, pots canviar-la en els ajustos del compte. delete_account: Elimina el compte delete_account_html: Si vols suprimir el compte pots <a href="%{path}">fer-ho aquí</a>. Se't demanarà confirmació. @@ -1569,6 +1573,8 @@ ca: over_daily_limit: Has superat el límit de %{limit} tuts programats per a avui over_total_limit: Has superat el límit de %{limit} tuts programats too_soon: La data programada ha de ser futura + self_destruct: + title: Aquest servidor tancarà sessions: activity: Última activitat browser: Navegador From fad9343bab37cd6de340b4cdd7c427730741e214 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 11:06:35 +0100 Subject: [PATCH 117/255] New Crowdin Translations (automated) (#28069) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/af.json | 3 + app/javascript/mastodon/locales/be.json | 1 + app/javascript/mastodon/locales/bg.json | 1 + app/javascript/mastodon/locales/ca.json | 1 + app/javascript/mastodon/locales/da.json | 1 + app/javascript/mastodon/locales/de.json | 1 + app/javascript/mastodon/locales/es-AR.json | 1 + app/javascript/mastodon/locales/es-MX.json | 1 + app/javascript/mastodon/locales/es.json | 1 + app/javascript/mastodon/locales/et.json | 15 +++ app/javascript/mastodon/locales/eu.json | 13 +-- app/javascript/mastodon/locales/fi.json | 3 +- app/javascript/mastodon/locales/fo.json | 1 + app/javascript/mastodon/locales/fr-QC.json | 11 ++- app/javascript/mastodon/locales/fr.json | 11 ++- app/javascript/mastodon/locales/fy.json | 16 ++++ app/javascript/mastodon/locales/gl.json | 1 + app/javascript/mastodon/locales/he.json | 1 + app/javascript/mastodon/locales/hu.json | 1 + app/javascript/mastodon/locales/is.json | 1 + app/javascript/mastodon/locales/it.json | 1 + app/javascript/mastodon/locales/ko.json | 1 + app/javascript/mastodon/locales/lt.json | 1 + app/javascript/mastodon/locales/nl.json | 15 +-- app/javascript/mastodon/locales/pl.json | 1 + app/javascript/mastodon/locales/pt-BR.json | 1 + app/javascript/mastodon/locales/pt-PT.json | 1 + app/javascript/mastodon/locales/sl.json | 1 + app/javascript/mastodon/locales/sr-Latn.json | 1 + app/javascript/mastodon/locales/sr.json | 1 + app/javascript/mastodon/locales/sv.json | 1 + app/javascript/mastodon/locales/tr.json | 1 + app/javascript/mastodon/locales/uk.json | 1 + app/javascript/mastodon/locales/vi.json | 1 + app/javascript/mastodon/locales/zh-CN.json | 1 + app/javascript/mastodon/locales/zh-HK.json | 1 + app/javascript/mastodon/locales/zh-TW.json | 3 +- config/locales/ca.yml | 5 + config/locales/et.yml | 2 +- config/locales/fy.yml | 1 + config/locales/lt.yml | 98 ++++++++++++++------ config/locales/nl.yml | 2 +- config/locales/simple_form.et.yml | 4 +- config/locales/zh-TW.yml | 2 +- 44 files changed, 180 insertions(+), 52 deletions(-) diff --git a/app/javascript/mastodon/locales/af.json b/app/javascript/mastodon/locales/af.json index 6f7f355fc..d3cc40c60 100644 --- a/app/javascript/mastodon/locales/af.json +++ b/app/javascript/mastodon/locales/af.json @@ -250,6 +250,9 @@ "notifications.column_settings.unread_notifications.highlight": "Lig ongelese kennisgewings uit", "notifications.filter.boosts": "Aangestuurde plasings", "notifications.group": "{count} kennisgewings", + "notifications.permission_denied_alert": "Lessenaarkennisgewings kan nie geaktiveer word nie omdat 'n webblaaier toegewing voorheen geweier was", + "notifications_permission_banner.enable": "Aktiveer lessenaarkennissgewings", + "notifications_permission_banner.how_to_control": "Om kennisgewings te ontvang wanner Mastodon nie oop is nie, aktiveer lessenaarkennisgewings. Jy kan beheer watter spesifieke tipe interaksies lessenaarkennisgewings genereer deur die {icon} knoppie hier bo sodra hulle geaktiveer is.", "onboarding.actions.go_to_explore": "See what's trending", "onboarding.actions.go_to_home": "Go to your home feed", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 06a329a8b..f94a8b79f 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Супадзенне паведамленняў {x}", "search.search_or_paste": "Пошук", "search_popout.full_text_search_disabled_message": "Недаступна на {domain}.", + "search_popout.full_text_search_logged_out_message": "Даступна толькі пры ўваходзе ў сістэму.", "search_popout.language_code": "ISO код мовы", "search_popout.options": "Параметры пошуку", "search_popout.quick_actions": "Хуткія дзеянні", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index ccbd1042d..f57d868c7 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Съвпадение на публикации {x}", "search.search_or_paste": "Търсене или поставяне на URL адрес", "search_popout.full_text_search_disabled_message": "Не е достъпно на {domain}.", + "search_popout.full_text_search_logged_out_message": "Достъпно само при влизане в системата.", "search_popout.language_code": "Код на езика по ISO", "search_popout.options": "Възможности при търсене", "search_popout.quick_actions": "Бързи действия", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 9ea2ab33c..87121b7c5 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -605,6 +605,7 @@ "search.quick_action.status_search": "Tuts coincidint amb {x}", "search.search_or_paste": "Cerca o escriu l'URL", "search_popout.full_text_search_disabled_message": "No disponible a {domain}.", + "search_popout.full_text_search_logged_out_message": "Només disponible en iniciar la sessió.", "search_popout.language_code": "Codi de llengua ISO", "search_popout.options": "Opcions de cerca", "search_popout.quick_actions": "Accions ràpides", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index 577d77782..04fc43734 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Indlæg matchende {x}", "search.search_or_paste": "Søg efter eller angiv URL", "search_popout.full_text_search_disabled_message": "Utilgængelig på {domain}.", + "search_popout.full_text_search_logged_out_message": "Kun tilgængelig, når logget ind.", "search_popout.language_code": "ISO-sprogkode", "search_popout.options": "Søgevalg", "search_popout.quick_actions": "Hurtige handlinger", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 7c0710efc..cf545e48c 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Beiträge passend zu {x}", "search.search_or_paste": "Suchen oder URL einfügen", "search_popout.full_text_search_disabled_message": "Auf {domain} nicht verfügbar.", + "search_popout.full_text_search_logged_out_message": "Nur verfügbar, wenn angemeldet.", "search_popout.language_code": "ISO-Sprachcode", "search_popout.options": "Suchoptionen", "search_popout.quick_actions": "Schnellaktionen", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index dfc00f1d8..4573f4ab9 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Mensajes que coinciden con {x}", "search.search_or_paste": "Buscar o pegar dirección web", "search_popout.full_text_search_disabled_message": "No disponible en {domain}.", + "search_popout.full_text_search_logged_out_message": "Solo disponible al iniciar sesión.", "search_popout.language_code": "Código ISO de idioma", "search_popout.options": "Opciones de búsqueda", "search_popout.quick_actions": "Acciones rápidas", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 83ff3debb..f7cd1b330 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Publicaciones que coinciden con {x}", "search.search_or_paste": "Buscar o pegar URL", "search_popout.full_text_search_disabled_message": "No disponible en {domain}.", + "search_popout.full_text_search_logged_out_message": "Solo disponible si inicias sesión.", "search_popout.language_code": "Código de idioma ISO", "search_popout.options": "Opciones de búsqueda", "search_popout.quick_actions": "Acciones rápidas", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 9850bf039..bbc8bcc75 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Publicaciones que coinciden con {x}", "search.search_or_paste": "Buscar o pegar URL", "search_popout.full_text_search_disabled_message": "No disponible en {domain}.", + "search_popout.full_text_search_logged_out_message": "Solo disponible si inicias sesión.", "search_popout.language_code": "Código de idioma ISO", "search_popout.options": "Opciones de búsqueda", "search_popout.quick_actions": "Acciones rápidas", diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index 3b6d86a9d..a67aa6fee 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -21,6 +21,7 @@ "account.blocked": "Blokeeritud", "account.browse_more_on_origin_server": "Vaata rohkem algsel profiilil", "account.cancel_follow_request": "Võta jälgimistaotlus tagasi", + "account.copy": "Kopeeri link profiili", "account.direct": "Maini privaatselt @{name}", "account.disable_notifications": "Peata teavitused @{name} postitustest", "account.domain_blocked": "Domeen peidetud", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Märgi loetuks", "conversation.open": "Vaata vestlust", "conversation.with": "Koos {names}", + "copy_icon_button.copied": "Kopeeritud vahemällu", "copypaste.copied": "Kopeeritud", "copypaste.copy_to_clipboard": "Kopeeri vahemällu", "directory.federated": "Tuntud födiversumist", @@ -390,6 +392,7 @@ "lists.search": "Otsi enda jälgitavate inimeste hulgast", "lists.subheading": "Sinu nimekirjad", "load_pending": "{count, plural, one {# uus kirje} other {# uut kirjet}}", + "loading_indicator.label": "Laadimine…", "media_gallery.toggle_visible": "{number, plural, one {Varja pilt} other {Varja pildid}}", "moved_to_account_banner.text": "Kontot {disabledAccount} ei ole praegu võimalik kasutada, sest kolisid kontole {movedToAccount}.", "mute_modal.duration": "Kestus", @@ -478,6 +481,17 @@ "onboarding.follows.empty": "Kahjuks ei saa hetkel tulemusi näidata. Proovi kasutada otsingut või lehitse uurimise lehte, et leida inimesi, keda jälgida, või proovi hiljem uuesti.", "onboarding.follows.lead": "Haldad ise oma koduvoogu. Mida rohkemaid inimesi jälgid, seda aktiivsem ja huvitavam see on. Need profiilid võiksid olla head alustamiskohad — saad nende jälgimise alati lõpetada!", "onboarding.follows.title": "Populaarne Mastodonis", + "onboarding.profile.discoverable": "Muuda mu profiil avastatavaks", + "onboarding.profile.discoverable_hint": "Kui nõustud enda avastamisega Mastodonis, võivad sinu postitused ilmuda otsingutulemustes ja trendides ning sinu profiili võidakse soovitada sinuga sarnaste huvidega inimestele.", + "onboarding.profile.display_name": "Näidatav nimi", + "onboarding.profile.display_name_hint": "Su täisnimi või naljanimi…", + "onboarding.profile.lead": "Saad selle alati hiljem seadetes lõpuni viia, kus on saadaval veel rohkem kohandamisvalikuid.", + "onboarding.profile.note": "Elulugu", + "onboarding.profile.note_hint": "Saad @mainida teisi kasutajaid või #sildistada…", + "onboarding.profile.save_and_continue": "Salvesta ja jätka", + "onboarding.profile.title": "Profiili seadistamine", + "onboarding.profile.upload_avatar": "Laadi üles profiilipilt", + "onboarding.profile.upload_header": "Laadi üles profiili päis", "onboarding.share.lead": "Anna inimestele teada, kuidas sind Mastodonist üles leida!", "onboarding.share.message": "Ma olen #Mastodon võrgustikus {username}! tule ja jälgi mind aadressil {url}", "onboarding.share.next_steps": "Võimalikud järgmised sammud:", @@ -521,6 +535,7 @@ "privacy.unlisted.short": "Määramata", "privacy_policy.last_updated": "Viimati uuendatud {date}", "privacy_policy.title": "Isikuandmete kaitse", + "recommended": "Soovitatud", "refresh": "Värskenda", "regeneration_indicator.label": "Laeb…", "regeneration_indicator.sublabel": "Su koduvoog on ettevalmistamisel!", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index eb666a0ee..26ed7add1 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -16,17 +16,17 @@ "account.badges.bot": "Bot-a", "account.badges.group": "Taldea", "account.block": "Blokeatu @{name}", - "account.block_domain": "Ezkutatu {domain} domeinuko guztia", + "account.block_domain": "Blokeatu {domain} domeinua", "account.block_short": "Blokeatu", "account.blocked": "Blokeatuta", "account.browse_more_on_origin_server": "Arakatu gehiago jatorrizko profilean", "account.cancel_follow_request": "Baztertu jarraitzeko eskaera", "account.copy": "Kopiatu profilerako esteka", "account.direct": "Aipatu pribatuki @{name}", - "account.disable_notifications": "Utzi jakinarazteari @{name} erabiltzailearen bidalketetan", + "account.disable_notifications": "Utzi jakinarazteari @{name} erabiltzaileak argitaratzean", "account.domain_blocked": "Ezkutatutako domeinua", "account.edit_profile": "Aldatu profila", - "account.enable_notifications": "Jakinarazi @{name} erabiltzaileak bidalketak egitean", + "account.enable_notifications": "Jakinarazi @{name} erabiltzaileak argitaratzean", "account.endorse": "Nabarmendu profilean", "account.featured_tags.last_status_at": "Azken bidalketa {date} datan", "account.featured_tags.last_status_never": "Bidalketarik ez", @@ -40,7 +40,7 @@ "account.follows.empty": "Erabiltzaile honek ez du inor jarraitzen oraindik.", "account.follows_you": "Jarraitzen dizu", "account.go_to_profile": "Joan profilera", - "account.hide_reblogs": "Ezkutatu @{name}(r)en bultzadak", + "account.hide_reblogs": "Ezkutatu @{name} erabiltzailearen bultzadak", "account.in_memoriam": "Oroimenezkoa.", "account.joined_short": "Elkartuta", "account.languages": "Aldatu harpidetutako hizkuntzak", @@ -60,8 +60,8 @@ "account.report": "Salatu @{name}", "account.requested": "Onarpenaren zain. Egin klik jarraipen-eskaera ezeztatzeko", "account.requested_follow": "{name}-(e)k zu jarraitzeko eskaera egin du", - "account.share": "@{name}(e)ren profila elkarbanatu", - "account.show_reblogs": "Erakutsi @{name}(r)en bultzadak", + "account.share": "Partekatu @{name} erabiltzailearen profila", + "account.show_reblogs": "Erakutsi @{name} erabiltzailearen bultzadak", "account.statuses_counter": "{count, plural, one {Bidalketa {counter}} other {{counter} bidalketa}}", "account.unblock": "Desblokeatu @{name}", "account.unblock_domain": "Berriz erakutsi {domain}", @@ -606,6 +606,7 @@ "search.quick_action.status_search": "{x}-(r)ekin bat datozen argitalpenak", "search.search_or_paste": "Bilatu edo itsatsi URLa", "search_popout.full_text_search_disabled_message": "{domain}-en ez dago eskuragarri.", + "search_popout.full_text_search_logged_out_message": "Soilik erabilgarri saioa hastean.", "search_popout.language_code": "ISO hizkuntza-kodea", "search_popout.options": "Bilaketaren aukerak", "search_popout.quick_actions": "Ekintza azkarrak", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 7a07913f8..e99de4d03 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -482,7 +482,7 @@ "onboarding.follows.lead": "Kokoat oman kotisyötteesi itse. Mitä enemmän ihmisiä seuraat, sitä aktiivisempi ja kiinnostavampi syöte on. Nämä profiilit voivat olla alkuun hyvä lähtökohta — voit aina lopettaa niiden seuraamisen myöhemmin!", "onboarding.follows.title": "Mukauta kotisyötettäsi", "onboarding.profile.discoverable": "Aseta profiilini löydettäväksi", - "onboarding.profile.discoverable_hint": "Kun olet määrittänyt itsesi löydettäväksi Mastodonista, voivat julkaisusi näkyä hakutuloksissa ja suosituissa kohteissa, ja profiiliasi voidaan ehdottaa käyttäjille, jotka ovat kiinnostuneet samoista aiheista kuin sinä.", + "onboarding.profile.discoverable_hint": "Kun olet määrittänyt itsesi löydettäväksi Mastodonista, julkaisusi voivat näkyä hakutuloksissa ja suosituissa kohteissa ja profiiliasi voidaan ehdottaa käyttäjille, jotka ovat kiinnostuneet samoista aiheista kuin sinä.", "onboarding.profile.display_name": "Näyttönimi", "onboarding.profile.display_name_hint": "Koko nimesi tai lempinimesi…", "onboarding.profile.lead": "Voit viimeistellä tämän milloin tahansa asetuksista, jotka tarjoavat vielä enemmän mukautusvalintoja.", @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Julkaisut haulla {x}", "search.search_or_paste": "Hae tai liitä URL-osoite", "search_popout.full_text_search_disabled_message": "Ei saatavilla palvelimella {domain}.", + "search_popout.full_text_search_logged_out_message": "Saatavilla vain sisäänkirjautuneena.", "search_popout.language_code": "ISO-kielikoodi", "search_popout.options": "Hakuvalinnat", "search_popout.quick_actions": "Pikatoiminnot", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index aa99a0c30..45fafd15d 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -596,6 +596,7 @@ "search.quick_action.status_search": "Postar, ið samsvara {x}", "search.search_or_paste": "Leita ella set URL inn", "search_popout.full_text_search_disabled_message": "Ikki tøkt á {domain}.", + "search_popout.full_text_search_logged_out_message": "Einans tøkt um innritað er.", "search_popout.language_code": "ISO málkoda", "search_popout.options": "Leitimøguleikar", "search_popout.quick_actions": "Skjótar atgerðir", diff --git a/app/javascript/mastodon/locales/fr-QC.json b/app/javascript/mastodon/locales/fr-QC.json index 94ab5333c..e2067cc46 100644 --- a/app/javascript/mastodon/locales/fr-QC.json +++ b/app/javascript/mastodon/locales/fr-QC.json @@ -21,6 +21,7 @@ "account.blocked": "Bloqué·e", "account.browse_more_on_origin_server": "Parcourir davantage sur le profil original", "account.cancel_follow_request": "Retirer cette demande d'abonnement", + "account.copy": "Copier le lien vers le profil", "account.direct": "Mention privée @{name}", "account.disable_notifications": "Ne plus me notifier quand @{name} publie", "account.domain_blocked": "Domaine bloqué", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marquer comme lu", "conversation.open": "Afficher cette conversation", "conversation.with": "Avec {names}", + "copy_icon_button.copied": "Copié dans le presse-papier", "copypaste.copied": "Copié", "copypaste.copy_to_clipboard": "Copier dans le presse-papiers", "directory.federated": "D'un fediverse connu", @@ -479,12 +481,17 @@ "onboarding.follows.empty": "Malheureusement, aucun résultat ne peut être affiché pour le moment. Vous pouvez essayer de rechercher ou de parcourir la page \"Explorer\" pour trouver des personnes à suivre, ou réessayer plus tard.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.discoverable": "Rendre mon profil découvrable", + "onboarding.profile.discoverable_hint": "Lorsque vous acceptez d'être découvert sur Mastodon, vos messages peuvent apparaître dans les résultats de recherche et les tendances, et votre profil peut être suggéré à des personnes ayant des intérêts similaires aux vôtres.", "onboarding.profile.display_name": "Nom affiché", + "onboarding.profile.display_name_hint": "Votre nom complet ou votre nom rigolo…", + "onboarding.profile.lead": "Vous pouvez toujours compléter cela plus tard dans les paramètres. Vous y trouverez encore plus d'options de personnalisation.", "onboarding.profile.note": "Biographie", + "onboarding.profile.note_hint": "Vous pouvez @mentionner d'autres personnes ou #hashtags…", "onboarding.profile.save_and_continue": "Enregistrer et continuer", "onboarding.profile.title": "Configuration du profil", "onboarding.profile.upload_avatar": "Importer une photo de profil", - "onboarding.profile.upload_header": "Envoyer une image de profil", + "onboarding.profile.upload_header": "Importer un entête de profil", "onboarding.share.lead": "Faites savoir aux gens comment vous trouver sur Mastodon!", "onboarding.share.message": "Je suis {username} sur #Mastodon! Suivez-moi sur {url}", "onboarding.share.next_steps": "Étapes suivantes possibles:", @@ -528,6 +535,7 @@ "privacy.unlisted.short": "Non listé", "privacy_policy.last_updated": "Dernière mise à jour {date}", "privacy_policy.title": "Politique de confidentialité", + "recommended": "Recommandé", "refresh": "Actualiser", "regeneration_indicator.label": "Chargement…", "regeneration_indicator.sublabel": "Votre fil d'accueil est en cours de préparation!", @@ -598,6 +606,7 @@ "search.quick_action.status_search": "Publications correspondant à {x}", "search.search_or_paste": "Rechercher ou saisir un URL", "search_popout.full_text_search_disabled_message": "Non disponible sur {domain}.", + "search_popout.full_text_search_logged_out_message": "Disponible uniquement lorsque vous êtes connecté.", "search_popout.language_code": "code de langue ISO", "search_popout.options": "Options de recherche", "search_popout.quick_actions": "Actions rapides", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index f7b3fc1f0..03b656cc4 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -21,6 +21,7 @@ "account.blocked": "Bloqué·e", "account.browse_more_on_origin_server": "Parcourir davantage sur le profil original", "account.cancel_follow_request": "Annuler le suivi", + "account.copy": "Copier le lien vers le profil", "account.direct": "Mention privée @{name}", "account.disable_notifications": "Ne plus me notifier quand @{name} publie quelque chose", "account.domain_blocked": "Domaine bloqué", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marquer comme lu", "conversation.open": "Afficher la conversation", "conversation.with": "Avec {names}", + "copy_icon_button.copied": "Copié dans le presse-papier", "copypaste.copied": "Copié", "copypaste.copy_to_clipboard": "Copier dans le presse-papiers", "directory.federated": "Du fédiverse connu", @@ -479,12 +481,17 @@ "onboarding.follows.empty": "Malheureusement, aucun résultat ne peut être affiché pour le moment. Vous pouvez essayer d'utiliser la recherche ou parcourir la page de découverte pour trouver des personnes à suivre, ou réessayez plus tard.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Personnaliser votre flux principal", + "onboarding.profile.discoverable": "Rendre mon profil découvrable", + "onboarding.profile.discoverable_hint": "Lorsque vous acceptez d'être découvert sur Mastodon, vos messages peuvent apparaître dans les résultats de recherche et les tendances, et votre profil peut être suggéré à des personnes ayant des intérêts similaires aux vôtres.", "onboarding.profile.display_name": "Nom affiché", + "onboarding.profile.display_name_hint": "Votre nom complet ou votre nom rigolo…", + "onboarding.profile.lead": "Vous pouvez toujours compléter cela plus tard dans les paramètres. Vous y trouverez encore plus d'options de personnalisation.", "onboarding.profile.note": "Biographie", + "onboarding.profile.note_hint": "Vous pouvez @mentionner d'autres personnes ou #hashtags…", "onboarding.profile.save_and_continue": "Enregistrer et continuer", "onboarding.profile.title": "Configuration du profil", "onboarding.profile.upload_avatar": "Importer une photo de profil", - "onboarding.profile.upload_header": "Envoyer une image de profil", + "onboarding.profile.upload_header": "Importer un entête de profil", "onboarding.share.lead": "Faites savoir aux gens comment ils peuvent vous trouver sur Mastodon!", "onboarding.share.message": "Je suis {username} sur #Mastodon ! Suivez-moi sur {url}", "onboarding.share.next_steps": "Étapes suivantes possibles :", @@ -528,6 +535,7 @@ "privacy.unlisted.short": "Non listé", "privacy_policy.last_updated": "Dernière mise à jour {date}", "privacy_policy.title": "Politique de confidentialité", + "recommended": "Recommandé", "refresh": "Actualiser", "regeneration_indicator.label": "Chargement…", "regeneration_indicator.sublabel": "Votre fil principal est en cours de préparation !", @@ -598,6 +606,7 @@ "search.quick_action.status_search": "Publications correspondant à {x}", "search.search_or_paste": "Rechercher ou saisir une URL", "search_popout.full_text_search_disabled_message": "Non disponible sur {domain}.", + "search_popout.full_text_search_logged_out_message": "Disponible uniquement lorsque vous êtes connecté.", "search_popout.language_code": "code de langue ISO", "search_popout.options": "Options de recherche", "search_popout.quick_actions": "Actions rapides", diff --git a/app/javascript/mastodon/locales/fy.json b/app/javascript/mastodon/locales/fy.json index 2128a045b..2ec4a53bf 100644 --- a/app/javascript/mastodon/locales/fy.json +++ b/app/javascript/mastodon/locales/fy.json @@ -21,6 +21,7 @@ "account.blocked": "Blokkearre", "account.browse_more_on_origin_server": "Mear op it orizjinele profyl besjen", "account.cancel_follow_request": "Folchfersyk annulearje", + "account.copy": "Keppeling nei profyl kopiearje", "account.direct": "Privee fermelde @{name}", "account.disable_notifications": "Jou gjin melding mear wannear @{name} in berjocht pleatst", "account.domain_blocked": "Domein blokkearre", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "As lêzen markearje", "conversation.open": "Petear toane", "conversation.with": "Mei {names}", + "copy_icon_button.copied": "Nei klamboerd kopiearre", "copypaste.copied": "Kopiearre", "copypaste.copy_to_clipboard": "Nei klamboerd kopiearje", "directory.federated": "Fediverse (wat bekend is)", @@ -390,6 +392,7 @@ "lists.search": "Sykje nei minsken dy’t jo folgje", "lists.subheading": "Jo listen", "load_pending": "{count, plural, one {# nij item} other {# nije items}}", + "loading_indicator.label": "Lade…", "media_gallery.toggle_visible": "{number, plural, one {ôfbylding ferstopje} other {ôfbyldingen ferstopje}}", "moved_to_account_banner.text": "Omdat jo nei {movedToAccount} ferhuze binne is jo account {disabledAccount} op dit stuit útskeakele.", "mute_modal.duration": "Doer", @@ -478,6 +481,17 @@ "onboarding.follows.empty": "Spitigernôch kinne op dit stuit gjin resultaten toand wurde. Jo kinne probearje te sykjen of te blêdzjen troch de ferkenningsside om minsken te finen dy’t jo folgje kinne, of probearje it letter opnij.", "onboarding.follows.lead": "Jo beheare jo eigen startside. Hoe mear minsken jo folgje, hoe aktiver en ynteressanter it wêze sil. Dizze profilen kinne in goed startpunt wêze, jo kinne se letter altyd ûntfolgje!", "onboarding.follows.title": "Populêr op Mastodon", + "onboarding.profile.discoverable": "Meitsje myn profyl te finen", + "onboarding.profile.discoverable_hint": "Wannear’t jo akkoard gean mei it te finen wêzen op Mastodon, ferskine jo berjochten yn sykresultaten en kinne se trending wurde, en jo profyl kin oan oare minsken oanrekommandearre wurde wannear’t se fergelykbere ynteressen hawwe.", + "onboarding.profile.display_name": "Werjeftenamme", + "onboarding.profile.display_name_hint": "Jo folsleine namme of in aardige bynamme…", + "onboarding.profile.lead": "Jo kinne dit letter altyd oanfolje yn de ynstellingen, wêr’t noch mear oanpassingsopsjes beskikber binne.", + "onboarding.profile.note": "Biografy", + "onboarding.profile.note_hint": "Jo kinne oare minsken @fermelde of #hashtags brûke…", + "onboarding.profile.save_and_continue": "Bewarje en trochgean", + "onboarding.profile.title": "Profyl ynstelle", + "onboarding.profile.upload_avatar": "Profylfoto oplade", + "onboarding.profile.upload_header": "Omslachfoto foar profyl oplade", "onboarding.share.lead": "Lit minsken witte hoe’t se jo fine kinne op Mastodon!", "onboarding.share.message": "Ik bin {username} op #Mastodon! Folgje my op {url}", "onboarding.share.next_steps": "Mooglike folgjende stappen:", @@ -521,6 +535,7 @@ "privacy.unlisted.short": "Minder iepenbier", "privacy_policy.last_updated": "Lêst bywurke op {date}", "privacy_policy.title": "Privacybelied", + "recommended": "Oanrekommandearre", "refresh": "Ferfarskje", "regeneration_indicator.label": "Lade…", "regeneration_indicator.sublabel": "Jo starttiidline wurdt oanmakke!", @@ -591,6 +606,7 @@ "search.quick_action.status_search": "Berjochten dy’t oerienkomme mei {x}", "search.search_or_paste": "Sykje of fier URL yn", "search_popout.full_text_search_disabled_message": "Net beskikber op {domain}.", + "search_popout.full_text_search_logged_out_message": "Allinnich beskikber as jo oanmeld binne.", "search_popout.language_code": "ISO-taalkoade", "search_popout.options": "Sykopsjes", "search_popout.quick_actions": "Flugge aksjes", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 83bc826a7..ea6bc05bc 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Publicacións coincidentes {x}", "search.search_or_paste": "Busca ou insire URL", "search_popout.full_text_search_disabled_message": "Non está dispoñible en {domain}.", + "search_popout.full_text_search_logged_out_message": "Só dispoñible ao iniciar sesión.", "search_popout.language_code": "Código ISO do idioma", "search_popout.options": "Opcións de busca", "search_popout.quick_actions": "Accións rápidas", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 4ab516fae..dda92c5c9 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "הודעות המכילות {x}", "search.search_or_paste": "חפש או הזן קישור", "search_popout.full_text_search_disabled_message": "בלתי זמין על {domain}.", + "search_popout.full_text_search_logged_out_message": "זמין רק לאחר כניסה לאתר.", "search_popout.language_code": "קוד ISO לשפה", "search_popout.options": "אפשרויות חיפוש", "search_popout.quick_actions": "פעולות זריזות", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 9be5b57e4..9bef81417 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Bejegyzések a következő keresésre: {x}", "search.search_or_paste": "Keresés vagy URL beillesztése", "search_popout.full_text_search_disabled_message": "Nem érhető el ezen: {domain}.", + "search_popout.full_text_search_logged_out_message": "Csak bejelentkezve érhető el.", "search_popout.language_code": "ISO nyelvkód", "search_popout.options": "Keresési beállítások", "search_popout.quick_actions": "Gyors műveletek", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 42d2c9811..0df1a5e75 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Færslur sem samsvara {x}", "search.search_or_paste": "Leita eða líma slóð", "search_popout.full_text_search_disabled_message": "Ekki tiltækt á {domain}.", + "search_popout.full_text_search_logged_out_message": "Aðeins tiltækt eftir innskráningu.", "search_popout.language_code": "ISO-kóði tungumáls", "search_popout.options": "Leitarvalkostir", "search_popout.quick_actions": "Flýtiaðgerðir", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 2ecf1d8c1..fa659506a 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Post corrispondenti a {x}", "search.search_or_paste": "Cerca o incolla URL", "search_popout.full_text_search_disabled_message": "Non disponibile in {domain}.", + "search_popout.full_text_search_logged_out_message": "Disponibile solo dopo aver effettuato l'accesso.", "search_popout.language_code": "Codice ISO lingua", "search_popout.options": "Opzioni di ricerca", "search_popout.quick_actions": "Azioni rapide", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 9947d1d8c..46caf32b0 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "{x}에 맞는 게시물", "search.search_or_paste": "검색하거나 URL 붙여넣기", "search_popout.full_text_search_disabled_message": "{domain}에서는 이용할 수 없습니다.", + "search_popout.full_text_search_logged_out_message": "로그인되어 있을 때만 할 수 있습니다.", "search_popout.language_code": "ISO 언어코드", "search_popout.options": "검색 옵션", "search_popout.quick_actions": "빠른 작업", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 4cb95426a..a976d5907 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -445,6 +445,7 @@ "search.placeholder": "Paieška", "search.search_or_paste": "Ieškok arba įklijuok URL", "search_popout.full_text_search_disabled_message": "Nepasiekima {domain}.", + "search_popout.full_text_search_logged_out_message": "Pasiekiama tik prisijungus.", "search_popout.language_code": "ISO kalbos kodas", "search_popout.specific_date": "konkreti data", "search_popout.user": "naudotojas", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index b39f1a5c8..295b420fd 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -143,7 +143,7 @@ "compose_form.encryption_warning": "Berichten op Mastodon worden, net zoals op andere social media, niet end-to-end versleuteld. Deel daarom geen gevoelige informatie via Mastodon.", "compose_form.hashtag_warning": "Dit bericht valt niet onder een hashtag te bekijken, omdat deze niet openbaar is. Alleen openbare berichten kunnen via hashtags gevonden worden.", "compose_form.lock_disclaimer": "Jouw account is niet {locked}. Iedereen kan jou volgen en kan de berichten zien die je alleen aan jouw volgers hebt gericht.", - "compose_form.lock_disclaimer.lock": "besloten", + "compose_form.lock_disclaimer.lock": "vergrendeld", "compose_form.placeholder": "Wat wil je kwijt?", "compose_form.poll.add_option": "Keuze toevoegen", "compose_form.poll.duration": "Duur van de peiling", @@ -382,7 +382,7 @@ "lists.delete": "Lijst verwijderen", "lists.edit": "Lijst bewerken", "lists.edit.submit": "Titel veranderen", - "lists.exclusive": "Verberg deze berichten op je starttijdlijn", + "lists.exclusive": "Verberg lijstleden op je starttijdlijn", "lists.new.create": "Lijst toevoegen", "lists.new.title_placeholder": "Naam nieuwe lijst", "lists.replies_policy.followed": "Elke gevolgde gebruiker", @@ -395,7 +395,7 @@ "loading_indicator.label": "Laden…", "media_gallery.toggle_visible": "{number, plural, one {afbeelding verbergen} other {afbeeldingen verbergen}}", "moved_to_account_banner.text": "Omdat je naar {movedToAccount} bent verhuisd is jouw account {disabledAccount} momenteel uitgeschakeld.", - "mute_modal.duration": "Duur", + "mute_modal.duration": "Tijdsduur", "mute_modal.hide_notifications": "Verberg meldingen van deze persoon?", "mute_modal.indefinite": "Voor onbepaalde tijd", "navigation_bar.about": "Over", @@ -481,8 +481,8 @@ "onboarding.follows.empty": "Helaas kunnen op dit moment geen resultaten worden getoond. Je kunt proberen te zoeken of op de verkenningspagina te bladeren om mensen te vinden die je kunt volgen, of probeer het later opnieuw.", "onboarding.follows.lead": "Jouw starttijdlijn is de belangrijkste manier om Mastodon te ervaren. Hoe meer mensen je volgt, hoe actiever en interessanter het zal zijn. Om te beginnen, zijn hier enkele suggesties:", "onboarding.follows.title": "Je starttijdlijn aan jouw wensen aanpassen", - "onboarding.profile.discoverable": "Maak mij profiel ontdekbaar", - "onboarding.profile.discoverable_hint": "Wanneer je kiest voor Mastodon kun je berichten weergeven in zoekresultaten en trending, en je profiel kan worden voorgesteld aan mensen met vergelijkbare interesses.", + "onboarding.profile.discoverable": "Maak mijn profiel vindbaar", + "onboarding.profile.discoverable_hint": "Wanneer je akkoord gaat met het vindbaar zijn op Mastodon, verschijnen je berichten in zoekresultaten en kunnen ze trending worden, en je profiel kan aan andere mensen worden aanbevolen wanneer ze vergelijkbare interesses hebben.", "onboarding.profile.display_name": "Weergavenaam", "onboarding.profile.display_name_hint": "Jouw volledige naam of een leuke bijnaam…", "onboarding.profile.lead": "Je kunt dit later altijd aanvullen in de instellingen, waar nog meer aanpassingsopties beschikbaar zijn.", @@ -491,7 +491,7 @@ "onboarding.profile.save_and_continue": "Opslaan en doorgaan", "onboarding.profile.title": "Profiel instellen", "onboarding.profile.upload_avatar": "Profielfoto uploaden", - "onboarding.profile.upload_header": "Kop voor het profiel uploaden", + "onboarding.profile.upload_header": "Omslagfoto voor het profiel uploaden", "onboarding.share.lead": "Laat mensen weten hoe ze je kunnen vinden op Mastodon!", "onboarding.share.message": "Ik ben {username} op #Mastodon! Volg mij op {url}", "onboarding.share.next_steps": "Mogelijke volgende stappen:", @@ -504,7 +504,7 @@ "onboarding.steps.publish_status.body": "Zeg hallo tegen de wereld met tekst, foto's, video's of peilingen {emoji}", "onboarding.steps.publish_status.title": "Maak je eerste bericht", "onboarding.steps.setup_profile.body": "Anderen zullen eerder met je in contact treden als je wat over jezelf vertelt.", - "onboarding.steps.setup_profile.title": "Pas je profiel aan", + "onboarding.steps.setup_profile.title": "Je profiel aanpassen", "onboarding.steps.share_profile.body": "Laat je vrienden weten waar je te vinden bent op Mastodon", "onboarding.steps.share_profile.title": "Deel je Mastodonprofiel", "onboarding.tips.2fa": "<strong>Wist je dat?</strong> Je kunt je account beveiligen door tweestapsverificatie in te stellen in je accountinstellingen. Het werkt met elke TOTP-app naar keuze, geen telefoonnummer nodig!", @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Berichten die overeenkomen met {x}", "search.search_or_paste": "Zoek of voer een URL in", "search_popout.full_text_search_disabled_message": "Niet beschikbaar op {domain}.", + "search_popout.full_text_search_logged_out_message": "Alleen beschikbaar als je bent ingelogd.", "search_popout.language_code": "ISO-taalcode", "search_popout.options": "Zoekopties", "search_popout.quick_actions": "Snelle acties", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 1e6985df2..dc77f8f4e 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Wpisy pasujące do {x}", "search.search_or_paste": "Wyszukaj lub wklej adres", "search_popout.full_text_search_disabled_message": "Niedostępne na {domain}.", + "search_popout.full_text_search_logged_out_message": "Dostępne tylko po zalogowaniu.", "search_popout.language_code": "Kod języka wg ISO", "search_popout.options": "Opcje wyszukiwania", "search_popout.quick_actions": "Szybkie akcje", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 68f367abc..e7975dd76 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Publicações correspondentes a {x}", "search.search_or_paste": "Buscar ou colar URL", "search_popout.full_text_search_disabled_message": "Não disponível em {domain}.", + "search_popout.full_text_search_logged_out_message": "Disponível apenas quando conectado.", "search_popout.language_code": "Código ISO do idioma", "search_popout.options": "Opções de pesquisa", "search_popout.quick_actions": "Ações rápidas", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index 36e09ac96..2d1616960 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Publicações com correspondência a {x}", "search.search_or_paste": "Pesquisar ou introduzir URL", "search_popout.full_text_search_disabled_message": "Não disponível em {domain}.", + "search_popout.full_text_search_logged_out_message": "Apenas disponível quando tem sessão iniciada.", "search_popout.language_code": "Código ISO do idioma", "search_popout.options": "Opções de pesquisa", "search_popout.quick_actions": "Ações rápidas", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index 21d198284..4ef2681f9 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Objave, ki se ujemajo z {x}", "search.search_or_paste": "Iščite ali prilepite URL", "search_popout.full_text_search_disabled_message": "Ni dostopno na {domain}.", + "search_popout.full_text_search_logged_out_message": "Na voljo le, če ste prijavljeni.", "search_popout.language_code": "Koda ISO jezika", "search_popout.options": "Možnosti iskanja", "search_popout.quick_actions": "Hitra dejanja", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 762ac68d9..35bb8f992 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Podudaranje objava {x}", "search.search_or_paste": "Pretražite ili unesite adresu", "search_popout.full_text_search_disabled_message": "Nije dostupno na {domain}.", + "search_popout.full_text_search_logged_out_message": "Dostupno samo kada ste prijavljeni.", "search_popout.language_code": "ISO kod jezika", "search_popout.options": "Opcije pretrage", "search_popout.quick_actions": "Brze radnje", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index 898f0c124..552c04d13 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Подударање објава {x}", "search.search_or_paste": "Претражите или унесите адресу", "search_popout.full_text_search_disabled_message": "Није доступно на {domain}.", + "search_popout.full_text_search_logged_out_message": "Доступно само када сте пријављени.", "search_popout.language_code": "ISO код језика", "search_popout.options": "Опције претраге", "search_popout.quick_actions": "Брзе радње", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 6473a41d6..8a07da72d 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -604,6 +604,7 @@ "search.quick_action.status_search": "Inlägg som matchar {x}", "search.search_or_paste": "Sök eller klistra in URL", "search_popout.full_text_search_disabled_message": "Inte tillgänglig på {domain}.", + "search_popout.full_text_search_logged_out_message": "Endast tillgängligt när du är inloggad.", "search_popout.language_code": "ISO språkkod", "search_popout.options": "Sökalternativ", "search_popout.quick_actions": "Snabbåtgärder", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index 25b61f40e..8eb09bb7c 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Eşleşen gönderiler {x}", "search.search_or_paste": "Ara veya bağlantıyı yapıştır", "search_popout.full_text_search_disabled_message": "{domain} sunucusunda mevcut değil.", + "search_popout.full_text_search_logged_out_message": "Sadece oturum açıldığında mevcuttur.", "search_popout.language_code": "ISO dil kodu", "search_popout.options": "Arama seçenekleri", "search_popout.quick_actions": "Hızlı eylemler", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 585a4b385..58a14c0ed 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Збіг дописів {x}", "search.search_or_paste": "Введіть адресу або пошуковий запит", "search_popout.full_text_search_disabled_message": "Недоступно на {domain}.", + "search_popout.full_text_search_logged_out_message": "Доступно лише після входу.", "search_popout.language_code": "Код мови ISO", "search_popout.options": "Опції пошуку", "search_popout.quick_actions": "Швидкі дії", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 8fc670557..9ac90b407 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Tút nhắc đến {x}", "search.search_or_paste": "Tìm kiếm hoặc nhập URL", "search_popout.full_text_search_disabled_message": "Không khả dụng trên {domain}.", + "search_popout.full_text_search_logged_out_message": "Cần đăng nhập trước.", "search_popout.language_code": "Mã ngôn ngữ ISO", "search_popout.options": "Tùy chọn tìm kiếm", "search_popout.quick_actions": "Thao tác nhanh", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index e58b50476..1678fd729 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "匹配 {x} 的嘟文", "search.search_or_paste": "搜索或输入网址", "search_popout.full_text_search_disabled_message": "在 {domain} 不可用", + "search_popout.full_text_search_logged_out_message": "只有登录后才可用。", "search_popout.language_code": "ISO语言代码", "search_popout.options": "搜索选项", "search_popout.quick_actions": "快捷操作", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index af4dad7f7..263c70799 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "符合的帖文 {x}", "search.search_or_paste": "搜尋或貼上網址", "search_popout.full_text_search_disabled_message": "在 {domain} 上無法使用。", + "search_popout.full_text_search_logged_out_message": "登入後才可使用。", "search_popout.language_code": "ISO 語言代碼", "search_popout.options": "搜尋選項", "search_popout.quick_actions": "快速動作", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 783f95b30..7ba66ae8c 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -176,7 +176,7 @@ "confirmations.domain_block.confirm": "封鎖整個網域", "confirmations.domain_block.message": "您真的非常確定要封鎖整個 {domain} 網域嗎?大部分情況下,封鎖或靜音少數特定的帳號就能滿足需求了。您將不能在任何公開的時間軸及通知中看到來自此網域的內容。您來自該網域的跟隨者也將被移除。", "confirmations.edit.confirm": "編輯", - "confirmations.edit.message": "編輯嘟文將覆蓋掉您目前正在撰寫的訊息。是否仍要繼續?", + "confirmations.edit.message": "編輯嘟文將覆蓋掉您目前正在撰寫之嘟文內容。您是否仍要繼續?", "confirmations.logout.confirm": "登出", "confirmations.logout.message": "您確定要登出嗎?", "confirmations.mute.confirm": "靜音", @@ -606,6 +606,7 @@ "search.quick_action.status_search": "符合的嘟文 {x}", "search.search_or_paste": "搜尋或輸入網址", "search_popout.full_text_search_disabled_message": "{domain} 上無法使用。", + "search_popout.full_text_search_logged_out_message": "僅於登入時能使用。", "search_popout.language_code": "ISO 語言代碼 (ISO language code)", "search_popout.options": "搜尋選項", "search_popout.quick_actions": "快捷操作", diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 85b444c28..0d7605f02 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -534,6 +534,7 @@ ca: total_reported: Informes sobre ells total_storage: Adjunts multimèdia totals_time_period_hint_html: Els totals mostrats a sota incloeixen dades de tots els temps. + unknown_instance: A hores d'ara no hi ha cap registre d'aquest domini al servidor. invites: deactivate_all: Desactiva-ho tot filter: @@ -610,6 +611,7 @@ ca: created_at: Denunciat delete_and_resolve: Elimina les publicacions forwarded: Reenviat + forwarded_replies_explanation: Aquesta denúncia és d'un usuari extern i sobre contingut extern. Se t'han reenviat perquè el contingut denunciat és en resposta a un dels teus usuaris. forwarded_to: Reenviat a %{domain} mark_as_resolved: Marca com a resolt mark_as_sensitive: Marca com a sensible @@ -1038,9 +1040,12 @@ ca: hint_html: Una cosa més! Necessitem confirmar que ets una persona humana (és així com mantenim a ratlla l'spam). Resolt el CAPTCHA inferior i clica a "Segueix". title: Revisió de seguretat confirmations: + awaiting_review: S'ha confirmat la teva adreça-e. El personal de %{domain} revisa ara el registre. Rebràs un correu si t'aproven el compte. + awaiting_review_title: S'està revisant la teva inscripció clicking_this_link: en clicar aquest enllaç login_link: inici de sessió proceed_to_login_html: Ara pots passar a %{login_link}. + registration_complete: La teva inscripció a %{domain} ja és completa. welcome_title: Hola, %{name}! wrong_email_hint: Si aquesta adreça de correu electrònic no és correcte, pots canviar-la en els ajustos del compte. delete_account: Elimina el compte diff --git a/config/locales/et.yml b/config/locales/et.yml index 20f79bdd3..fb0fdc3a3 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -1804,7 +1804,7 @@ et: Kui mõni asi arusaamatuks jääb, siis võib vaadata juhendvideot: https://youtu.be/J4ItbTOAw7Q explanation: Siin on mõned nõuanded, mis aitavad alustada final_action: Alusta postitamist - final_step: 'Nüüd tee oma esimene postitus. Hea tava on uues kohas ennast tutvustada ning kindlasti kasuta selles postituses ka teemaviidet #tutvustus. Isegi kui sul ei ole veel jälgijaid, siis su postitusi näevad kohalikul ajajoonel ka kõik teised serveri kasutajad.' + final_step: 'Nüüd tee oma esimene postitus. Hea tava on uues kohas ennast tutvustada ning kindlasti kasuta selles postituses ka silti #tutvustus. Isegi kui sul ei ole veel jälgijaid, siis su postitusi näevad kohalikul ajajoonel ka kõik teised serveri kasutajad.' full_handle: Kasutajanimi Mastodon võrgustikus full_handle_hint: Kui jagad kasutajanime väljaspool serverit, siis kasuta kindlasti pikka nime. Erinevates serverites võib olla sama kasutajanimega liikmeid. subject: Tere tulemast Mastodoni diff --git a/config/locales/fy.yml b/config/locales/fy.yml index 6a7cb3551..a08b3a401 100644 --- a/config/locales/fy.yml +++ b/config/locales/fy.yml @@ -611,6 +611,7 @@ fy: created_at: Rapportearre op delete_and_resolve: Berjocht fuortsmite forwarded: Trochstjoerd + forwarded_replies_explanation: Dit rapport komt fan in eksterne brûker en giet oer eksterne ynhâld. It is nei jo trochstjoerd, omdat de rapportearre ynhâld in reaksje is op ien fan jo brûkers. forwarded_to: Trochstjoerd nei %{domain} mark_as_resolved: As oplost markearje mark_as_sensitive: As gefoelich markearje diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 035b04462..111127749 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -1,37 +1,44 @@ --- lt: about: - about_mastodon_html: Mastodon, tai socialinis tinklas pagrįstas atviro kodo programavimu, ir atvirais web protokolais. Visiškai nemokamas. Ši sistema decantrilizuota kaip jūsų elektroninis paštas. + about_mastodon_html: 'Ateities socialinis tinklas: jokių reklamų, jokių įmonių sekimo, etiškas dizainas ir decentralizacija. Turėk savo duomenis su Mastodon!' contact_missing: Nenustatyta - contact_unavailable: Nėra duomenų - hosted_on: Mastodon palaikomas naudojantis %{domain} talpinimu + contact_unavailable: Nėra + hosted_on: Mastodon talpinamas %{domain} title: Apie accounts: follow: Sekti followers: few: Sekėjai - many: Sekėjai + many: Sekėjo one: Sekėjas - other: Sekėjai - following: Sekami - last_active: paskutinį kartą aktyvus - link_verified_on: Nuorodos nuosavybė paskutinį kartą tikrinta %{date} - nothing_here: Čia nieko nėra! + other: Sekėjų + following: Seka + instance_actor_flash: Ši paskyra yra virtualus veikėjas (-a), naudojamas atstovauti pačiam serveriui, o ne atskiram naudotojui. Tai naudojama federacijos tikslais ir neturėtų būti pristabdyta. + last_active: paskutinis aktyumas + link_verified_on: Šios nuorodos nuosavybė buvo patikrinta %{date} + nothing_here: Nieko čia nėra! pin_errors: - following: Privalai sekti žmogų kurį nori pagerbti - posts_tab_heading: Tootai + following: Privalai sekti asmenį, kurį nori patvirtinti. + posts: + few: Įrašai + many: Įrašo + one: Įrašas + other: Įrašų + posts_tab_heading: Įrašai admin: account_actions: - action: Veiksmas - title: Moderuoti %{acct} + action: Atlikti veiksmą + title: Atlikti prižiūrėjimo veiksmą %{acct} account_moderation_notes: - create: Palikti žinutę - created_msg: Moderavimo žinutė sėkimngai sukurta! - destroyed_msg: Moderacijos žinutė sėkmingai ištrinta! + create: Palikti pastabą + created_msg: Prižiūrėjimo pastaba sėkmingai sukurta! + destroyed_msg: Prižiūrėjimo pastaba sėkmingai sunaikinta! accounts: + add_email_domain_block: Blokuoti el. pašto domeną approve: Patvirtinti - are_you_sure: Ar esate įsitikinęs? - avatar: Profilio nuotrauka + are_you_sure: Ar esi įsitikinęs (-usi)? + avatar: Avataras by_domain: Domenas change_email: current_email: Dabartinis el paštas @@ -208,7 +215,7 @@ lt: destroyed_msg: Skundo žinutė sekmingai ištrinta! reports: action_taken_by: Veiksmo ėmėsi - are_you_sure: Ar tu įsitikinęs? + are_you_sure: Ar esi įsitikinęs (-usi)? assign_to_self: Paskirti man assigned: Paskirtas moderatorius comment: @@ -223,6 +230,7 @@ lt: create_and_unresolve: Atidaryti su rašteliu delete: Ištrinti placeholder: Apibūdink, kokių veiksmų imtasi arba kitokie atnaujinimai.. + notes_description_html: Peržiūrėk ir palik pastabas kitiems prižiūrėtojams ir savo būsimam aš reopen: Atidaryti skundą report: 'Skundas #%{id}' reported_account: Reportuota paskyra @@ -242,6 +250,8 @@ lt: desc_html: Tai priklauso nuo hCaptcha išorinių skriptų, kurie gali kelti susirūpinimą dėl saugumo ir privatumo. Be to, <strong>dėl to registracijos procesas kai kuriems žmonėms (ypač neįgaliesiems) gali būti gerokai sunkiau prieinami</strong>. Dėl šių priežasčių apsvarstyk alternatyvias priemones, pavyzdžiui, patvirtinimu arba kvietimu grindžiamą registraciją. domain_blocks: all: Visiems + software_updates: + description: Rekomenduojama nuolat atnaujinti Mastodon diegyklę, kad galėtum naudotis naujausiais pataisymais ir funkcijomis. Be to, kartais labai svarbu laiku naujinti Mastodon, kad būtų išvengta saugumo problemų. Dėl šių priežasčių Mastodon kas 30 minučių tikrina, ar yra atnaujinimų, ir praneša tau apie tai pagal tavo el. pašto pranešimų parinktis. statuses: back_to_account: Atgal į paskyros puslapį media: @@ -249,6 +259,13 @@ lt: no_status_selected: Jokie statusai nebuvo pakeisti, nes niekas nepasirinkta title: Paskyros statusai with_media: Su medija + system_checks: + elasticsearch_health_yellow: + message_html: Elasticsearch klasteris yra nesveikas (geltona būsena), galbūt norėsi išsiaiškinti priežastį + elasticsearch_preset: + message_html: Tavo Elasticsearch klasteris turi daugiau nei vieną mazgą, bet Mastodon nėra sukonfigūruotas juos naudoti. + elasticsearch_preset_single_node: + message_html: Tavo Elasticsearch klasteris turi tik vieną mazgą, <code>ES_PRESET</code> turėtų būti nustatyta į <code>single_node_cluster</code>. title: Administracija warning_presets: add_new: Pridėti naują @@ -276,10 +293,11 @@ lt: regenerate_token: Regeneruoti prieigos žetoną token_regenerated: Prieigos žetonas sėkmingai sugeneruotas warning: Būkite atsargūs su šia informacija. Niekada jos nesidalinkite! - your_token: Jūsų prieigos žetonas + your_token: Tavo prieigos raktas auth: delete_account: Ištrinti paskyrą delete_account_html: Jeigu norite ištrinti savo paskyrą, galite eiti <a href="%{path}">čia</a>. Jūsų prašys patvirtinti pasirinkimą. + dont_have_your_security_key: Neturi saugumo rakto? forgot_password: Pamiršote slaptažodį? invalid_reset_password_token: Slaptažodžio atkūrimo žetonas netinkamas arba jo galiojimo laikas pasibaigęs. Prašykite naujo žetono. login: Prisijungti @@ -294,6 +312,12 @@ lt: preamble_invited: Prieš tęsiant, atsižvelk į pagrindines taisykles, kurias nustatė %{domain} prižiūrėtojai. security: Apsauga set_new_password: Nustatyti naują slaptažodį + status: + redirecting_to: Tavo paskyra yra neaktyvi, nes šiuo metu ji nukreipiama į %{acct}. + self_destruct: Kadangi %{domain} uždaromas, turėsi tik ribotą prieigą prie savo paskyros. + view_strikes: Peržiūrėti ankstesnius savo paskyros pažeidimus + challenge: + hint_html: "<strong>Patarimas:</strong> artimiausią valandą daugiau neprašysime tavo slaptažodžio." datetime: distance_in_words: about_x_hours: "%{count} val" @@ -309,9 +333,16 @@ lt: x_months: "%{count}mėn" x_seconds: "%{count}sek" deletes: - confirm_password: Kad patvirtintumėte savo tapatybę, įveskite dabartini slaptažodį + challenge_not_passed: Įvesta informacija buvo neteisinga + confirm_password: Įvesk dabartinį slaptažodį, kad patvirtintum savo tapatybę + confirm_username: Procedūros patvirtinimui įvesk savo naudotojo vardą proceed: Ištrinti paskyrą - success_msg: Jūsų paskyra sėkmingai ištrinta + success_msg: Tavo paskyra buvo sėkmingai ištrinta + disputes: + strikes: + your_appeal_approved: Tavo apeliacija buvo patvirtinta + your_appeal_pending: Pateikei apeliaciją + your_appeal_rejected: Tavo apeliacija buvo atmesta errors: '403': Jūs neturie prieigos matyti šiam puslapiui. '404': Puslapis nerastas. @@ -412,21 +443,21 @@ lt: title: Naujas mėgstamas follow: body: "%{name} pradėjo jus sekti!" - subject: "%{name} pradėjo jus sekti" + subject: "%{name} dabar seka tave" title: Naujas sekėjas follow_request: action: Tvarkyti prašymus sekti - body: "%{name} nori tapti Jūsų sekėju" + body: "%{name} paprašė tave sekti" subject: 'Laukiantis sprendimo sekėjas: %{name}' title: Naujas prašymas sekti mention: action: Atsakyti - body: 'Jus paminėjo %{name} pranešime:' - subject: Jus paminėjo %{name} + body: 'Tave %{name} paminėjo:' + subject: Tave paminėjo %{name} title: Naujas paminėjimas reblog: - body: 'Jūsų statusą pakėlė %{name}:' - subject: "%{name} pakėlė Jūsų statusą" + body: 'Tavo įrašą pakėlė %{name}:' + subject: "%{name} pakėlė tavo įrašą" title: Naujas pakėlimas pagination: newer: Naujesnis @@ -517,8 +548,9 @@ lt: suspend: Paskyra užrakinta welcome: edit_profile_action: Nustatyti profilį - explanation: Štai keletas patarimų Jums + explanation: Štai keletas patarimų, kaip pradėti final_action: Pradėti kelti įrašus + final_step: 'Pradėk skelbti! Net jei ir neturi sekėjų, tavo viešus įrašus gali matyti kiti, pavyzdžiui, vietinėje laiko skalėje arba saitažodžiuose. Galbūt norėsi prisistatyti saitažodyje #introductions.' full_handle: Jūsų pilnas slapyvardis full_handle_hint: Štai ką jūs sakytumėte savo draugams, kad jie galėtų jums siųsti žinutes arba just sekti iš kitų serverių. subject: Sveiki atvykę į Mastodon @@ -526,9 +558,15 @@ lt: users: follow_limit_reached: Negalite sekti daugiau nei %{limit} žmonių invalid_otp_token: Netinkamas dviejų veiksnių kodas - otp_lost_help_html: Jeigu praradote prieiga prie abiejų, susisiekite su mumis per %{email} + otp_lost_help_html: Jei praradai prieigą prie abiejų, gali susisiek su %{email} seamless_external_login: Jūs esate prisijungę per išorini įrenginį, todėl slaptąžodis ir el pašto nustatymai neprieinami. signed_in_as: 'Prisijungta kaip:' verification: hint_html: "<strong>Savo tapatybės patvirtinimas Mastodon skirtas visiems.</strong> Remiantis atviraisiais žiniatinklio standartais, dabar ir visam laikui nemokamas. Viskas, ko tau reikia, yra asmeninė svetainė, pagal kurią žmonės tave atpažįsta. Kai iš savo profilio pateiksi nuorodą į šią svetainę, patikrinsime, ar svetainėje yra nuoroda į tavo profilį, ir parodysime vizualinį indikatorių." verification: Patvirtinimas + verified_links: Tavo patikrintos nuorodos + webauthn_credentials: + create: + error: Kilo problema pridedant saugumo raktą. Bandyk dar kartą. + nickname_hint: Įvesk naujojo saugumo rakto slapyvardį + not_enabled: Dar neįjungei WebAuthn diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 6ad414b3e..870da2a9a 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -611,7 +611,7 @@ nl: created_at: Gerapporteerd op delete_and_resolve: Bericht verwijderen forwarded: Doorgestuurd - forwarded_replies_explanation: Dit rapport komt van een externe gebruiker en gaat over externe inhoud. Het is naar u doorgestuurd omdat de gerapporteerde inhoud een reactie is op een van uw gebruikers. + forwarded_replies_explanation: Dit rapport komt van een externe gebruiker en gaat over externe inhoud. Het is naar je doorgestuurd omdat de gerapporteerde inhoud een reactie is op een van uw gebruikers. forwarded_to: Doorgestuurd naar %{domain} mark_as_resolved: Markeer als opgelost mark_as_sensitive: Als gevoelig markeren diff --git a/config/locales/simple_form.et.yml b/config/locales/simple_form.et.yml index b5a80da98..501e1f333 100644 --- a/config/locales/simple_form.et.yml +++ b/config/locales/simple_form.et.yml @@ -69,7 +69,7 @@ et: domain: See võib olla e-postiaadressis näha olev domeen või MX-kirje, mida aadress kasutab. Kontroll toimub liitumise käigus. with_dns_records: Püütakse lahendada selle domeeni DNS-kirjed ja ühtlasi blokeerida ka selle tulemused featured_tag: - name: 'Siin on mõned nendest siltidest mida sa oled kõige hiljutisemalt kasutanud:' + name: 'Siin on mõned nendest siltidest, mida oled viimati kasutanud:' filters: action: Tegevuse valik, kui postitus vastab filtrile actions: @@ -98,7 +98,7 @@ et: thumbnail: Umbes 2:1 mõõdus pilt serveri informatsiooni kõrval. timeline_preview: Sisenemata külastajatel on võimalik sirvida viimaseid avalikke postitusi serveril. trendable_by_default: Populaarse sisu ülevaatuse vahele jätmine. Pärast seda on siiski võimalik üksikuid üksusi trendidest eemaldada. - trends: Populaarsuse suunad näitavad millised postitused, sildid ja uudislood koguvad sinu serveris tähelepanu. + trends: Trendid näitavad, millised postitused, sildid ja uudislood koguvad sinu serveris tähelepanu. trends_as_landing_page: Näitab välja logitud kasutajatele ja külalistele serveri kirjelduse asemel populaarset sisu. Populaarne sisu (trendid) peab selleks olema sisse lülitatud. form_challenge: current_password: Turvalisse alasse sisenemine diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index b8cbf6e80..755ac3403 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -785,7 +785,7 @@ zh-TW: statuses: account: 作者 application: 應用程式 - back_to_account: 返回帳號訊息頁 + back_to_account: 返回帳號資訊頁面 back_to_report: 回到檢舉報告頁面 batch: remove_from_report: 從檢舉報告中移除 From 73ab080608b5d2378bcc2f10c63377af988f71fc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 11:06:40 +0100 Subject: [PATCH 118/255] Update dependency jsdom to v23 (#28075) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- streaming/package.json | 2 +- yarn.lock | 122 +++++++++++++++++++++++++++-------------- 2 files changed, 81 insertions(+), 43 deletions(-) diff --git a/streaming/package.json b/streaming/package.json index aecc5752e..52245aeeb 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -18,7 +18,7 @@ "dotenv": "^16.0.3", "express": "^4.18.2", "ioredis": "^5.3.2", - "jsdom": "^22.1.0", + "jsdom": "^23.0.0", "npmlog": "^7.0.1", "pg": "^8.5.0", "pg-connection-string": "^2.6.0", diff --git a/yarn.lock b/yarn.lock index 3275d1235..c7511a151 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2473,7 +2473,7 @@ __metadata: dotenv: "npm:^16.0.3" express: "npm:^4.18.2" ioredis: "npm:^5.3.2" - jsdom: "npm:^22.1.0" + jsdom: "npm:^23.0.0" npmlog: "npm:^7.0.1" pg: "npm:^8.5.0" pg-connection-string: "npm:^2.6.0" @@ -6366,14 +6366,13 @@ __metadata: languageName: node linkType: hard -"data-urls@npm:^4.0.0": - version: 4.0.0 - resolution: "data-urls@npm:4.0.0" +"data-urls@npm:^5.0.0": + version: 5.0.0 + resolution: "data-urls@npm:5.0.0" dependencies: - abab: "npm:^2.0.6" - whatwg-mimetype: "npm:^3.0.0" - whatwg-url: "npm:^12.0.0" - checksum: 928d9a21db31d3dcee125d514fddfeb88067c348b1225e9d2c6ca55db16e1cbe49bf58c092cae7163de958f415fd5c612c2aef2eef87896e097656fce205d766 + whatwg-mimetype: "npm:^4.0.0" + whatwg-url: "npm:^14.0.0" + checksum: 1b894d7d41c861f3a4ed2ae9b1c3f0909d4575ada02e36d3d3bc584bdd84278e20709070c79c3b3bff7ac98598cb191eb3e86a89a79ea4ee1ef360e1694f92ad languageName: node linkType: hard @@ -8850,6 +8849,15 @@ __metadata: languageName: node linkType: hard +"html-encoding-sniffer@npm:^4.0.0": + version: 4.0.0 + resolution: "html-encoding-sniffer@npm:4.0.0" + dependencies: + whatwg-encoding: "npm:^3.1.1" + checksum: 523398055dc61ac9b34718a719cb4aa691e4166f29187e211e1607de63dc25ac7af52ca7c9aead0c4b3c0415ffecb17326396e1202e2e86ff4bca4c0ee4c6140 + languageName: node + linkType: hard + "html-entities@npm:^1.3.1": version: 1.4.0 resolution: "html-entities@npm:1.4.0" @@ -8985,7 +8993,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.1": +"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.2": version: 7.0.2 resolution: "https-proxy-agent@npm:7.0.2" dependencies: @@ -10603,39 +10611,37 @@ __metadata: languageName: node linkType: hard -"jsdom@npm:^22.1.0": - version: 22.1.0 - resolution: "jsdom@npm:22.1.0" +"jsdom@npm:^23.0.0": + version: 23.0.0 + resolution: "jsdom@npm:23.0.0" dependencies: - abab: "npm:^2.0.6" cssstyle: "npm:^3.0.0" - data-urls: "npm:^4.0.0" + data-urls: "npm:^5.0.0" decimal.js: "npm:^10.4.3" - domexception: "npm:^4.0.0" form-data: "npm:^4.0.0" - html-encoding-sniffer: "npm:^3.0.0" - http-proxy-agent: "npm:^5.0.0" - https-proxy-agent: "npm:^5.0.1" + html-encoding-sniffer: "npm:^4.0.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.2" is-potential-custom-element-name: "npm:^1.0.1" - nwsapi: "npm:^2.2.4" + nwsapi: "npm:^2.2.7" parse5: "npm:^7.1.2" rrweb-cssom: "npm:^0.6.0" saxes: "npm:^6.0.0" symbol-tree: "npm:^3.2.4" - tough-cookie: "npm:^4.1.2" - w3c-xmlserializer: "npm:^4.0.0" + tough-cookie: "npm:^4.1.3" + w3c-xmlserializer: "npm:^5.0.0" webidl-conversions: "npm:^7.0.0" - whatwg-encoding: "npm:^2.0.0" - whatwg-mimetype: "npm:^3.0.0" - whatwg-url: "npm:^12.0.1" - ws: "npm:^8.13.0" - xml-name-validator: "npm:^4.0.0" + whatwg-encoding: "npm:^3.1.1" + whatwg-mimetype: "npm:^4.0.0" + whatwg-url: "npm:^14.0.0" + ws: "npm:^8.14.2" + xml-name-validator: "npm:^5.0.0" peerDependencies: - canvas: ^2.5.0 + canvas: ^3.0.0 peerDependenciesMeta: canvas: optional: true - checksum: a1c1501c611d1fe833e0a28796a234325aa09d4c597a9d8ccf6970004a9d946d261469502eadb555bdd7a55f5a2fbf3ce60c727cd99acb0d63f257fb9afcd33d + checksum: 2c876a02de49e0ed6b667a4eb9b08b8e76ac189a5571ff97791cc9564e713259314deea6d657cc7f59fc30af41b900e7d833c95017e576dfcaf25f32565722af languageName: node linkType: hard @@ -11983,7 +11989,7 @@ __metadata: languageName: node linkType: hard -"nwsapi@npm:^2.2.2, nwsapi@npm:^2.2.4": +"nwsapi@npm:^2.2.2, nwsapi@npm:^2.2.7": version: 2.2.7 resolution: "nwsapi@npm:2.2.7" checksum: 44be198adae99208487a1c886c0a3712264f7bbafa44368ad96c003512fed2753d4e22890ca1e6edb2690c3456a169f2a3c33bfacde1905cf3bf01c7722464db @@ -13423,7 +13429,7 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.0": +"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.0, punycode@npm:^2.3.1": version: 2.3.1 resolution: "punycode@npm:2.3.1" checksum: 14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 @@ -16201,7 +16207,7 @@ __metadata: languageName: node linkType: hard -"tough-cookie@npm:^4.1.2": +"tough-cookie@npm:^4.1.2, tough-cookie@npm:^4.1.3": version: 4.1.3 resolution: "tough-cookie@npm:4.1.3" dependencies: @@ -16231,12 +16237,12 @@ __metadata: languageName: node linkType: hard -"tr46@npm:^4.1.1": - version: 4.1.1 - resolution: "tr46@npm:4.1.1" +"tr46@npm:^5.0.0": + version: 5.0.0 + resolution: "tr46@npm:5.0.0" dependencies: - punycode: "npm:^2.3.0" - checksum: 92085dcf186f56a49ba4124a581d9ae6a5d0cd4878107c34e2e670b9ddc49da85e4950084bb3e75015195cc23f37ae1c02d45064e94dd6018f5e789aa51d93a8 + punycode: "npm:^2.3.1" + checksum: 1521b6e7bbc8adc825c4561480f9fe48eb2276c81335eed9fa610aa4c44a48a3221f78b10e5f18b875769eb3413e30efbf209ed556a17a42aa8d690df44b7bee languageName: node linkType: hard @@ -16851,6 +16857,15 @@ __metadata: languageName: node linkType: hard +"w3c-xmlserializer@npm:^5.0.0": + version: 5.0.0 + resolution: "w3c-xmlserializer@npm:5.0.0" + dependencies: + xml-name-validator: "npm:^5.0.0" + checksum: 8712774c1aeb62dec22928bf1cdfd11426c2c9383a1a63f2bcae18db87ca574165a0fbe96b312b73652149167ac6c7f4cf5409f2eb101d9c805efe0e4bae798b + languageName: node + linkType: hard + "walker@npm:^1.0.8": version: 1.0.8 resolution: "walker@npm:1.0.8" @@ -17158,6 +17173,15 @@ __metadata: languageName: node linkType: hard +"whatwg-encoding@npm:^3.1.1": + version: 3.1.1 + resolution: "whatwg-encoding@npm:3.1.1" + dependencies: + iconv-lite: "npm:0.6.3" + checksum: 273b5f441c2f7fda3368a496c3009edbaa5e43b71b09728f90425e7f487e5cef9eb2b846a31bd760dd8077739c26faf6b5ca43a5f24033172b003b72cf61a93e + languageName: node + linkType: hard + "whatwg-mimetype@npm:^3.0.0": version: 3.0.0 resolution: "whatwg-mimetype@npm:3.0.0" @@ -17165,6 +17189,13 @@ __metadata: languageName: node linkType: hard +"whatwg-mimetype@npm:^4.0.0": + version: 4.0.0 + resolution: "whatwg-mimetype@npm:4.0.0" + checksum: a773cdc8126b514d790bdae7052e8bf242970cebd84af62fb2f35a33411e78e981f6c0ab9ed1fe6ec5071b09d5340ac9178e05b52d35a9c4bcf558ba1b1551df + languageName: node + linkType: hard + "whatwg-url@npm:^11.0.0": version: 11.0.0 resolution: "whatwg-url@npm:11.0.0" @@ -17175,13 +17206,13 @@ __metadata: languageName: node linkType: hard -"whatwg-url@npm:^12.0.0, whatwg-url@npm:^12.0.1": - version: 12.0.1 - resolution: "whatwg-url@npm:12.0.1" +"whatwg-url@npm:^14.0.0": + version: 14.0.0 + resolution: "whatwg-url@npm:14.0.0" dependencies: - tr46: "npm:^4.1.1" + tr46: "npm:^5.0.0" webidl-conversions: "npm:^7.0.0" - checksum: 99f506b2c996704fa0fc5c70d8e5e27dce15492db2921c99cf319a8d56cb61641f5c06089f63e1ab1983de9fd6a63c3c112a90cdb5fe352d7a846979b10df566 + checksum: ac32e9ba9d08744605519bbe9e1371174d36229689ecc099157b6ba102d4251a95e81d81f3d80271eb8da182eccfa65653f07f0ab43ea66a6934e643fd091ba9 languageName: node linkType: hard @@ -17616,7 +17647,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.11.0, ws@npm:^8.12.1, ws@npm:^8.13.0": +"ws@npm:^8.11.0, ws@npm:^8.12.1, ws@npm:^8.14.2": version: 8.14.2 resolution: "ws@npm:8.14.2" peerDependencies: @@ -17638,6 +17669,13 @@ __metadata: languageName: node linkType: hard +"xml-name-validator@npm:^5.0.0": + version: 5.0.0 + resolution: "xml-name-validator@npm:5.0.0" + checksum: 3fcf44e7b73fb18be917fdd4ccffff3639373c7cb83f8fc35df6001fecba7942f1dbead29d91ebb8315e2f2ff786b508f0c9dc0215b6353f9983c6b7d62cb1f5 + languageName: node + linkType: hard + "xmlchars@npm:^2.2.0": version: 2.2.0 resolution: "xmlchars@npm:2.2.0" From 97e677f9931db77ab329fc24e1c3b238fd3e055c Mon Sep 17 00:00:00 2001 From: June <julian+github@jsts.xyz> Date: Mon, 27 Nov 2023 11:06:48 +0100 Subject: [PATCH 119/255] Fix not all legal images showing in file picker when uploading custom emoji (#28076) --- app/views/admin/custom_emojis/new.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/custom_emojis/new.html.haml b/app/views/admin/custom_emojis/new.html.haml index 95996dec8..a03676b00 100644 --- a/app/views/admin/custom_emojis/new.html.haml +++ b/app/views/admin/custom_emojis/new.html.haml @@ -7,7 +7,7 @@ .fields-group = f.input :shortcode, wrapper: :with_label, label: t('admin.custom_emojis.shortcode'), hint: t('admin.custom_emojis.shortcode_hint') .fields-group - = f.input :image, wrapper: :with_label, input_html: { accept: CustomEmoji::IMAGE_MIME_TYPES.join(' ') }, hint: t('admin.custom_emojis.image_hint', size: number_to_human_size(CustomEmoji::LIMIT)) + = f.input :image, wrapper: :with_label, input_html: { accept: CustomEmoji::IMAGE_MIME_TYPES.join(',') }, hint: t('admin.custom_emojis.image_hint', size: number_to_human_size(CustomEmoji::LIMIT)) .actions = f.button :button, t('admin.custom_emojis.upload'), type: :submit From 228b6684464c8a4427ff2712a732e343c26a0c1f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 10:07:01 +0000 Subject: [PATCH 120/255] Update DefinitelyTyped types (non-major) (#28077) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 76 ++++++++++++++++++++++++++-------------------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/package.json b/package.json index bcd91e3fc..5fe190c69 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "@types/react-dom": "^18.2.4", "@types/react-helmet": "^6.1.6", "@types/react-immutable-proptypes": "^2.1.0", - "@types/react-motion": "^0.0.37", + "@types/react-motion": "^0.0.39", "@types/react-overlays": "^3.1.0", "@types/react-router": "^5.1.20", "@types/react-router-dom": "^5.3.3", diff --git a/yarn.lock b/yarn.lock index c7511a151..77045f04f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2321,7 +2321,7 @@ __metadata: "@types/react-dom": "npm:^18.2.4" "@types/react-helmet": "npm:^6.1.6" "@types/react-immutable-proptypes": "npm:^2.1.0" - "@types/react-motion": "npm:^0.0.37" + "@types/react-motion": "npm:^0.0.39" "@types/react-overlays": "npm:^3.1.0" "@types/react-router": "npm:^5.1.20" "@types/react-router-dom": "npm:^5.3.3" @@ -2953,15 +2953,15 @@ __metadata: linkType: hard "@types/babel__core@npm:*, @types/babel__core@npm:^7.1.12, @types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.1.7, @types/babel__core@npm:^7.20.1": - version: 7.20.4 - resolution: "@types/babel__core@npm:7.20.4" + version: 7.20.5 + resolution: "@types/babel__core@npm:7.20.5" dependencies: "@babel/parser": "npm:^7.20.7" "@babel/types": "npm:^7.20.7" "@types/babel__generator": "npm:*" "@types/babel__template": "npm:*" "@types/babel__traverse": "npm:*" - checksum: 2adc7ec49de5f922271ce087cedee000de468a3e13f92b7b6254016bd8357298cb98e6d2b3c9defc69bb6e38e0c134ffe80776a8ce4e9fb167bbffcb4d7613b7 + checksum: bdee3bb69951e833a4b811b8ee9356b69a61ed5b7a23e1a081ec9249769117fa83aaaf023bb06562a038eb5845155ff663e2d5c75dd95c1d5ccc91db012868ff languageName: node linkType: hard @@ -3022,11 +3022,11 @@ __metadata: linkType: hard "@types/emoji-mart@npm:^3.0.9": - version: 3.0.12 - resolution: "@types/emoji-mart@npm:3.0.12" + version: 3.0.13 + resolution: "@types/emoji-mart@npm:3.0.13" dependencies: "@types/react": "npm:*" - checksum: 146abafe3ce9f4954c7f6ed3603bdc5a897b2d6b99dd9da6065ef597a9a6a59fb914e907decbda29b661216ddf3da8bb34a28d50f3d6929efce2b3c42e73b085 + checksum: 840f920c3242e1d274f0102e67cb2d00434e1fd370e0bcc8983b43b6b62322b01e3ddcd5fb078c60883e613530a7c70b8c40060624897543cd4da9441ca81486 languageName: node linkType: hard @@ -3170,12 +3170,12 @@ __metadata: linkType: hard "@types/jest@npm:^29.5.2": - version: 29.5.8 - resolution: "@types/jest@npm:29.5.8" + version: 29.5.10 + resolution: "@types/jest@npm:29.5.10" dependencies: expect: "npm:^29.0.0" pretty-format: "npm:^29.0.0" - checksum: a28e7827ea7e1a2aace6a386868fa6b8402c162d6c71570aed2c29d3745ddc22ceef6899a20643071817905d3c57b670a7992fc8760bff65939351fd4dc481cf + checksum: b46171d59d12a5f69bbe710f65eaf59a8073337c6b4a67dff8158575caec53f1c61f8a7d645b34d6ac3c4ea398acd30f0c5d1c4a131c0c918798019264a3397d languageName: node linkType: hard @@ -3219,9 +3219,9 @@ __metadata: linkType: hard "@types/lodash@npm:^4.14.195": - version: 4.14.201 - resolution: "@types/lodash@npm:4.14.201" - checksum: 14dc43787296c429433d7d034ed47c5ac24b92217056f80a0e6c990449120b9c9c1058918188945fb88353c0c8333c5c36dccc40c51edbd39b05d2169ab2e0ad + version: 4.14.202 + resolution: "@types/lodash@npm:4.14.202" + checksum: 6064d43c8f454170841bd67c8266cc9069d9e570a72ca63f06bceb484cb4a3ee60c9c1f305c1b9e3a87826049fd41124b8ef265c4dd08b00f6766609c7fe9973 languageName: node linkType: hard @@ -3318,16 +3318,16 @@ __metadata: linkType: hard "@types/prop-types@npm:*, @types/prop-types@npm:^15.7.5": - version: 15.7.10 - resolution: "@types/prop-types@npm:15.7.10" - checksum: 964348d05cdf7399260b3179fbd1462b23d7452dc39fbccb319e54ed6ffafb0a01c0a62c3e6f7c944a635c7a4ad5c99d62c4787c9c4b74e2ec07aebaf6cfedc1 + version: 15.7.11 + resolution: "@types/prop-types@npm:15.7.11" + checksum: e53423cf9d510515ef8b47ff42f4f1b65a7b7b37c8704e2dbfcb9a60defe0c0e1f3cb1acfdeb466bad44ca938d7c79bffdd51b48ffb659df2432169d0b27a132 languageName: node linkType: hard "@types/punycode@npm:^2.1.0": - version: 2.1.2 - resolution: "@types/punycode@npm:2.1.2" - checksum: 4a748533bde61097f205638b3acc2c3b0e25382d2c35a2e3b60c33c904afbad158ef778ae3e1b3f3c84edd7b04b6d9fa049f2832210c308d3fee77ba7b637cb9 + version: 2.1.3 + resolution: "@types/punycode@npm:2.1.3" + checksum: c4babd33d0ed010017bc2d44a15b322b1e2997b9bb335020c26a58ac855e176d337536fa0ca84aa1b0c6d7008799566d4d5430a083d123ac6bbcc59c451b9cfc languageName: node linkType: hard @@ -3353,11 +3353,11 @@ __metadata: linkType: hard "@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.4": - version: 18.2.15 - resolution: "@types/react-dom@npm:18.2.15" + version: 18.2.17 + resolution: "@types/react-dom@npm:18.2.17" dependencies: "@types/react": "npm:*" - checksum: 70e86f15f69f89b8f179139ab2e8a8aa9765e742789f5dd5a46fec40d4300ada8fe3349cceda42b9964a018982d7ccb7d791b47f781966c992bfd37da909fbd3 + checksum: 33b53078ed7e9e0cfc4dc691e938f7db1cc06353bc345947b41b581c3efe2b980c9e4eb6460dbf5ddc521dd91959194c970221a2bd4bfad9d23ebce338e12938 languageName: node linkType: hard @@ -3380,12 +3380,12 @@ __metadata: languageName: node linkType: hard -"@types/react-motion@npm:^0.0.37": - version: 0.0.37 - resolution: "@types/react-motion@npm:0.0.37" +"@types/react-motion@npm:^0.0.39": + version: 0.0.39 + resolution: "@types/react-motion@npm:0.0.39" dependencies: "@types/react": "npm:*" - checksum: 387f60636d9bdd2e765ce94db969cf762a62495e32807f88380748a74e9beeb3d8e17c3ec334dab8040244ea62e7954d5f4d4bdbdd0ecc8985eb4a6ce465b61c + checksum: 0dfcde777576b3c3289b4dbf2a5085decf71aba6d543697f4c1069d02ed3b543792a253692bd98870af04112c92469328a4fdb93988f93af2e099de8f2c9bc2e languageName: node linkType: hard @@ -3447,11 +3447,11 @@ __metadata: linkType: hard "@types/react-test-renderer@npm:^18.0.0": - version: 18.0.6 - resolution: "@types/react-test-renderer@npm:18.0.6" + version: 18.0.7 + resolution: "@types/react-test-renderer@npm:18.0.7" dependencies: "@types/react": "npm:*" - checksum: f490d4379e8d095f8fa91700ceb37d0fe5a96d7cc0c51e9d7127fc3d2dc4e37a382dd6215b295b300037985cb8938cb5088130102ad14b79e4622e7e520c5a3b + checksum: 45cbe963354acee2ab090979d856763c84f59ef7b63477d1fef5d0fd52760b69aa67bbd205fbd3bd36264620fce72c8e407735a9f2009c40ca50da59b0058c34 languageName: node linkType: hard @@ -3483,13 +3483,13 @@ __metadata: linkType: hard "@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7": - version: 18.2.37 - resolution: "@types/react@npm:18.2.37" + version: 18.2.38 + resolution: "@types/react@npm:18.2.38" dependencies: "@types/prop-types": "npm:*" "@types/scheduler": "npm:*" csstype: "npm:^3.0.2" - checksum: 79dd5d23da05bec54e7423ca17096e345eb8fd80a3bf8dd916bb5cdd60677d27c298523aa5b245d090fcc4ec100cfd58c1af4631fbac709d0a9d8be75f9d78a9 + checksum: 56edd4756081b677e38ee23ad6d340658c5e2468785cb20968318cec357e1ea7ccf3ecd9534981741192dd1b894200acfaf0f1551b4795c6077668f6afc19345 languageName: node linkType: hard @@ -3631,8 +3631,8 @@ __metadata: linkType: hard "@types/webpack@npm:^4.41.33": - version: 4.41.36 - resolution: "@types/webpack@npm:4.41.36" + version: 4.41.38 + resolution: "@types/webpack@npm:4.41.38" dependencies: "@types/node": "npm:*" "@types/tapable": "npm:^1" @@ -3640,7 +3640,7 @@ __metadata: "@types/webpack-sources": "npm:*" anymatch: "npm:^3.0.0" source-map: "npm:^0.6.0" - checksum: 9e9021049b8f7482ec7c45e95d7c1da3604ee04481d7550421ed58f201f66edb8eb6c26b85be94ce3f761874cdbb8b570827becdaf5acdb1897aba9b7f226252 + checksum: 5a0a7465d45a0e7701a8c863e88c6cba7660b37e4aeab851c71baf505dbab2e178be1cac82488c2e7d0ea11fb703ceddb53476daec3ec9a004e2fc1554233483 languageName: node linkType: hard @@ -3652,11 +3652,11 @@ __metadata: linkType: hard "@types/yargs@npm:^17.0.24, @types/yargs@npm:^17.0.8": - version: 17.0.31 - resolution: "@types/yargs@npm:17.0.31" + version: 17.0.32 + resolution: "@types/yargs@npm:17.0.32" dependencies: "@types/yargs-parser": "npm:*" - checksum: 1e04df99bd0ad8ac8b3748b6ac0e99a9a4efe20b9cd8eab69ac9503fe87ab9bec312ad56982e969cdb0e2c0679431434ad571f6934049adb15fa35b22810c867 + checksum: 2095e8aad8a4e66b86147415364266b8d607a3b95b4239623423efd7e29df93ba81bb862784a6e08664f645cc1981b25fd598f532019174cd3e5e1e689e1cccf languageName: node linkType: hard From b8fe77353eb41a5c1ad993a83c1d3715ae2b439e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 11:07:14 +0100 Subject: [PATCH 121/255] Update dependency aws-sdk-s3 to v1.140.0 (#28080) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1c4f628f1..8c571e6ce 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -131,7 +131,7 @@ GEM attr_required (1.0.1) awrence (1.2.1) aws-eventstream (1.3.0) - aws-partitions (1.855.0) + aws-partitions (1.857.0) aws-sdk-core (3.188.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) @@ -140,7 +140,7 @@ GEM aws-sdk-kms (1.73.0) aws-sdk-core (~> 3, >= 3.188.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.139.0) + aws-sdk-s3 (1.140.0) aws-sdk-core (~> 3, >= 3.188.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.6) From 9b8ba9b3506e9899bbaa6a2e8ae430a3f769b892 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 27 Nov 2023 05:40:03 -0500 Subject: [PATCH 122/255] Remove unused `plain_mailer` layout (#28065) --- app/mailers/admin_mailer.rb | 2 -- app/views/layouts/plain_mailer.html.haml | 1 - 2 files changed, 3 deletions(-) delete mode 100644 app/views/layouts/plain_mailer.html.haml diff --git a/app/mailers/admin_mailer.rb b/app/mailers/admin_mailer.rb index 990b92c33..385e53c65 100644 --- a/app/mailers/admin_mailer.rb +++ b/app/mailers/admin_mailer.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class AdminMailer < ApplicationMailer - layout 'plain_mailer' - helper :accounts helper :languages diff --git a/app/views/layouts/plain_mailer.html.haml b/app/views/layouts/plain_mailer.html.haml deleted file mode 100644 index 0a90f092c..000000000 --- a/app/views/layouts/plain_mailer.html.haml +++ /dev/null @@ -1 +0,0 @@ -= yield From 7b56085f11d06371c4c0cd8bfbbaa268bd0b0be9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 13:55:29 +0100 Subject: [PATCH 123/255] Update dependency typescript to v5.3.2 (#28078) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 77045f04f..98dbfbb68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16416,22 +16416,22 @@ __metadata: linkType: hard "typescript@npm:5, typescript@npm:^5.0.4": - version: 5.2.2 - resolution: "typescript@npm:5.2.2" + version: 5.3.2 + resolution: "typescript@npm:5.3.2" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 91ae3e6193d0ddb8656d4c418a033f0f75dec5e077ebbc2bd6d76439b93f35683936ee1bdc0e9cf94ec76863aa49f27159b5788219b50e1cd0cd6d110aa34b07 + checksum: d7dbe1fbe19039e36a65468ea64b5d338c976550394ba576b7af9c68ed40c0bc5d12ecce390e4b94b287a09a71bd3229f19c2d5680611f35b7c53a3898791159 languageName: node linkType: hard "typescript@patch:typescript@npm%3A5#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin<compat/typescript>": - version: 5.2.2 - resolution: "typescript@patch:typescript@npm%3A5.2.2#optional!builtin<compat/typescript>::version=5.2.2&hash=f3b441" + version: 5.3.2 + resolution: "typescript@patch:typescript@npm%3A5.3.2#optional!builtin<compat/typescript>::version=5.3.2&hash=e012d7" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 062c1cee1990e6b9419ce8a55162b8dc917eb87f807e4de0327dbc1c2fa4e5f61bc0dd4e034d38ff541d1ed0479b53bcee8e4de3a4075c51a1724eb6216cb6f5 + checksum: 73c8bad74e732d93211c9d77f28b03307e2f5fc6a0afc73f4b783261ab567686a16d6ae958bdaef383a00be1b0b8c8b6741dd6ca3d13af4963fa7e47456d49c7 languageName: node linkType: hard From f1657e6d6275384c199956e8872115fdcec600b0 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Mon, 27 Nov 2023 14:25:54 +0100 Subject: [PATCH 124/255] Clamp dates when serializing to Elasticsearch API (#28081) --- app/chewy/accounts_index.rb | 4 +++- app/chewy/concerns/datetime_clamping_concern.rb | 14 ++++++++++++++ app/chewy/public_statuses_index.rb | 4 +++- app/chewy/statuses_index.rb | 4 +++- app/chewy/tags_index.rb | 4 +++- 5 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 app/chewy/concerns/datetime_clamping_concern.rb diff --git a/app/chewy/accounts_index.rb b/app/chewy/accounts_index.rb index 00db257ac..59f2f991f 100644 --- a/app/chewy/accounts_index.rb +++ b/app/chewy/accounts_index.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class AccountsIndex < Chewy::Index + include DatetimeClampingConcern + settings index: index_preset(refresh_interval: '30s'), analysis: { filter: { english_stop: { @@ -60,7 +62,7 @@ class AccountsIndex < Chewy::Index field(:following_count, type: 'long') field(:followers_count, type: 'long') field(:properties, type: 'keyword', value: ->(account) { account.searchable_properties }) - field(:last_status_at, type: 'date', value: ->(account) { account.last_status_at || account.created_at }) + field(:last_status_at, type: 'date', value: ->(account) { clamp_date(account.last_status_at || account.created_at) }) field(:display_name, type: 'text', analyzer: 'verbatim') { field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'verbatim' } field(:username, type: 'text', analyzer: 'verbatim', value: ->(account) { [account.username, account.domain].compact.join('@') }) { field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'verbatim' } field(:text, type: 'text', analyzer: 'verbatim', value: ->(account) { account.searchable_text }) { field :stemmed, type: 'text', analyzer: 'natural' } diff --git a/app/chewy/concerns/datetime_clamping_concern.rb b/app/chewy/concerns/datetime_clamping_concern.rb new file mode 100644 index 000000000..7f176b6e5 --- /dev/null +++ b/app/chewy/concerns/datetime_clamping_concern.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module DatetimeClampingConcern + extend ActiveSupport::Concern + + MIN_ISO8601_DATETIME = '0000-01-01T00:00:00Z'.to_datetime.freeze + MAX_ISO8601_DATETIME = '9999-12-31T23:59:59Z'.to_datetime.freeze + + class_methods do + def clamp_date(datetime) + datetime.clamp(MIN_ISO8601_DATETIME, MAX_ISO8601_DATETIME) + end + end +end diff --git a/app/chewy/public_statuses_index.rb b/app/chewy/public_statuses_index.rb index b5f0be5e5..09a4dfc09 100644 --- a/app/chewy/public_statuses_index.rb +++ b/app/chewy/public_statuses_index.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class PublicStatusesIndex < Chewy::Index + include DatetimeClampingConcern + settings index: index_preset(refresh_interval: '30s', number_of_shards: 5), analysis: { filter: { english_stop: { @@ -62,6 +64,6 @@ class PublicStatusesIndex < Chewy::Index field(:tags, type: 'text', analyzer: 'hashtag', value: ->(status) { status.tags.map(&:display_name) }) field(:language, type: 'keyword') field(:properties, type: 'keyword', value: ->(status) { status.searchable_properties }) - field(:created_at, type: 'date') + field(:created_at, type: 'date', value: ->(status) { clamp_date(status.created_at) }) end end diff --git a/app/chewy/statuses_index.rb b/app/chewy/statuses_index.rb index e315a2030..e739ccecb 100644 --- a/app/chewy/statuses_index.rb +++ b/app/chewy/statuses_index.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class StatusesIndex < Chewy::Index + include DatetimeClampingConcern + settings index: index_preset(refresh_interval: '30s', number_of_shards: 5), analysis: { filter: { english_stop: { @@ -60,6 +62,6 @@ class StatusesIndex < Chewy::Index field(:searchable_by, type: 'long', value: ->(status) { status.searchable_by }) field(:language, type: 'keyword') field(:properties, type: 'keyword', value: ->(status) { status.searchable_properties }) - field(:created_at, type: 'date') + field(:created_at, type: 'date', value: ->(status) { clamp_date(status.created_at) }) end end diff --git a/app/chewy/tags_index.rb b/app/chewy/tags_index.rb index 5b6349a96..c99218a47 100644 --- a/app/chewy/tags_index.rb +++ b/app/chewy/tags_index.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class TagsIndex < Chewy::Index + include DatetimeClampingConcern + settings index: index_preset(refresh_interval: '30s'), analysis: { analyzer: { content: { @@ -42,6 +44,6 @@ class TagsIndex < Chewy::Index field(:name, type: 'text', analyzer: 'content', value: :display_name) { field(:edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'content') } field(:reviewed, type: 'boolean', value: ->(tag) { tag.reviewed? }) field(:usage, type: 'long', value: ->(tag, crutches) { tag.history.aggregate(crutches.time_period).accounts }) - field(:last_status_at, type: 'date', value: ->(tag) { tag.last_status_at || tag.created_at }) + field(:last_status_at, type: 'date', value: ->(tag) { clamp_date(tag.last_status_at || tag.created_at) }) end end From 10b879bd5e87b88b09a4316686be939509ede79a Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Tue, 28 Nov 2023 01:51:22 +0100 Subject: [PATCH 125/255] nodeinfo: add instance name and description (#28079) --- app/serializers/node_info/serializer.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/serializers/node_info/serializer.rb b/app/serializers/node_info/serializer.rb index f70cc38f0..3920b3ee4 100644 --- a/app/serializers/node_info/serializer.rb +++ b/app/serializers/node_info/serializer.rb @@ -38,7 +38,10 @@ class NodeInfo::Serializer < ActiveModel::Serializer end def metadata - {} + { + nodeName: Setting.site_title, + nodeDescription: Setting.site_short_description, + } end private From 2d536bb05f26febeedbb652e342aac630665897b Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 28 Nov 2023 02:41:26 -0500 Subject: [PATCH 126/255] Use `admin_mailer` layout with initial salutation (#28085) --- app/mailers/admin_mailer.rb | 2 ++ app/views/admin_mailer/new_appeal.text.erb | 2 -- app/views/admin_mailer/new_critical_software_updates.text.erb | 2 -- app/views/admin_mailer/new_pending_account.text.erb | 2 -- app/views/admin_mailer/new_report.text.erb | 2 -- app/views/admin_mailer/new_software_updates.text.erb | 2 -- app/views/admin_mailer/new_trends.text.erb | 2 -- app/views/layouts/admin_mailer.text.erb | 3 +++ 8 files changed, 5 insertions(+), 12 deletions(-) create mode 100644 app/views/layouts/admin_mailer.text.erb diff --git a/app/mailers/admin_mailer.rb b/app/mailers/admin_mailer.rb index 385e53c65..2a6fbb0ab 100644 --- a/app/mailers/admin_mailer.rb +++ b/app/mailers/admin_mailer.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class AdminMailer < ApplicationMailer + layout 'admin_mailer' + helper :accounts helper :languages diff --git a/app/views/admin_mailer/new_appeal.text.erb b/app/views/admin_mailer/new_appeal.text.erb index 8b8582360..0494f8898 100644 --- a/app/views/admin_mailer/new_appeal.text.erb +++ b/app/views/admin_mailer/new_appeal.text.erb @@ -1,5 +1,3 @@ -<%= raw t('application_mailer.salutation', name: display_name(@me)) %> - <%= raw t('admin_mailer.new_appeal.body', target: @appeal.account.username, action_taken_by: @appeal.strike.account.username, date: l(@appeal.strike.created_at, format: :with_time_zone), type: t(@appeal.strike.action, scope: 'admin_mailer.new_appeal.actions')) %> > <%= raw word_wrap(@appeal.text, break_sequence: "\n> ") %> diff --git a/app/views/admin_mailer/new_critical_software_updates.text.erb b/app/views/admin_mailer/new_critical_software_updates.text.erb index c901bc50f..63c170dc0 100644 --- a/app/views/admin_mailer/new_critical_software_updates.text.erb +++ b/app/views/admin_mailer/new_critical_software_updates.text.erb @@ -1,5 +1,3 @@ -<%= raw t('application_mailer.salutation', name: display_name(@me)) %> - <%= raw t('admin_mailer.new_critical_software_updates.body') %> <%= raw t('application_mailer.view')%> <%= admin_software_updates_url %> diff --git a/app/views/admin_mailer/new_pending_account.text.erb b/app/views/admin_mailer/new_pending_account.text.erb index a8a2a35fa..9eabb8f15 100644 --- a/app/views/admin_mailer/new_pending_account.text.erb +++ b/app/views/admin_mailer/new_pending_account.text.erb @@ -1,5 +1,3 @@ -<%= raw t('application_mailer.salutation', name: display_name(@me)) %> - <%= raw t('admin_mailer.new_pending_account.body') %> <%= @account.user_email %> (@<%= @account.username %>) diff --git a/app/views/admin_mailer/new_report.text.erb b/app/views/admin_mailer/new_report.text.erb index f8a5224a1..8482225ab 100644 --- a/app/views/admin_mailer/new_report.text.erb +++ b/app/views/admin_mailer/new_report.text.erb @@ -1,5 +1,3 @@ -<%= raw t('application_mailer.salutation', name: display_name(@me)) %> - <%= raw(@report.account.local? ? t('admin_mailer.new_report.body', target: @report.target_account.pretty_acct, reporter: @report.account.pretty_acct) : t('admin_mailer.new_report.body_remote', target: @report.target_account.acct, domain: @report.account.domain)) %> <%= raw t('application_mailer.view')%> <%= admin_report_url(@report) %> diff --git a/app/views/admin_mailer/new_software_updates.text.erb b/app/views/admin_mailer/new_software_updates.text.erb index 2fc4d1a5f..96808f3cb 100644 --- a/app/views/admin_mailer/new_software_updates.text.erb +++ b/app/views/admin_mailer/new_software_updates.text.erb @@ -1,5 +1,3 @@ -<%= raw t('application_mailer.salutation', name: display_name(@me)) %> - <%= raw t('admin_mailer.new_software_updates.body') %> <%= raw t('application_mailer.view')%> <%= admin_software_updates_url %> diff --git a/app/views/admin_mailer/new_trends.text.erb b/app/views/admin_mailer/new_trends.text.erb index 10b10e604..4bcfa1401 100644 --- a/app/views/admin_mailer/new_trends.text.erb +++ b/app/views/admin_mailer/new_trends.text.erb @@ -1,5 +1,3 @@ -<%= raw t('application_mailer.salutation', name: display_name(@me)) %> - <%= raw t('admin_mailer.new_trends.body') %> <%= render partial: 'new_trending_links', object: @links unless @links.empty? %> diff --git a/app/views/layouts/admin_mailer.text.erb b/app/views/layouts/admin_mailer.text.erb new file mode 100644 index 000000000..298007ac8 --- /dev/null +++ b/app/views/layouts/admin_mailer.text.erb @@ -0,0 +1,3 @@ +<%= raw t('application_mailer.salutation', name: display_name(@me)) %> + +<%= yield %> From dfc7154767443a21e82531ddfb56c2fc8fb95dda Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 28 Nov 2023 02:43:16 -0500 Subject: [PATCH 127/255] Remove unused `cached_filtered_status_page` method from accounts controller (#28090) --- app/controllers/accounts_controller.rb | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 936973fb2..a34c116a0 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -96,17 +96,4 @@ class AccountsController < ApplicationController def tag_requested? request.path.split('.').first.end_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize) end - - def cached_filtered_status_page - cache_collection_paginated_by_id( - filtered_statuses, - Status, - PAGE_SIZE, - params_slice(:max_id, :min_id, :since_id) - ) - end - - def params_slice(*keys) - params.slice(*keys).permit(*keys) - end end From 9072896ae57c75550c83ad1ec4df7970d9b59045 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 28 Nov 2023 03:19:08 -0500 Subject: [PATCH 128/255] Avoid unnecessary i-var for account rss page url generation (#28092) --- app/controllers/accounts_controller.rb | 3 +-- app/views/accounts/show.html.haml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index a34c116a0..b0f973172 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -18,8 +18,6 @@ class AccountsController < ApplicationController respond_to do |format| format.html do expires_in(15.seconds, public: true, stale_while_revalidate: 30.seconds, stale_if_error: 1.hour) unless user_signed_in? - - @rss_url = rss_url end format.rss do @@ -84,6 +82,7 @@ class AccountsController < ApplicationController short_account_url(@account, format: 'rss') end end + helper_method :rss_url def media_requested? request.path.split('.').first.end_with?('/media') && !tag_requested? diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml index d56f10a7f..dde9c5084 100644 --- a/app/views/accounts/show.html.haml +++ b/app/views/accounts/show.html.haml @@ -5,7 +5,7 @@ - if @account.user_prefers_noindex? %meta{ name: 'robots', content: 'noindex, noarchive' }/ - %link{ rel: 'alternate', type: 'application/rss+xml', href: @rss_url }/ + %link{ rel: 'alternate', type: 'application/rss+xml', href: rss_url }/ %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@account) }/ - @account.fields.select(&:verifiable?).each do |field| From af02484714162d2a17c23c3beb4a534017945be5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 09:59:48 +0100 Subject: [PATCH 129/255] New Crowdin Translations (automated) (#28096) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/gl.json | 2 +- app/javascript/mastodon/locales/ru.json | 17 +++++++++++++++++ app/javascript/mastodon/locales/th.json | 1 + config/locales/nl.yml | 2 +- config/locales/ru.yml | 3 +++ 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index ea6bc05bc..08d7d4977 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -687,7 +687,7 @@ "status.translated_from_with": "Traducido do {lang} usando {provider}", "status.uncached_media_warning": "A vista previa non está dispoñíble", "status.unmute_conversation": "Deixar de silenciar conversa", - "status.unpin": "Desafixar do perfil", + "status.unpin": "Non fixar no perfil", "subscribed_languages.lead": "Ao facer cambios só as publicacións nos idiomas seleccionados aparecerán nas túas cronoloxías. Non elixas ningún para poder ver publicacións en tódolos idiomas.", "subscribed_languages.save": "Gardar cambios", "subscribed_languages.target": "Cambiar a subscrición a idiomas para {target}", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index 5c98d906b..f0c48236b 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -21,6 +21,7 @@ "account.blocked": "Заблокировано", "account.browse_more_on_origin_server": "Посмотреть в оригинальном профиле", "account.cancel_follow_request": "Отозвать запрос на подписку", + "account.copy": "Скопировать ссылку на профиль", "account.direct": "Лично упоминать @{name}", "account.disable_notifications": "Не уведомлять о постах от @{name}", "account.domain_blocked": "Домен заблокирован", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Отметить как прочитанное", "conversation.open": "Просмотр беседы", "conversation.with": "С {names}", + "copy_icon_button.copied": "Скопировано в буфер обмена", "copypaste.copied": "Скопировано", "copypaste.copy_to_clipboard": "Копировать в буфер обмена", "directory.federated": "Со всей федерации", @@ -222,6 +224,7 @@ "emoji_button.search_results": "Результаты поиска", "emoji_button.symbols": "Символы", "emoji_button.travel": "Путешествия и места", + "empty_column.account_hides_collections": "Данный пользователь решил не предоставлять эту информацию", "empty_column.account_suspended": "Учетная запись заблокирована", "empty_column.account_timeline": "Здесь нет постов!", "empty_column.account_unavailable": "Профиль недоступен", @@ -389,6 +392,7 @@ "lists.search": "Искать среди подписок", "lists.subheading": "Ваши списки", "load_pending": "{count, plural, one {# новый элемент} few {# новых элемента} other {# новых элементов}}", + "loading_indicator.label": "Загрузка…", "media_gallery.toggle_visible": "Показать/скрыть {number, plural, =1 {изображение} other {изображения}}", "moved_to_account_banner.text": "Ваша учетная запись {disabledAccount} в настоящее время заморожена, потому что вы переехали на {movedToAccount}.", "mute_modal.duration": "Продолжительность", @@ -477,6 +481,17 @@ "onboarding.follows.empty": "К сожалению, сейчас нет результатов. Вы можете попробовать использовать поиск или просмотреть страницу \"Исследования\", чтобы найти людей, за которыми можно следить, или повторить попытку позже.", "onboarding.follows.lead": "Вы сами формируете свою домашнюю ленту. Чем больше людей, за которыми вы следите, тем активнее и интереснее она будет. Эти профили могут быть хорошей отправной точкой - вы всегда можете от них отказаться!", "onboarding.follows.title": "Популярно на Mastodon", + "onboarding.profile.discoverable": "Сделать мой профиль открытым", + "onboarding.profile.discoverable_hint": "Если вы соглашаетесь на открытость на Mastodon, ваши сообщения могут появляться в результатах поиска и трендах, а ваш профиль может быть предложен людям со схожими с вами интересами.", + "onboarding.profile.display_name": "Отображаемое имя", + "onboarding.profile.display_name_hint": "Ваше полное имя или псевдоним…", + "onboarding.profile.lead": "Вы всегда можете завершить это позже в настройках, где доступны еще более широкие возможности настройки.", + "onboarding.profile.note": "О себе", + "onboarding.profile.note_hint": "Вы можете @упоминать других людей или использовать #хэштеги…", + "onboarding.profile.save_and_continue": "Сохранить и продолжить", + "onboarding.profile.title": "Настройка профиля", + "onboarding.profile.upload_avatar": "Загрузить фотографию профиля", + "onboarding.profile.upload_header": "Загрузить заголовок профиля", "onboarding.share.lead": "Расскажите людям, как они могут найти вас на Mastodon!", "onboarding.share.message": "Я {username} на #Mastodon! Следуйте за мной по адресу {url}", "onboarding.share.next_steps": "Возможные дальнейшие шаги:", @@ -520,6 +535,7 @@ "privacy.unlisted.short": "Скрытый", "privacy_policy.last_updated": "Последнее обновление {date}", "privacy_policy.title": "Политика конфиденциальности", + "recommended": "Рекомендуется", "refresh": "Обновить", "regeneration_indicator.label": "Загрузка…", "regeneration_indicator.sublabel": "Один момент, мы подготавливаем вашу ленту!", @@ -590,6 +606,7 @@ "search.quick_action.status_search": "Посты, соответствующие {x}", "search.search_or_paste": "Поиск (или вставьте URL)", "search_popout.full_text_search_disabled_message": "Недоступно на {domain}.", + "search_popout.full_text_search_logged_out_message": "Доступно только при авторизации.", "search_popout.language_code": "Код языка по стандарту ISO", "search_popout.options": "Параметры поиска", "search_popout.quick_actions": "Быстрые действия", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index d60509143..c020dc362 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "โพสต์ที่ตรงกับ {x}", "search.search_or_paste": "ค้นหาหรือวาง URL", "search_popout.full_text_search_disabled_message": "ไม่พร้อมใช้งานใน {domain}", + "search_popout.full_text_search_logged_out_message": "พร้อมใช้งานเฉพาะเมื่อเข้าสู่ระบบแล้วเท่านั้น", "search_popout.language_code": "รหัสภาษา ISO", "search_popout.options": "ตัวเลือกการค้นหา", "search_popout.quick_actions": "การกระทำด่วน", diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 870da2a9a..44843b219 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -611,7 +611,7 @@ nl: created_at: Gerapporteerd op delete_and_resolve: Bericht verwijderen forwarded: Doorgestuurd - forwarded_replies_explanation: Dit rapport komt van een externe gebruiker en gaat over externe inhoud. Het is naar je doorgestuurd omdat de gerapporteerde inhoud een reactie is op een van uw gebruikers. + forwarded_replies_explanation: Dit rapport komt van een externe gebruiker en gaat over externe inhoud. Het is naar je doorgestuurd omdat de gerapporteerde inhoud een reactie is op een van jouw gebruikers. forwarded_to: Doorgestuurd naar %{domain} mark_as_resolved: Markeer als opgelost mark_as_sensitive: Als gevoelig markeren diff --git a/config/locales/ru.yml b/config/locales/ru.yml index c380776b5..b1c86494c 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -635,6 +635,7 @@ ru: created_at: Создана delete_and_resolve: Удалить посты forwarded: Переслано + forwarded_replies_explanation: Этот отчёт получен от удаленного пользователя и касается удаленного содержимого. Он был направлен вам, так как содержимое сообщения является ответом одному из ваших пользователей. forwarded_to: Переслано на %{domain} mark_as_resolved: Отметить как решённую mark_as_sensitive: Отметить как деликатное @@ -1080,6 +1081,7 @@ ru: clicking_this_link: нажатие на эту ссылку login_link: войти proceed_to_login_html: Теперь вы можете перейти к %{login_link}. + redirect_to_app_html: Вы должны были перенаправлены на приложение <strong>%{app_name}</strong>. Если этого не произошло, попробуйте %{clicking_this_link} или вернитесь к приложению вручную. registration_complete: Ваша регистрация на %{domain} завершена! welcome_title: Добро пожаловать, %{name}! wrong_email_hint: Если этот адрес электронной почты неверен, вы можете изменить его в настройках аккаунта. @@ -1415,6 +1417,7 @@ ru: '86400': 1 день expires_in_prompt: Никогда generate: Сгенерировать + invalid: Это приглашение недействительно invited_by: 'Вас пригласил(а):' max_uses: few: "%{count} раза" From c824d98ceccda299190ebe1364ffd8bd2a8e330c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:17:00 +0100 Subject: [PATCH 130/255] chore(deps): update dependency fabrication to v2.31.0 (#28089) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8c571e6ce..972adae38 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -272,7 +272,7 @@ GEM et-orbi (1.2.7) tzinfo excon (0.104.0) - fabrication (2.30.0) + fabrication (2.31.0) faker (3.2.2) i18n (>= 1.8.11, < 2) faraday (1.10.3) From baf3b71e3b881a2143c983ce71646ae3a8262086 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 28 Nov 2023 04:17:26 -0500 Subject: [PATCH 131/255] Extract `path_without_format` private methd in accounts controller (#28091) --- app/controllers/accounts_controller.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index b0f973172..850bf881f 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -85,14 +85,18 @@ class AccountsController < ApplicationController helper_method :rss_url def media_requested? - request.path.split('.').first.end_with?('/media') && !tag_requested? + path_without_format.end_with?('/media') && !tag_requested? end def replies_requested? - request.path.split('.').first.end_with?('/with_replies') && !tag_requested? + path_without_format.end_with?('/with_replies') && !tag_requested? end def tag_requested? - request.path.split('.').first.end_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize) + path_without_format.end_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize) + end + + def path_without_format + request.path.split('.').first end end From 8ebc94dd22a18c28c4c9763b909e92e6ba64e242 Mon Sep 17 00:00:00 2001 From: Renaud Chaput <renchap@gmail.com> Date: Tue, 28 Nov 2023 11:03:32 +0100 Subject: [PATCH 132/255] Ignore `@svgr/webpack` updates as they require a Webpacker upgrade (#28098) --- .github/renovate.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 77b64fdd3..895dbfbad 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -22,6 +22,7 @@ 'react-hotkeys', // Requires code changes // Requires Webpacker upgrade or replacement + '@svgr/webpack', '@types/webpack', 'babel-loader', 'compression-webpack-plugin', From a80530d1df39f549b3fa2e4f84669c4851bea443 Mon Sep 17 00:00:00 2001 From: Michael Stanclift <mx@vmstan.com> Date: Tue, 28 Nov 2023 04:04:40 -0600 Subject: [PATCH 133/255] Dockerfile rewrite based on Ruby image with performance optimizations and size reduction, dedicated Streaming image (#26850) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: “Michael <“mx@vmstan.com> Co-authored-by: Emelia Smith <ThisIsMissEm@users.noreply.github.com> --- .github/workflows/build-container-image.yml | 3 + .github/workflows/build-nightly.yml | 23 ++ .github/workflows/build-push-pr.yml | 17 ++ .github/workflows/build-releases.yml | 22 ++ .github/workflows/test-image-build.yml | 14 + Dockerfile | 295 +++++++++++++++----- streaming/.dockerignore | 7 + streaming/Dockerfile | 102 +++++++ 8 files changed, 419 insertions(+), 64 deletions(-) create mode 100644 streaming/.dockerignore create mode 100644 streaming/Dockerfile diff --git a/.github/workflows/build-container-image.yml b/.github/workflows/build-container-image.yml index 29868c72f..e100e1582 100644 --- a/.github/workflows/build-container-image.yml +++ b/.github/workflows/build-container-image.yml @@ -21,6 +21,8 @@ on: type: string labels: type: string + file_to_build: + type: string jobs: build-image: @@ -86,6 +88,7 @@ jobs: - uses: docker/build-push-action@v5 with: context: . + file: ${{ inputs.file_to_build }} build-args: | MASTODON_VERSION_PRERELEASE=${{ inputs.version_prerelease }} MASTODON_VERSION_METADATA=${{ inputs.version_metadata }} diff --git a/.github/workflows/build-nightly.yml b/.github/workflows/build-nightly.yml index 1790d5c84..7c6f74b45 100644 --- a/.github/workflows/build-nightly.yml +++ b/.github/workflows/build-nightly.yml @@ -25,6 +25,7 @@ jobs: needs: compute-suffix uses: ./.github/workflows/build-container-image.yml with: + file_to_build: Dockerfile platforms: linux/amd64,linux/arm64 use_native_arm64_builder: true cache: false @@ -41,3 +42,25 @@ jobs: type=raw,value=nightly type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }} secrets: inherit + + build-image-streaming: + needs: compute-suffix + uses: ./.github/workflows/build-container-image.yml + with: + file_to_build: streaming/Dockerfile + platforms: linux/amd64,linux/arm64 + use_native_arm64_builder: true + cache: false + push_to_images: | + tootsuite/mastodon-streaming + ghcr.io/mastodon/mastodon-streaming + version_prerelease: ${{ needs.compute-suffix.outputs.prerelease }} + labels: | + org.opencontainers.image.description=Nightly build image used for testing purposes + flavor: | + latest=auto + tags: | + type=raw,value=edge + type=raw,value=nightly + type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }} + secrets: inherit diff --git a/.github/workflows/build-push-pr.yml b/.github/workflows/build-push-pr.yml index 1f647e2a1..72baed512 100644 --- a/.github/workflows/build-push-pr.yml +++ b/.github/workflows/build-push-pr.yml @@ -29,6 +29,7 @@ jobs: needs: compute-suffix uses: ./.github/workflows/build-container-image.yml with: + file_to_build: Dockerfile platforms: linux/amd64,linux/arm64 use_native_arm64_builder: true push_to_images: | @@ -39,3 +40,19 @@ jobs: tags: | type=ref,event=pr secrets: inherit + + build-image-streaming: + needs: compute-suffix + uses: ./.github/workflows/build-container-image.yml + with: + file_to_build: streaming/Dockerfile + platforms: linux/amd64,linux/arm64 + use_native_arm64_builder: true + push_to_images: | + ghcr.io/mastodon/mastodon-streaming + version_metadata: ${{ needs.compute-suffix.outputs.metadata }} + flavor: | + latest=auto + tags: | + type=ref,event=pr + secrets: inherit diff --git a/.github/workflows/build-releases.yml b/.github/workflows/build-releases.yml index 3b82eef9d..3f0bef32a 100644 --- a/.github/workflows/build-releases.yml +++ b/.github/workflows/build-releases.yml @@ -12,6 +12,7 @@ jobs: build-image: uses: ./.github/workflows/build-container-image.yml with: + file_to_build: Dockerfile platforms: linux/amd64,linux/arm64 use_native_arm64_builder: true push_to_images: | @@ -27,3 +28,24 @@ jobs: type=pep440,pattern={{raw}} type=pep440,pattern=v{{major}}.{{minor}} secrets: inherit + + build-image-streaming: + if: startsWith(github.ref, 'refs/tags/v4.3.') + uses: ./.github/workflows/build-container-image.yml + with: + file_to_build: streaming/Dockerfile + platforms: linux/amd64,linux/arm64 + use_native_arm64_builder: true + push_to_images: | + tootsuite/mastodon-streaming + ghcr.io/mastodon/mastodon-streaming + # Do not use cache when building releases, so apt update is always ran and the release always contain the latest packages + cache: false + # Only tag with latest when ran against the latest stable branch + # This needs to be updated after each minor version release + flavor: | + latest=${{ startsWith(github.ref, 'refs/tags/v4.3.') }} + tags: | + type=pep440,pattern={{raw}} + type=pep440,pattern=v{{major}}.{{minor}} + secrets: inherit diff --git a/.github/workflows/test-image-build.yml b/.github/workflows/test-image-build.yml index 778e34177..980e07189 100644 --- a/.github/workflows/test-image-build.yml +++ b/.github/workflows/test-image-build.yml @@ -7,6 +7,7 @@ on: - .github/workflows/build-releases.yml - .github/workflows/test-image-build.yml - Dockerfile + - streaming/Dockerfile permissions: contents: read @@ -18,4 +19,17 @@ jobs: uses: ./.github/workflows/build-container-image.yml with: + file_to_build: Dockerfile platforms: linux/amd64 # Testing only on native platform so it is performant + cache: true + + build-image-streaming: + concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-streaming + cancel-in-progress: true + + uses: ./.github/workflows/build-container-image.yml + with: + file_to_build: streaming/Dockerfile + platforms: linux/amd64 # Testing only on native platform so it is performant + cache: true diff --git a/Dockerfile b/Dockerfile index 7e032073b..623a4d4ea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,182 @@ # syntax=docker/dockerfile:1.4 -# This needs to be bookworm-slim because the Ruby image is built on bookworm-slim -ARG NODE_VERSION="20.9-bookworm-slim" -FROM ghcr.io/moritzheiber/ruby-jemalloc:3.2.2-slim as ruby -FROM node:${NODE_VERSION} as build +# Please see https://docs.docker.com/engine/reference/builder for information about +# the extended buildx capabilities used in this file. +# Make sure multiarch TARGETPLATFORM is available for interpolation +# See: https://docs.docker.com/build/building/multi-platform/ +ARG TARGETPLATFORM=${TARGETPLATFORM} +ARG BUILDPLATFORM=${BUILDPLATFORM} -COPY --link --from=ruby /opt/ruby /opt/ruby +# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.2.2"] +ARG RUBY_VERSION="3.2.2" +# # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] +ARG NODE_MAJOR_VERSION="20" +# Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] +ARG DEBIAN_VERSION="bookworm" +# Node image to use for base image based on combined variables (ex: 20-bookworm-slim) +FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as node +# Ruby image to use for base image based on combined variables (ex: 3.2.2-slim-bookworm) +FROM docker.io/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} as ruby -ENV DEBIAN_FRONTEND="noninteractive" \ - PATH="${PATH}:/opt/ruby/bin" +# Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA +# Example: v4.2.0-nightly.2023.11.09+something +# Overwrite existance of 'alpha.0' in version.rb [--build-arg MASTODON_VERSION_PRERELEASE="nightly.2023.11.09"] +ARG MASTODON_VERSION_PRERELEASE="" +# Append build metadata or fork information to version.rb [--build-arg MASTODON_VERSION_METADATA="something"] +ARG MASTODON_VERSION_METADATA="" -SHELL ["/bin/bash", "-o", "pipefail", "-c"] +# Allow Ruby on Rails to serve static files +# See: https://docs.joinmastodon.org/admin/config/#rails_serve_static_files +ARG RAILS_SERVE_STATIC_FILES="true" +# Allow to use YJIT compiler +# See: https://github.com/ruby/ruby/blob/master/doc/yjit/yjit.md +ARG RUBY_YJIT_ENABLE="1" +# Timezone used by the Docker container and runtime, change with [--build-arg TZ=Europe/Berlin] +ARG TZ="Etc/UTC" +# Linux UID (user id) for the mastodon user, change with [--build-arg UID=1234] +ARG UID="991" +# Linux GID (group id) for the mastodon user, change with [--build-arg GID=1234] +ARG GID="991" +# Apply Mastodon build options based on options above +ENV \ +# Apply Mastodon version information + MASTODON_VERSION_PRERELEASE="${MASTODON_VERSION_PRERELEASE}" \ + MASTODON_VERSION_METADATA="${MASTODON_VERSION_METADATA}" \ +# Apply Mastodon static files and YJIT options + RAILS_SERVE_STATIC_FILES=${RAILS_SERVE_STATIC_FILES} \ + RUBY_YJIT_ENABLE=${RUBY_YJIT_ENABLE} \ +# Apply timezone + TZ=${TZ} + +ENV \ +# Configure the IP to bind Mastodon to when serving traffic + BIND="0.0.0.0" \ +# Use production settings for Yarn, Node and related nodejs based tools + NODE_ENV="production" \ +# Use production settings for Ruby on Rails + RAILS_ENV="production" \ +# Add Ruby and Mastodon installation to the PATH + DEBIAN_FRONTEND="noninteractive" \ + PATH="${PATH}:/opt/ruby/bin:/opt/mastodon/bin" \ +# Optimize jemalloc 5.x performance + MALLOC_CONF="narenas:2,background_thread:true,thp:never,dirty_decay_ms:1000,muzzy_decay_ms:0" + +# Set default shell used for running commands +SHELL ["/bin/bash", "-o", "pipefail", "-o", "errexit", "-c"] + +ARG TARGETPLATFORM + +RUN echo "Target platform is $TARGETPLATFORM" + +RUN \ +# Sets timezone + echo "${TZ}" > /etc/localtime; \ +# Creates mastodon user/group and sets home directory + groupadd -g "${GID}" mastodon; \ + useradd -l -u "${UID}" -g "${GID}" -m -d /opt/mastodon mastodon; \ +# Creates /mastodon symlink to /opt/mastodon + ln -s /opt/mastodon /mastodon; + +# Set /opt/mastodon as working directory WORKDIR /opt/mastodon +# hadolint ignore=DL3008,DL3005 +RUN \ +# Mount Apt cache and lib directories from Docker buildx caches +--mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \ +--mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \ +# Apt update & upgrade to check for security updates to Debian image + apt-get update; \ + apt-get dist-upgrade -yq; \ +# Install jemalloc, curl and other necessary components + apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + ffmpeg \ + file \ + imagemagick \ + libjemalloc2 \ + patchelf \ + procps \ + tini \ + tzdata \ + ; \ +# Patch Ruby to use jemalloc + patchelf --add-needed libjemalloc.so.2 /usr/local/bin/ruby; \ +# Discard patchelf after use + apt-get purge -y \ + patchelf \ + ; + +# Create temporary build layer from base image +FROM ruby as build + +# Copy Node package configuration files into working directory +COPY package.json yarn.lock .yarnrc.yml /opt/mastodon/ +COPY .yarn /opt/mastodon/.yarn + +COPY --from=node /usr/local/bin /usr/local/bin +COPY --from=node /usr/local/lib /usr/local/lib + +ARG TARGETPLATFORM + # hadolint ignore=DL3008 +RUN \ +# Mount Apt cache and lib directories from Docker buildx caches +--mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \ +--mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \ +# Install build tools and bundler dependencies from APT + apt-get update; \ + apt-get install -y --no-install-recommends \ + g++ \ + gcc \ + git \ + libgdbm-dev \ + libgmp-dev \ + libicu-dev \ + libidn-dev \ + libpq-dev \ + libssl-dev \ + make \ + shared-mime-info \ + zlib1g-dev \ + ; + +RUN \ +# Configure Corepack + rm /usr/local/bin/yarn*; \ + corepack enable; \ + corepack prepare --activate; + +# Create temporary bundler specific build layer from build layer +FROM build as bundler + +ARG TARGETPLATFORM + +# Copy Gemfile config into working directory +COPY Gemfile* /opt/mastodon/ + +RUN \ +# Mount Ruby Gem caches +--mount=type=cache,id=gem-cache-${TARGETPLATFORM},target=/usr/local/bundle/cache/,sharing=locked \ +# Configure bundle to prevent changes to Gemfile and Gemfile.lock + bundle config set --global frozen "true"; \ +# Configure bundle to not cache downloaded Gems + bundle config set --global cache_all "false"; \ +# Configure bundle to only process production Gems + bundle config set --local without "development test"; \ +# Configure bundle to not warn about root user + bundle config set silence_root_warning "true"; \ +# Download and install required Gems + bundle install -j"$(nproc)"; + +# Create temporary node specific build layer from build layer +FROM build as yarn + +ARG TARGETPLATFORM + +# Copy Node package configuration files into working directory RUN apt-get update && \ apt-get -yq dist-upgrade && \ apt-get install -y --no-install-recommends build-essential \ @@ -41,72 +203,77 @@ COPY Gemfile* package.json yarn.lock .yarnrc.yml /opt/mastodon/ COPY streaming/package.json /opt/mastodon/streaming/ COPY .yarn /opt/mastodon/.yarn -RUN bundle install -j"$(nproc)" +# hadolint ignore=DL3008 +RUN \ +--mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \ +--mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \ +# Install Node packages + yarn workspaces focus --production @mastodon/mastodon; -RUN yarn workspaces focus --all --production && \ - yarn cache clean +# Create temporary assets build layer from build layer +FROM build as precompiler -FROM node:${NODE_VERSION} +# Copy Mastodon sources into precompiler layer +COPY . /opt/mastodon/ -# Use those args to specify your own version flags & suffixes -ARG MASTODON_VERSION_PRERELEASE="" -ARG MASTODON_VERSION_METADATA="" +# Copy bundler and node packages from build layer to container +COPY --from=yarn /opt/mastodon /opt/mastodon/ +COPY --from=bundler /opt/mastodon /opt/mastodon/ +COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/ -ARG UID="991" -ARG GID="991" +ARG TARGETPLATFORM -COPY --link --from=ruby /opt/ruby /opt/ruby +RUN \ +# Use Ruby on Rails to create Mastodon assets + OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder bundle exec rails assets:precompile; \ +# Cleanup temporary files + rm -fr /opt/mastodon/tmp; -SHELL ["/bin/bash", "-o", "pipefail", "-c"] +# Prep final Mastodon Ruby layer +FROM ruby as mastodon -ENV DEBIAN_FRONTEND="noninteractive" \ - PATH="${PATH}:/opt/ruby/bin:/opt/mastodon/bin" +ARG TARGETPLATFORM -# Ignoring these here since we don't want to pin any versions and the Debian image removes apt-get content after use -# hadolint ignore=DL3008,DL3009 -RUN apt-get update && \ - echo "Etc/UTC" > /etc/localtime && \ - groupadd -g "${GID}" mastodon && \ - useradd -l -u "$UID" -g "${GID}" -m -d /opt/mastodon mastodon && \ - apt-get -y --no-install-recommends install whois \ - wget \ - procps \ - libssl3 \ - libpq5 \ - imagemagick \ - ffmpeg \ - libjemalloc2 \ - libicu72 \ - libidn12 \ - libyaml-0-2 \ - file \ - ca-certificates \ - tzdata \ - libreadline8 \ - tini && \ - ln -s /opt/mastodon /mastodon && \ - corepack enable +# hadolint ignore=DL3008 +RUN \ +# Mount Apt cache and lib directories from Docker buildx caches +--mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \ +--mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \ +# Mount Corepack and Yarn caches from Docker buildx caches +--mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \ +--mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \ +# Apt update install non-dev versions of necessary components + apt-get update; \ + apt-get install -y --no-install-recommends \ + libssl3 \ + libpq5 \ + libicu72 \ + libidn12 \ + libreadline8 \ + libyaml-0-2 \ + ; -# Note: no, cleaning here since Debian does this automatically -# See the file /etc/apt/apt.conf.d/docker-clean within the Docker image's filesystem +# Copy Mastodon sources into final layer +COPY . /opt/mastodon/ -COPY --chown=mastodon:mastodon . /opt/mastodon -COPY --chown=mastodon:mastodon --from=build /opt/mastodon /opt/mastodon +# Copy compiled assets to layer +COPY --from=precompiler /opt/mastodon/public/packs /opt/mastodon/public/packs +COPY --from=precompiler /opt/mastodon/public/assets /opt/mastodon/public/assets +# Copy bundler components to layer +COPY --from=bundler /usr/local/bundle/ /usr/local/bundle/ -ENV RAILS_ENV="production" \ - NODE_ENV="production" \ - RAILS_SERVE_STATIC_FILES="true" \ - BIND="0.0.0.0" \ - MASTODON_VERSION_PRERELEASE="${MASTODON_VERSION_PRERELEASE}" \ - MASTODON_VERSION_METADATA="${MASTODON_VERSION_METADATA}" +RUN \ +# Precompile bootsnap code for faster Rails startup + bundle exec bootsnap precompile --gemfile app/ lib/; -# Set the run user +RUN \ +# Pre-create and chown system volume to Mastodon user + mkdir -p /opt/mastodon/public/system; \ + chown mastodon:mastodon /opt/mastodon/public/system; + +# Set the running user for resulting container USER mastodon -WORKDIR /opt/mastodon - -# Precompile assets -RUN OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder rails assets:precompile - -# Set the work dir and the container entry point -ENTRYPOINT ["/usr/bin/tini", "--"] -EXPOSE 3000 4000 +# Expose default Puma ports +EXPOSE 3000 +# Set container tini as default entry point +ENTRYPOINT ["/usr/bin/tini", "--"] \ No newline at end of file diff --git a/streaming/.dockerignore b/streaming/.dockerignore new file mode 100644 index 000000000..ea611a7b8 --- /dev/null +++ b/streaming/.dockerignore @@ -0,0 +1,7 @@ +.env +.env.* +.gitignore +node_modules +.DS_Store +*.swp +*~ diff --git a/streaming/Dockerfile b/streaming/Dockerfile new file mode 100644 index 000000000..ee62e9ec7 --- /dev/null +++ b/streaming/Dockerfile @@ -0,0 +1,102 @@ +# syntax=docker/dockerfile:1.4 + +# Please see https://docs.docker.com/engine/reference/builder for information about +# the extended buildx capabilities used in this file. +# Make sure multiarch TARGETPLATFORM is available for interpolation +# See: https://docs.docker.com/build/building/multi-platform/ +ARG TARGETPLATFORM=${TARGETPLATFORM} +ARG BUILDPLATFORM=${BUILDPLATFORM} + +# Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] +ARG NODE_MAJOR_VERSION="20" +# Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] +ARG DEBIAN_VERSION="bookworm" +# Node image to use for base image based on combined variables (ex: 20-bookworm-slim) +FROM docker.io/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim as streaming + +# Timezone used by the Docker container and runtime, change with [--build-arg TZ=Europe/Berlin] +ARG TZ="Etc/UTC" +# Linux UID (user id) for the mastodon user, change with [--build-arg UID=1234] +ARG UID="991" +# Linux GID (group id) for the mastodon user, change with [--build-arg GID=1234] +ARG GID="991" + +# Apply Mastodon build options based on options above +ENV \ +# Apply Mastodon version information + MASTODON_VERSION_PRERELEASE="${MASTODON_VERSION_PRERELEASE}" \ + MASTODON_VERSION_METADATA="${MASTODON_VERSION_METADATA}" \ +# Apply timezone + TZ=${TZ} + +ENV \ +# Configure the IP to bind Mastodon to when serving traffic + BIND="0.0.0.0" \ +# Explicitly set PORT to match the exposed port + PORT=4000 \ +# Use production settings for Yarn, Node and related nodejs based tools + NODE_ENV="production" \ +# Add Ruby and Mastodon installation to the PATH + DEBIAN_FRONTEND="noninteractive" + +# Set default shell used for running commands +SHELL ["/bin/bash", "-o", "pipefail", "-o", "errexit", "-c"] + +ARG TARGETPLATFORM + +RUN echo "Target platform is ${TARGETPLATFORM}" + +RUN \ +# Sets timezone + echo "${TZ}" > /etc/localtime; \ +# Creates mastodon user/group and sets home directory + groupadd -g "${GID}" mastodon; \ + useradd -l -u "${UID}" -g "${GID}" -m -d /opt/mastodon mastodon; \ +# Creates symlink for /mastodon folder + ln -s /opt/mastodon /mastodon; + +# hadolint ignore=DL3008,DL3005 +RUN \ +# Mount Apt cache and lib directories from Docker buildx caches +--mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \ +--mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \ +# upgrade to check for security updates to Debian image + apt-get update; \ + apt-get dist-upgrade -yq; \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + tzdata \ + ; + +# Set /opt/mastodon as working directory +WORKDIR /opt/mastodon + +# Copy Node package configuration files from build system to container +COPY package.json yarn.lock .yarnrc.yml /opt/mastodon/ +COPY .yarn /opt/mastodon/.yarn +# Copy Streaming source code from build system to container +COPY ./streaming /opt/mastodon/streaming + +RUN \ +# Mount local Corepack and Yarn caches from Docker buildx caches +--mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \ +--mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \ + # Configure Corepack + rm /usr/local/bin/yarn*; \ + corepack enable; \ + corepack prepare --activate; + +RUN \ +# Mount Corepack and Yarn caches from Docker buildx caches +--mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \ +--mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \ +# Install Node packages + yarn workspaces focus --production @mastodon/streaming; + +# Set the running user for resulting container +USER mastodon +# Expose default Streaming ports +EXPOSE 4000 +# Run streaming when started +CMD [ node ./streaming/index.js ] \ No newline at end of file From 4949b6da585335fc277a28efee1d7a99c1c697ab Mon Sep 17 00:00:00 2001 From: Emelia Smith <ThisIsMissEm@users.noreply.github.com> Date: Tue, 28 Nov 2023 15:09:21 +0100 Subject: [PATCH 134/255] Fix streaming eslint configuration (#28055) --- .eslintrc.js | 19 ++++++++----------- package.json | 1 + streaming/.eslintrc.js | 32 ++++++++++++++++++++++++++++++++ streaming/package.json | 8 ++++++-- streaming/tsconfig.json | 11 +++++++++++ yarn.lock | 20 ++++++++++++++++++++ 6 files changed, 78 insertions(+), 13 deletions(-) create mode 100644 streaming/.eslintrc.js create mode 100644 streaming/tsconfig.json diff --git a/.eslintrc.js b/.eslintrc.js index 70506f60c..a9aa86605 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,7 @@ -module.exports = { +// @ts-check +const { defineConfig } = require('eslint-define-config'); + +module.exports = defineConfig({ root: true, extends: [ @@ -193,6 +196,7 @@ module.exports = { 'error', { devDependencies: [ + '.eslintrc.js', 'config/webpack/**', 'app/javascript/mastodon/performance.js', 'app/javascript/mastodon/test_setup.js', @@ -299,6 +303,7 @@ module.exports = { overrides: [ { files: [ + '.eslintrc.js', '*.config.js', '.*rc.js', 'ide-helper.js', @@ -372,14 +377,6 @@ module.exports = { env: { jest: true, }, - }, - { - files: [ - 'streaming/**/*', - ], - rules: { - 'import/no-commonjs': 'off', - }, - }, + } ], -}; +}); diff --git a/package.json b/package.json index 5fe190c69..2f324f77a 100644 --- a/package.json +++ b/package.json @@ -184,6 +184,7 @@ "babel-jest": "^29.5.0", "eslint": "^8.41.0", "eslint-config-prettier": "^9.0.0", + "eslint-define-config": "^2.0.0", "eslint-import-resolver-typescript": "^3.5.5", "eslint-plugin-formatjs": "^4.10.1", "eslint-plugin-import": "~2.29.0", diff --git a/streaming/.eslintrc.js b/streaming/.eslintrc.js new file mode 100644 index 000000000..5e2d233c6 --- /dev/null +++ b/streaming/.eslintrc.js @@ -0,0 +1,32 @@ +// @ts-check +const { defineConfig } = require('eslint-define-config'); + +module.exports = defineConfig({ + extends: ['../.eslintrc.js'], + env: { + browser: false, + }, + parserOptions: { + project: true, + tsconfigRootDir: __dirname, + ecmaFeatures: { + jsx: false, + }, + ecmaVersion: 2021, + }, + rules: { + 'import/no-commonjs': 'off', + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: [ + 'streaming/.eslintrc.js', + ], + optionalDependencies: false, + peerDependencies: false, + includeTypes: true, + packageDir: __dirname, + }, + ], + }, +}); diff --git a/streaming/package.json b/streaming/package.json index 52245aeeb..0cfc5b327 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -12,7 +12,8 @@ "url": "https://github.com/mastodon/mastodon.git" }, "scripts": { - "start": "node ./index.js" + "start": "node ./index.js", + "check:types": "tsc --noEmit" }, "dependencies": { "dotenv": "^16.0.3", @@ -30,7 +31,10 @@ "@types/express": "^4.17.17", "@types/npmlog": "^7.0.0", "@types/pg": "^8.6.6", - "@types/uuid": "^9.0.0" + "@types/uuid": "^9.0.0", + "@types/ws": "^8.5.9", + "eslint-define-config": "^2.0.0", + "typescript": "^5.0.4" }, "optionalDependencies": { "bufferutil": "^4.0.7", diff --git a/streaming/tsconfig.json b/streaming/tsconfig.json new file mode 100644 index 000000000..032274d85 --- /dev/null +++ b/streaming/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "target": "esnext", + "module": "CommonJS", + "moduleResolution": "node", + "noUnusedParameters": false, + "paths": {} + }, + "include": ["./*.js", "./.eslintrc.js"] +} diff --git a/yarn.lock b/yarn.lock index 98dbfbb68..0dd9a627c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2362,6 +2362,7 @@ __metadata: escape-html: "npm:^1.0.3" eslint: "npm:^8.41.0" eslint-config-prettier: "npm:^9.0.0" + eslint-define-config: "npm:^2.0.0" eslint-import-resolver-typescript: "npm:^3.5.5" eslint-plugin-formatjs: "npm:^4.10.1" eslint-plugin-import: "npm:~2.29.0" @@ -2469,8 +2470,10 @@ __metadata: "@types/npmlog": "npm:^7.0.0" "@types/pg": "npm:^8.6.6" "@types/uuid": "npm:^9.0.0" + "@types/ws": "npm:^8.5.9" bufferutil: "npm:^4.0.7" dotenv: "npm:^16.0.3" + eslint-define-config: "npm:^2.0.0" express: "npm:^4.18.2" ioredis: "npm:^5.3.2" jsdom: "npm:^23.0.0" @@ -2478,6 +2481,7 @@ __metadata: pg: "npm:^8.5.0" pg-connection-string: "npm:^2.6.0" prom-client: "npm:^15.0.0" + typescript: "npm:^5.0.4" utf-8-validate: "npm:^6.0.3" uuid: "npm:^9.0.0" ws: "npm:^8.12.1" @@ -3644,6 +3648,15 @@ __metadata: languageName: node linkType: hard +"@types/ws@npm:^8.5.9": + version: 8.5.9 + resolution: "@types/ws@npm:8.5.9" + dependencies: + "@types/node": "npm:*" + checksum: 678bdd6461c4653f2975c537fb673cb1918c331558e2d2422b69761c9ced67200bb07c664e2593f3864077a891cb7c13ef2a40d303b4aacb06173d095d8aa3ce + languageName: node + linkType: hard + "@types/yargs-parser@npm:*": version: 21.0.2 resolution: "@types/yargs-parser@npm:21.0.2" @@ -7302,6 +7315,13 @@ __metadata: languageName: node linkType: hard +"eslint-define-config@npm:^2.0.0": + version: 2.0.0 + resolution: "eslint-define-config@npm:2.0.0" + checksum: 617c3143bc1ed8df0b20ae632d428d5f241dbb04483631e1410c58fe65ba3e503cf94631c5973115482b58ba464d052422a718c0f4d49182f8d13ffbb36bf1d6 + languageName: node + linkType: hard + "eslint-import-resolver-node@npm:^0.3.9": version: 0.3.9 resolution: "eslint-import-resolver-node@npm:0.3.9" From a4de0e364b9f73299ab121340c0f5ab27125be9e Mon Sep 17 00:00:00 2001 From: Emelia Smith <ThisIsMissEm@users.noreply.github.com> Date: Tue, 28 Nov 2023 15:24:41 +0100 Subject: [PATCH 135/255] Refactor streaming to simplify for logging change (#28056) --- streaming/index.js | 104 +++++------------------------------------- streaming/metrics.js | 105 +++++++++++++++++++++++++++++++++++++++++++ streaming/utils.js | 22 +++++++++ 3 files changed, 139 insertions(+), 92 deletions(-) create mode 100644 streaming/metrics.js create mode 100644 streaming/utils.js diff --git a/streaming/index.js b/streaming/index.js index e3b63b53a..fb3e3fb2b 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -12,10 +12,12 @@ const { JSDOM } = require('jsdom'); const log = require('npmlog'); const pg = require('pg'); const dbUrlToConfig = require('pg-connection-string').parse; -const metrics = require('prom-client'); const uuid = require('uuid'); const WebSocket = require('ws'); +const { setupMetrics } = require('./metrics'); +const { isTruthy } = require("./utils"); + const environment = process.env.NODE_ENV || 'development'; // Correctly detect and load .env or .env.production file based on environment: @@ -196,78 +198,15 @@ const startServer = async () => { const redisClient = await createRedisClient(redisConfig); const { redisPrefix } = redisConfig; - // Collect metrics from Node.js - metrics.collectDefaultMetrics(); - - new metrics.Gauge({ - name: 'pg_pool_total_connections', - help: 'The total number of clients existing within the pool', - collect() { - this.set(pgPool.totalCount); - }, - }); - - new metrics.Gauge({ - name: 'pg_pool_idle_connections', - help: 'The number of clients which are not checked out but are currently idle in the pool', - collect() { - this.set(pgPool.idleCount); - }, - }); - - new metrics.Gauge({ - name: 'pg_pool_waiting_queries', - help: 'The number of queued requests waiting on a client when all clients are checked out', - collect() { - this.set(pgPool.waitingCount); - }, - }); - - const connectedClients = new metrics.Gauge({ - name: 'connected_clients', - help: 'The number of clients connected to the streaming server', - labelNames: ['type'], - }); - - const connectedChannels = new metrics.Gauge({ - name: 'connected_channels', - help: 'The number of channels the streaming server is streaming to', - labelNames: [ 'type', 'channel' ] - }); - - const redisSubscriptions = new metrics.Gauge({ - name: 'redis_subscriptions', - help: 'The number of Redis channels the streaming server is subscribed to', - }); - - const redisMessagesReceived = new metrics.Counter({ - name: 'redis_messages_received_total', - help: 'The total number of messages the streaming server has received from redis subscriptions' - }); - - const messagesSent = new metrics.Counter({ - name: 'messages_sent_total', - help: 'The total number of messages the streaming server sent to clients per connection type', - labelNames: [ 'type' ] - }); - - // Prime the gauges so we don't loose metrics between restarts: - redisSubscriptions.set(0); - connectedClients.set({ type: 'websocket' }, 0); - connectedClients.set({ type: 'eventsource' }, 0); - - // For each channel, initialize the gauges at zero; There's only a finite set of channels available - CHANNEL_NAMES.forEach(( channel ) => { - connectedChannels.set({ type: 'websocket', channel }, 0); - connectedChannels.set({ type: 'eventsource', channel }, 0); - }); - - // Prime the counters so that we don't loose metrics between restarts. - // Unfortunately counters don't support the set() API, so instead I'm using - // inc(0) to achieve the same result. - redisMessagesReceived.inc(0); - messagesSent.inc({ type: 'websocket' }, 0); - messagesSent.inc({ type: 'eventsource' }, 0); + const metrics = setupMetrics(CHANNEL_NAMES, pgPool); + // TODO: migrate all metrics to metrics.X.method() instead of just X.method() + const { + connectedClients, + connectedChannels, + redisSubscriptions, + redisMessagesReceived, + messagesSent, + } = metrics; // When checking metrics in the browser, the favicon is requested this // prevents the request from falling through to the API Router, which would @@ -388,25 +327,6 @@ const startServer = async () => { } }; - const FALSE_VALUES = [ - false, - 0, - '0', - 'f', - 'F', - 'false', - 'FALSE', - 'off', - 'OFF', - ]; - - /** - * @param {any} value - * @returns {boolean} - */ - const isTruthy = value => - value && !FALSE_VALUES.includes(value); - /** * @param {any} req * @param {any} res diff --git a/streaming/metrics.js b/streaming/metrics.js new file mode 100644 index 000000000..d05b4c9b1 --- /dev/null +++ b/streaming/metrics.js @@ -0,0 +1,105 @@ +// @ts-check + +const metrics = require('prom-client'); + +/** + * @typedef StreamingMetrics + * @property {metrics.Registry} register + * @property {metrics.Gauge<"type">} connectedClients + * @property {metrics.Gauge<"type" | "channel">} connectedChannels + * @property {metrics.Gauge} redisSubscriptions + * @property {metrics.Counter} redisMessagesReceived + * @property {metrics.Counter<"type">} messagesSent + */ + +/** + * + * @param {string[]} channels + * @param {import('pg').Pool} pgPool + * @returns {StreamingMetrics} + */ +function setupMetrics(channels, pgPool) { + // Collect metrics from Node.js + metrics.collectDefaultMetrics(); + + new metrics.Gauge({ + name: 'pg_pool_total_connections', + help: 'The total number of clients existing within the pool', + collect() { + this.set(pgPool.totalCount); + }, + }); + + new metrics.Gauge({ + name: 'pg_pool_idle_connections', + help: 'The number of clients which are not checked out but are currently idle in the pool', + collect() { + this.set(pgPool.idleCount); + }, + }); + + new metrics.Gauge({ + name: 'pg_pool_waiting_queries', + help: 'The number of queued requests waiting on a client when all clients are checked out', + collect() { + this.set(pgPool.waitingCount); + }, + }); + + const connectedClients = new metrics.Gauge({ + name: 'connected_clients', + help: 'The number of clients connected to the streaming server', + labelNames: ['type'], + }); + + const connectedChannels = new metrics.Gauge({ + name: 'connected_channels', + help: 'The number of channels the streaming server is streaming to', + labelNames: [ 'type', 'channel' ] + }); + + const redisSubscriptions = new metrics.Gauge({ + name: 'redis_subscriptions', + help: 'The number of Redis channels the streaming server is subscribed to', + }); + + const redisMessagesReceived = new metrics.Counter({ + name: 'redis_messages_received_total', + help: 'The total number of messages the streaming server has received from redis subscriptions' + }); + + const messagesSent = new metrics.Counter({ + name: 'messages_sent_total', + help: 'The total number of messages the streaming server sent to clients per connection type', + labelNames: [ 'type' ] + }); + + // Prime the gauges so we don't loose metrics between restarts: + redisSubscriptions.set(0); + connectedClients.set({ type: 'websocket' }, 0); + connectedClients.set({ type: 'eventsource' }, 0); + + // For each channel, initialize the gauges at zero; There's only a finite set of channels available + channels.forEach(( channel ) => { + connectedChannels.set({ type: 'websocket', channel }, 0); + connectedChannels.set({ type: 'eventsource', channel }, 0); + }); + + // Prime the counters so that we don't loose metrics between restarts. + // Unfortunately counters don't support the set() API, so instead I'm using + // inc(0) to achieve the same result. + redisMessagesReceived.inc(0); + messagesSent.inc({ type: 'websocket' }, 0); + messagesSent.inc({ type: 'eventsource' }, 0); + + return { + register: metrics.register, + connectedClients, + connectedChannels, + redisSubscriptions, + redisMessagesReceived, + messagesSent, + }; +} + +exports.setupMetrics = setupMetrics; diff --git a/streaming/utils.js b/streaming/utils.js new file mode 100644 index 000000000..ad8dd4889 --- /dev/null +++ b/streaming/utils.js @@ -0,0 +1,22 @@ +// @ts-check + +const FALSE_VALUES = [ + false, + 0, + '0', + 'f', + 'F', + 'false', + 'FALSE', + 'off', + 'OFF', +]; + +/** + * @param {any} value + * @returns {boolean} + */ +const isTruthy = value => + value && !FALSE_VALUES.includes(value); + +exports.isTruthy = isTruthy; From cdc789424355617c800dc3b589b36fdfdc01b796 Mon Sep 17 00:00:00 2001 From: Renaud Chaput <renchap@gmail.com> Date: Tue, 28 Nov 2023 15:47:32 +0100 Subject: [PATCH 136/255] Fix devcontainer by not forcing `NODE_ENV` (#28099) --- .devcontainer/post-create.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh index 20f3437f4..82a2ccbb6 100755 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/post-create.sh @@ -24,4 +24,4 @@ RAILS_ENV=development ./bin/rails db:setup RAILS_ENV=development ./bin/rails assets:precompile # Precompile assets for test -RAILS_ENV=test NODE_ENV=tests ./bin/rails assets:precompile +RAILS_ENV=test ./bin/rails assets:precompile From 1142f4c79e3eaf4450ed727de0f480e300e8b9a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= <git@joshuakgoldberg.com> Date: Tue, 28 Nov 2023 18:47:55 +0100 Subject: [PATCH 137/255] Converted app/javascript/mastodon/utils/ folder to TypeScript (#27895) --- .../{base64-test.js => base64-test.ts} | 0 .../__tests__/{html-test.js => html-test.s} | 0 app/javascript/mastodon/utils/config.js | 10 ----- app/javascript/mastodon/utils/config.ts | 13 ++++++ app/javascript/mastodon/utils/html.js | 6 --- app/javascript/mastodon/utils/html.ts | 9 +++++ .../mastodon/utils/{icons.jsx => icons.tsx} | 14 ++++++- .../mastodon/utils/{log_out.js => log_out.ts} | 0 .../mastodon/utils/notifications.js | 30 -------------- .../mastodon/utils/notifications.ts | 13 ++++++ .../{react_router.jsx => react_router.tsx} | 40 +++++++++++-------- .../utils/{scrollbar.js => scrollbar.ts} | 15 +++---- package.json | 1 + yarn.lock | 8 ++++ 14 files changed, 84 insertions(+), 75 deletions(-) rename app/javascript/mastodon/utils/__tests__/{base64-test.js => base64-test.ts} (100%) rename app/javascript/mastodon/utils/__tests__/{html-test.js => html-test.s} (100%) delete mode 100644 app/javascript/mastodon/utils/config.js create mode 100644 app/javascript/mastodon/utils/config.ts delete mode 100644 app/javascript/mastodon/utils/html.js create mode 100644 app/javascript/mastodon/utils/html.ts rename app/javascript/mastodon/utils/{icons.jsx => icons.tsx} (69%) rename app/javascript/mastodon/utils/{log_out.js => log_out.ts} (100%) delete mode 100644 app/javascript/mastodon/utils/notifications.js create mode 100644 app/javascript/mastodon/utils/notifications.ts rename app/javascript/mastodon/utils/{react_router.jsx => react_router.tsx} (53%) rename app/javascript/mastodon/utils/{scrollbar.js => scrollbar.ts} (70%) diff --git a/app/javascript/mastodon/utils/__tests__/base64-test.js b/app/javascript/mastodon/utils/__tests__/base64-test.ts similarity index 100% rename from app/javascript/mastodon/utils/__tests__/base64-test.js rename to app/javascript/mastodon/utils/__tests__/base64-test.ts diff --git a/app/javascript/mastodon/utils/__tests__/html-test.js b/app/javascript/mastodon/utils/__tests__/html-test.s similarity index 100% rename from app/javascript/mastodon/utils/__tests__/html-test.js rename to app/javascript/mastodon/utils/__tests__/html-test.s diff --git a/app/javascript/mastodon/utils/config.js b/app/javascript/mastodon/utils/config.js deleted file mode 100644 index 932cd0cbf..000000000 --- a/app/javascript/mastodon/utils/config.js +++ /dev/null @@ -1,10 +0,0 @@ -import ready from '../ready'; - -export let assetHost = ''; - -ready(() => { - const cdnHost = document.querySelector('meta[name=cdn-host]'); - if (cdnHost) { - assetHost = cdnHost.content || ''; - } -}); diff --git a/app/javascript/mastodon/utils/config.ts b/app/javascript/mastodon/utils/config.ts new file mode 100644 index 000000000..9222c89d1 --- /dev/null +++ b/app/javascript/mastodon/utils/config.ts @@ -0,0 +1,13 @@ +import ready from '../ready'; + +export let assetHost = ''; + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +ready(() => { + const cdnHost = document.querySelector<HTMLMetaElement>( + 'meta[name=cdn-host]', + ); + if (cdnHost) { + assetHost = cdnHost.content || ''; + } +}); diff --git a/app/javascript/mastodon/utils/html.js b/app/javascript/mastodon/utils/html.js deleted file mode 100644 index 247e98c88..000000000 --- a/app/javascript/mastodon/utils/html.js +++ /dev/null @@ -1,6 +0,0 @@ -// NB: This function can still return unsafe HTML -export const unescapeHTML = (html) => { - const wrapper = document.createElement('div'); - wrapper.innerHTML = html.replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n').replace(/<[^>]*>/g, ''); - return wrapper.textContent; -}; diff --git a/app/javascript/mastodon/utils/html.ts b/app/javascript/mastodon/utils/html.ts new file mode 100644 index 000000000..0145a0455 --- /dev/null +++ b/app/javascript/mastodon/utils/html.ts @@ -0,0 +1,9 @@ +// NB: This function can still return unsafe HTML +export const unescapeHTML = (html: string) => { + const wrapper = document.createElement('div'); + wrapper.innerHTML = html + .replace(/<br\s*\/?>/g, '\n') + .replace(/<\/p><p>/g, '\n\n') + .replace(/<[^>]*>/g, ''); + return wrapper.textContent; +}; diff --git a/app/javascript/mastodon/utils/icons.jsx b/app/javascript/mastodon/utils/icons.tsx similarity index 69% rename from app/javascript/mastodon/utils/icons.jsx rename to app/javascript/mastodon/utils/icons.tsx index be566032e..6e432e32f 100644 --- a/app/javascript/mastodon/utils/icons.jsx +++ b/app/javascript/mastodon/utils/icons.tsx @@ -1,13 +1,23 @@ // Copied from emoji-mart for consistency with emoji picker and since // they don't export the icons in the package export const loupeIcon = ( - <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='13' height='13'> + <svg + xmlns='http://www.w3.org/2000/svg' + viewBox='0 0 20 20' + width='13' + height='13' + > <path d='M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z' /> </svg> ); export const deleteIcon = ( - <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' width='13' height='13'> + <svg + xmlns='http://www.w3.org/2000/svg' + viewBox='0 0 20 20' + width='13' + height='13' + > <path d='M10 8.586L2.929 1.515 1.515 2.929 8.586 10l-7.071 7.071 1.414 1.414L10 11.414l7.071 7.071 1.414-1.414L11.414 10l7.071-7.071-1.414-1.414L10 8.586z' /> </svg> ); diff --git a/app/javascript/mastodon/utils/log_out.js b/app/javascript/mastodon/utils/log_out.ts similarity index 100% rename from app/javascript/mastodon/utils/log_out.js rename to app/javascript/mastodon/utils/log_out.ts diff --git a/app/javascript/mastodon/utils/notifications.js b/app/javascript/mastodon/utils/notifications.js deleted file mode 100644 index 42623ac7c..000000000 --- a/app/javascript/mastodon/utils/notifications.js +++ /dev/null @@ -1,30 +0,0 @@ -// Handles browser quirks, based on -// https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API/Using_the_Notifications_API - -const checkNotificationPromise = () => { - try { - // eslint-disable-next-line promise/valid-params, promise/catch-or-return - Notification.requestPermission().then(); - } catch(e) { - return false; - } - - return true; -}; - -const handlePermission = (permission, callback) => { - // Whatever the user answers, we make sure Chrome stores the information - if(!('permission' in Notification)) { - Notification.permission = permission; - } - - callback(Notification.permission); -}; - -export const requestNotificationPermission = (callback) => { - if (checkNotificationPromise()) { - Notification.requestPermission().then((permission) => handlePermission(permission, callback)).catch(console.warn); - } else { - Notification.requestPermission((permission) => handlePermission(permission, callback)); - } -}; diff --git a/app/javascript/mastodon/utils/notifications.ts b/app/javascript/mastodon/utils/notifications.ts new file mode 100644 index 000000000..08f677f8f --- /dev/null +++ b/app/javascript/mastodon/utils/notifications.ts @@ -0,0 +1,13 @@ +/** + * Tries Notification.requestPermission, console warning instead of rejecting on error. + * @param callback Runs with the permission result on completion. + */ +export const requestNotificationPermission = async ( + callback: NotificationPermissionCallback, +) => { + try { + callback(await Notification.requestPermission()); + } catch (error) { + console.warn(error); + } +}; diff --git a/app/javascript/mastodon/utils/react_router.jsx b/app/javascript/mastodon/utils/react_router.tsx similarity index 53% rename from app/javascript/mastodon/utils/react_router.jsx rename to app/javascript/mastodon/utils/react_router.tsx index fa8f0db2b..0682fee55 100644 --- a/app/javascript/mastodon/utils/react_router.jsx +++ b/app/javascript/mastodon/utils/react_router.tsx @@ -1,8 +1,8 @@ -import PropTypes from "prop-types"; +import PropTypes from 'prop-types'; -import { __RouterContext } from "react-router"; +import { __RouterContext } from 'react-router'; -import hoistStatics from "hoist-non-react-statics"; +import hoistStatics from 'hoist-non-react-statics'; export const WithRouterPropTypes = { match: PropTypes.object.isRequired, @@ -16,31 +16,37 @@ export const WithOptionalRouterPropTypes = { history: PropTypes.object, }; +export interface OptionalRouterProps { + ref: unknown; + wrappedComponentRef: unknown; +} + // This is copied from https://github.com/remix-run/react-router/blob/v5.3.4/packages/react-router/modules/withRouter.js // but does not fail if called outside of a React Router context -export function withOptionalRouter(Component) { - const displayName = `withRouter(${Component.displayName || Component.name})`; - const C = props => { +export function withOptionalRouter< + ComponentType extends React.ComponentType<OptionalRouterProps>, +>(Component: ComponentType) { + const displayName = `withRouter(${Component.displayName ?? Component.name})`; + const C = (props: React.ComponentProps<ComponentType>) => { const { wrappedComponentRef, ...remainingProps } = props; return ( <__RouterContext.Consumer> - {context => { - if(context) + {(context) => { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (context) { return ( + // @ts-expect-error - Dynamic covariant generic components are tough to type. <Component {...remainingProps} {...context} ref={wrappedComponentRef} /> ); - else - return ( - <Component - {...remainingProps} - ref={wrappedComponentRef} - /> - ); + } else { + // @ts-expect-error - Dynamic covariant generic components are tough to type. + return <Component {...remainingProps} ref={wrappedComponentRef} />; + } }} </__RouterContext.Consumer> ); @@ -53,8 +59,8 @@ export function withOptionalRouter(Component) { wrappedComponentRef: PropTypes.oneOfType([ PropTypes.string, PropTypes.func, - PropTypes.object - ]) + PropTypes.object, + ]), }; return hoistStatics(C, Component); diff --git a/app/javascript/mastodon/utils/scrollbar.js b/app/javascript/mastodon/utils/scrollbar.ts similarity index 70% rename from app/javascript/mastodon/utils/scrollbar.js rename to app/javascript/mastodon/utils/scrollbar.ts index ca87dd76f..d505df124 100644 --- a/app/javascript/mastodon/utils/scrollbar.js +++ b/app/javascript/mastodon/utils/scrollbar.ts @@ -1,11 +1,7 @@ import { isMobile } from '../is_mobile'; -/** @type {number | null} */ -let cachedScrollbarWidth = null; +let cachedScrollbarWidth: number | null = null; -/** - * @returns {number} - */ const getActualScrollbarWidth = () => { const outer = document.createElement('div'); outer.style.visibility = 'hidden'; @@ -16,20 +12,19 @@ const getActualScrollbarWidth = () => { outer.appendChild(inner); const scrollbarWidth = outer.offsetWidth - inner.offsetWidth; - outer.parentNode.removeChild(outer); + outer.remove(); return scrollbarWidth; }; -/** - * @returns {number} - */ export const getScrollbarWidth = () => { if (cachedScrollbarWidth !== null) { return cachedScrollbarWidth; } - const scrollbarWidth = isMobile(window.innerWidth) ? 0 : getActualScrollbarWidth(); + const scrollbarWidth = isMobile(window.innerWidth) + ? 0 + : getActualScrollbarWidth(); cachedScrollbarWidth = scrollbarWidth; return scrollbarWidth; diff --git a/package.json b/package.json index 2f324f77a..543af8a4b 100644 --- a/package.json +++ b/package.json @@ -161,6 +161,7 @@ "@types/object-assign": "^4.0.30", "@types/prop-types": "^15.7.5", "@types/punycode": "^2.1.0", + "@types/rails__ujs": "^6.0.4", "@types/react": "^18.2.7", "@types/react-dom": "^18.2.4", "@types/react-helmet": "^6.1.6", diff --git a/yarn.lock b/yarn.lock index 0dd9a627c..11c2724d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2317,6 +2317,7 @@ __metadata: "@types/object-assign": "npm:^4.0.30" "@types/prop-types": "npm:^15.7.5" "@types/punycode": "npm:^2.1.0" + "@types/rails__ujs": "npm:^6.0.4" "@types/react": "npm:^18.2.7" "@types/react-dom": "npm:^18.2.4" "@types/react-helmet": "npm:^6.1.6" @@ -3349,6 +3350,13 @@ __metadata: languageName: node linkType: hard +"@types/rails__ujs@npm:^6.0.4": + version: 6.0.4 + resolution: "@types/rails__ujs@npm:6.0.4" + checksum: 7477cb03a0e1339b9cd5c8ac4a197a153e2ff48742b2f527c5a39dcdf80f01493011e368483290d3717662c63066fada3ab203a335804cbb3573cf575f37007e + languageName: node + linkType: hard + "@types/range-parser@npm:*": version: 1.2.7 resolution: "@types/range-parser@npm:1.2.7" From 3a7f10c3f10e6a7ab154030a2abf5a1a68c1b8f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= <git@joshuakgoldberg.com> Date: Tue, 28 Nov 2023 19:20:10 +0100 Subject: [PATCH 138/255] Converted hashtag.jsx to TypeScript (#27872) Co-authored-by: Claire <claire.github-309c@sitedethib.com> Co-authored-by: Renaud Chaput <renchap@gmail.com> --- .eslintrc.js | 3 +- .../mastodon/components/admin/Trends.jsx | 2 +- .../mastodon/components/hashtag.jsx | 120 --------------- .../mastodon/components/hashtag.tsx | 145 ++++++++++++++++++ .../account/components/featured_tags.jsx | 2 +- .../mastodon/features/followed_tags/index.jsx | 2 +- 6 files changed, 149 insertions(+), 125 deletions(-) delete mode 100644 app/javascript/mastodon/components/hashtag.jsx create mode 100644 app/javascript/mastodon/components/hashtag.tsx diff --git a/.eslintrc.js b/.eslintrc.js index a9aa86605..176879034 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -284,7 +284,6 @@ module.exports = defineConfig({ 'formatjs/no-id': 'off', // IDs are used for translation keys 'formatjs/no-invalid-icu': 'error', 'formatjs/no-literal-string-in-jsx': 'off', // Should be looked at, but mainly flagging punctuation outside of strings - 'formatjs/no-multiple-plurals': 'off', // Only used by hashtag.jsx 'formatjs/no-multiple-whitespaces': 'error', 'formatjs/no-offset': 'error', 'formatjs/no-useless-message': 'error', @@ -354,7 +353,7 @@ module.exports = defineConfig({ '@typescript-eslint/consistent-type-definitions': ['warn', 'interface'], '@typescript-eslint/consistent-type-exports': 'error', '@typescript-eslint/consistent-type-imports': 'error', - "@typescript-eslint/prefer-nullish-coalescing": ['error', {ignorePrimitives: {boolean: true}}], + "@typescript-eslint/prefer-nullish-coalescing": ['error', { ignorePrimitives: { boolean: true } }], 'jsdoc/require-jsdoc': 'off', diff --git a/app/javascript/mastodon/components/admin/Trends.jsx b/app/javascript/mastodon/components/admin/Trends.jsx index 49976276e..c69b4a8cb 100644 --- a/app/javascript/mastodon/components/admin/Trends.jsx +++ b/app/javascript/mastodon/components/admin/Trends.jsx @@ -6,7 +6,7 @@ import { FormattedMessage } from 'react-intl'; import classNames from 'classnames'; import api from 'mastodon/api'; -import Hashtag from 'mastodon/components/hashtag'; +import { Hashtag } from 'mastodon/components/hashtag'; export default class Trends extends PureComponent { diff --git a/app/javascript/mastodon/components/hashtag.jsx b/app/javascript/mastodon/components/hashtag.jsx deleted file mode 100644 index 14bb4ddc6..000000000 --- a/app/javascript/mastodon/components/hashtag.jsx +++ /dev/null @@ -1,120 +0,0 @@ -// @ts-check -import PropTypes from 'prop-types'; -import { Component } from 'react'; - -import { FormattedMessage } from 'react-intl'; - -import classNames from 'classnames'; -import { Link } from 'react-router-dom'; - -import ImmutablePropTypes from 'react-immutable-proptypes'; - -import { Sparklines, SparklinesCurve } from 'react-sparklines'; - -import { ShortNumber } from 'mastodon/components/short_number'; -import { Skeleton } from 'mastodon/components/skeleton'; - -class SilentErrorBoundary extends Component { - - static propTypes = { - children: PropTypes.node, - }; - - state = { - error: false, - }; - - componentDidCatch() { - this.setState({ error: true }); - } - - render() { - if (this.state.error) { - return null; - } - - return this.props.children; - } - -} - -/** - * Used to render counter of how much people are talking about hashtag - * @type {(displayNumber: JSX.Element, pluralReady: number) => JSX.Element} - */ -export const accountsCountRenderer = (displayNumber, pluralReady) => ( - <FormattedMessage - id='trends.counter_by_accounts' - defaultMessage='{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {# days}}' - values={{ - count: pluralReady, - counter: <strong>{displayNumber}</strong>, - days: 2, - }} - /> -); - -// @ts-expect-error -export const ImmutableHashtag = ({ hashtag }) => ( - <Hashtag - name={hashtag.get('name')} - to={`/tags/${hashtag.get('name')}`} - people={hashtag.getIn(['history', 0, 'accounts']) * 1 + hashtag.getIn(['history', 1, 'accounts']) * 1} - // @ts-expect-error - history={hashtag.get('history').reverse().map((day) => day.get('uses')).toArray()} - /> -); - -ImmutableHashtag.propTypes = { - hashtag: ImmutablePropTypes.map.isRequired, -}; - -// @ts-expect-error -const Hashtag = ({ name, to, people, uses, history, className, description, withGraph }) => ( - <div className={classNames('trends__item', className)}> - <div className='trends__item__name'> - <Link to={to}> - {name ? <>#<span>{name}</span></> : <Skeleton width={50} />} - </Link> - - {description ? ( - <span>{description}</span> - ) : ( - typeof people !== 'undefined' ? <ShortNumber value={people} renderer={accountsCountRenderer} /> : <Skeleton width={100} /> - )} - </div> - - {typeof uses !== 'undefined' && ( - <div className='trends__item__current'> - <ShortNumber value={uses} /> - </div> - )} - - {withGraph && ( - <div className='trends__item__sparkline'> - <SilentErrorBoundary> - <Sparklines width={50} height={28} data={history ? history : Array.from(Array(7)).map(() => 0)}> - <SparklinesCurve style={{ fill: 'none' }} /> - </Sparklines> - </SilentErrorBoundary> - </div> - )} - </div> -); - -Hashtag.propTypes = { - name: PropTypes.string, - to: PropTypes.string, - people: PropTypes.number, - description: PropTypes.node, - uses: PropTypes.number, - history: PropTypes.arrayOf(PropTypes.number), - className: PropTypes.string, - withGraph: PropTypes.bool, -}; - -Hashtag.defaultProps = { - withGraph: true, -}; - -export default Hashtag; diff --git a/app/javascript/mastodon/components/hashtag.tsx b/app/javascript/mastodon/components/hashtag.tsx new file mode 100644 index 000000000..8963e4a40 --- /dev/null +++ b/app/javascript/mastodon/components/hashtag.tsx @@ -0,0 +1,145 @@ +import type { JSX } from 'react'; +import { Component } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import classNames from 'classnames'; +import { Link } from 'react-router-dom'; + +import type Immutable from 'immutable'; + +import { Sparklines, SparklinesCurve } from 'react-sparklines'; + +import { ShortNumber } from 'mastodon/components/short_number'; +import { Skeleton } from 'mastodon/components/skeleton'; + +interface SilentErrorBoundaryProps { + children: React.ReactNode; +} + +class SilentErrorBoundary extends Component<SilentErrorBoundaryProps> { + state = { + error: false, + }; + + componentDidCatch() { + this.setState({ error: true }); + } + + render() { + if (this.state.error) { + return null; + } + + return this.props.children; + } +} + +/** + * Used to render counter of how much people are talking about hashtag + * @param displayNumber Counter number to display + * @param pluralReady Whether the count is plural + * @returns Formatted counter of how much people are talking about hashtag + */ +export const accountsCountRenderer = ( + displayNumber: JSX.Element, + pluralReady: number, +) => ( + <FormattedMessage + id='trends.counter_by_accounts' + defaultMessage='{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {# days}}' + values={{ + count: pluralReady, + counter: <strong>{displayNumber}</strong>, + days: 2, + }} + /> +); + +interface ImmutableHashtagProps { + hashtag: Immutable.Map<string, unknown>; +} + +export const ImmutableHashtag = ({ hashtag }: ImmutableHashtagProps) => ( + <Hashtag + name={hashtag.get('name') as string} + to={`/tags/${hashtag.get('name') as string}`} + people={ + (hashtag.getIn(['history', 0, 'accounts']) as number) * 1 + + (hashtag.getIn(['history', 1, 'accounts']) as number) * 1 + } + history={( + hashtag.get('history') as Immutable.Collection.Indexed< + Immutable.Map<string, number> + > + ) + .reverse() + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + .map((day) => day.get('uses')!) + .toArray()} + /> +); + +export interface HashtagProps { + className?: string; + description?: React.ReactNode; + history?: number[]; + name: string; + people: number; + to: string; + uses?: number; + withGraph?: boolean; +} + +export const Hashtag: React.FC<HashtagProps> = ({ + name, + to, + people, + uses, + history, + className, + description, + withGraph = true, +}) => ( + <div className={classNames('trends__item', className)}> + <div className='trends__item__name'> + <Link to={to}> + {name ? ( + <> + #<span>{name}</span> + </> + ) : ( + <Skeleton width={50} /> + )} + </Link> + + {description ? ( + <span>{description}</span> + ) : typeof people !== 'undefined' ? ( + <ShortNumber value={people} renderer={accountsCountRenderer} /> + ) : ( + <Skeleton width={100} /> + )} + </div> + + {typeof uses !== 'undefined' && ( + <div className='trends__item__current'> + <ShortNumber value={uses} /> + </div> + )} + + {withGraph && ( + <div className='trends__item__sparkline'> + <SilentErrorBoundary> + <Sparklines + width={50} + height={28} + data={history ? history : Array.from(Array(7)).map(() => 0)} + > + <SparklinesCurve style={{ fill: 'none' }} /> + </Sparklines> + </SilentErrorBoundary> + </div> + )} + </div> +); diff --git a/app/javascript/mastodon/features/account/components/featured_tags.jsx b/app/javascript/mastodon/features/account/components/featured_tags.jsx index 4d7dd8656..56a9efac0 100644 --- a/app/javascript/mastodon/features/account/components/featured_tags.jsx +++ b/app/javascript/mastodon/features/account/components/featured_tags.jsx @@ -5,7 +5,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import Hashtag from 'mastodon/components/hashtag'; +import { Hashtag } from 'mastodon/components/hashtag'; const messages = defineMessages({ lastStatusAt: { id: 'account.featured_tags.last_status_at', defaultMessage: 'Last post on {date}' }, diff --git a/app/javascript/mastodon/features/followed_tags/index.jsx b/app/javascript/mastodon/features/followed_tags/index.jsx index 7042f2438..dec53f012 100644 --- a/app/javascript/mastodon/features/followed_tags/index.jsx +++ b/app/javascript/mastodon/features/followed_tags/index.jsx @@ -13,7 +13,7 @@ import { debounce } from 'lodash'; import { expandFollowedHashtags, fetchFollowedHashtags } from 'mastodon/actions/tags'; import ColumnHeader from 'mastodon/components/column_header'; -import Hashtag from 'mastodon/components/hashtag'; +import { Hashtag } from 'mastodon/components/hashtag'; import ScrollableList from 'mastodon/components/scrollable_list'; import Column from 'mastodon/features/ui/components/column'; From b45fe15c06c020ee9e5303e4640f12b1db20ff29 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 28 Nov 2023 13:36:16 -0500 Subject: [PATCH 139/255] Update temple to version 0.10.3 (#28086) --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 972adae38..793869157 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -755,7 +755,7 @@ GEM attr_required (>= 0.0.5) httpclient (>= 2.4) sysexits (1.2.0) - temple (0.10.2) + temple (0.10.3) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) terrapin (0.6.0) From b9492d84a0f367ec6eb4cb609958fab5f850608e Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 28 Nov 2023 13:36:21 -0500 Subject: [PATCH 140/255] Update `bcrypt` to version 3.1.20 (#28084) --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 793869157..7440f1b32 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -156,7 +156,7 @@ GEM nokogiri (~> 1, >= 1.10.8) base64 (0.2.0) bcp47_spec (0.2.1) - bcrypt (3.1.19) + bcrypt (3.1.20) better_errors (2.10.1) erubi (>= 1.0.0) rack (>= 0.9.0) From 6b46bf99539112cb119958a5d79ffa46fe9c0a9c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Tue, 28 Nov 2023 13:37:54 -0500 Subject: [PATCH 141/255] Handle scenario when webfinger response `subject` is missing host value (#28088) --- app/services/resolve_account_service.rb | 4 +++- spec/services/resolve_account_service_spec.rb | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/services/resolve_account_service.rb b/app/services/resolve_account_service.rb index 6204fefd6..078a0423f 100644 --- a/app/services/resolve_account_service.rb +++ b/app/services/resolve_account_service.rb @@ -100,7 +100,9 @@ class ResolveAccountService < BaseService end def split_acct(acct) - acct.delete_prefix('acct:').split('@') + acct.delete_prefix('acct:').split('@').tap do |parts| + raise Webfinger::Error, 'Webfinger response is missing user or host value' unless parts.size == 2 + end end def fetch_account! diff --git a/spec/services/resolve_account_service_spec.rb b/spec/services/resolve_account_service_spec.rb index f446d0ca6..9f5fdca29 100644 --- a/spec/services/resolve_account_service_spec.rb +++ b/spec/services/resolve_account_service_spec.rb @@ -144,6 +144,19 @@ RSpec.describe ResolveAccountService, type: :service do end end + context 'with webfinger response subject missing a host value' do + let(:body) { Oj.dump({ subject: 'user@' }) } + let(:url) { 'https://host.example/.well-known/webfinger?resource=acct:user@host.example' } + + before do + stub_request(:get, url).to_return(status: 200, body: body) + end + + it 'returns nil with incomplete subject in response' do + expect(subject.call('user@host.example')).to be_nil + end + end + context 'with an ActivityPub account' do it 'returns new remote account' do account = subject.call('foo@ap.example.com') From 7a3b41eb54f24545854da6bb364f240fceff3c2f Mon Sep 17 00:00:00 2001 From: Michael Stanclift <mx@vmstan.com> Date: Tue, 28 Nov 2023 14:44:04 -0600 Subject: [PATCH 142/255] Fix incorrect apt-get install block in Dockerfile (#28112) --- Dockerfile | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/Dockerfile b/Dockerfile index 623a4d4ea..73267f380 100644 --- a/Dockerfile +++ b/Dockerfile @@ -177,29 +177,7 @@ FROM build as yarn ARG TARGETPLATFORM # Copy Node package configuration files into working directory -RUN apt-get update && \ - apt-get -yq dist-upgrade && \ - apt-get install -y --no-install-recommends build-essential \ - git \ - libicu-dev \ - libidn-dev \ - libpq-dev \ - libjemalloc-dev \ - zlib1g-dev \ - libgdbm-dev \ - libgmp-dev \ - libssl-dev \ - libyaml-dev \ - ca-certificates \ - libreadline8 \ - python3 \ - shared-mime-info && \ - bundle config set --local deployment 'true' && \ - bundle config set --local without 'development test' && \ - bundle config set silence_root_warning true && \ - corepack enable - -COPY Gemfile* package.json yarn.lock .yarnrc.yml /opt/mastodon/ +COPY package.json yarn.lock .yarnrc.yml /opt/mastodon/ COPY streaming/package.json /opt/mastodon/streaming/ COPY .yarn /opt/mastodon/.yarn From c40cfc5d0905651dcf3c1e5fa04c0bd06da6e9d1 Mon Sep 17 00:00:00 2001 From: Michael Stanclift <mx@vmstan.com> Date: Tue, 28 Nov 2023 16:23:44 -0600 Subject: [PATCH 143/255] Fix apt cache not being properly utilized in Dockerfile (#28115) --- Dockerfile | 4 ++-- streaming/Dockerfile | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 73267f380..ed5ebf1e0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -70,6 +70,8 @@ ARG TARGETPLATFORM RUN echo "Target platform is $TARGETPLATFORM" RUN \ +# Remove automatic apt cache Docker cleanup scripts + rm -f /etc/apt/apt.conf.d/docker-clean; \ # Sets timezone echo "${TZ}" > /etc/localtime; \ # Creates mastodon user/group and sets home directory @@ -127,7 +129,6 @@ RUN \ --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \ --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \ # Install build tools and bundler dependencies from APT - apt-get update; \ apt-get install -y --no-install-recommends \ g++ \ gcc \ @@ -221,7 +222,6 @@ RUN \ --mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \ --mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \ # Apt update install non-dev versions of necessary components - apt-get update; \ apt-get install -y --no-install-recommends \ libssl3 \ libpq5 \ diff --git a/streaming/Dockerfile b/streaming/Dockerfile index ee62e9ec7..6e0a84771 100644 --- a/streaming/Dockerfile +++ b/streaming/Dockerfile @@ -47,6 +47,8 @@ ARG TARGETPLATFORM RUN echo "Target platform is ${TARGETPLATFORM}" RUN \ +# Remove automatic apt cache Docker cleanup scripts + rm -f /etc/apt/apt.conf.d/docker-clean; \ # Sets timezone echo "${TZ}" > /etc/localtime; \ # Creates mastodon user/group and sets home directory @@ -60,7 +62,7 @@ RUN \ # Mount Apt cache and lib directories from Docker buildx caches --mount=type=cache,id=apt-cache-${TARGETPLATFORM},target=/var/cache/apt,sharing=locked \ --mount=type=cache,id=apt-lib-${TARGETPLATFORM},target=/var/lib/apt,sharing=locked \ -# upgrade to check for security updates to Debian image +# Upgrade to check for security updates to Debian image apt-get update; \ apt-get dist-upgrade -yq; \ apt-get install -y --no-install-recommends \ From 603b245cc62acba0d8f71ad4c31d2f1676e90190 Mon Sep 17 00:00:00 2001 From: Emelia Smith <ThisIsMissEm@users.noreply.github.com> Date: Wed, 29 Nov 2023 09:34:36 +0100 Subject: [PATCH 144/255] Add VAPID public key to instance serializer (#28006) Co-authored-by: Renaud Chaput <renchap@gmail.com> --- app/serializers/rest/application_serializer.rb | 5 ++++- app/serializers/rest/instance_serializer.rb | 4 ++++ spec/serializers/rest/instance_serializer_spec.rb | 6 ++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/serializers/rest/application_serializer.rb b/app/serializers/rest/application_serializer.rb index e4806a3c9..635508a17 100644 --- a/app/serializers/rest/application_serializer.rb +++ b/app/serializers/rest/application_serializer.rb @@ -2,7 +2,10 @@ class REST::ApplicationSerializer < ActiveModel::Serializer attributes :id, :name, :website, :scopes, :redirect_uri, - :client_id, :client_secret, :vapid_key + :client_id, :client_secret + + # NOTE: Deprecated in 4.3.0, needs to be removed in 5.0.0 + attribute :vapid_key def id object.id.to_s diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb index 14aeda946..d7ed381e1 100644 --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@ -48,6 +48,10 @@ class REST::InstanceSerializer < ActiveModel::Serializer status: object.status_page_url, }, + vapid: { + public_key: Rails.configuration.x.vapid_public_key, + }, + accounts: { max_featured_tags: FeaturedTag::LIMIT, }, diff --git a/spec/serializers/rest/instance_serializer_spec.rb b/spec/serializers/rest/instance_serializer_spec.rb index 8ac32f224..d8f2536d2 100644 --- a/spec/serializers/rest/instance_serializer_spec.rb +++ b/spec/serializers/rest/instance_serializer_spec.rb @@ -10,5 +10,11 @@ describe REST::InstanceSerializer do it 'returns recent usage data' do expect(serialization['usage']).to eq({ 'users' => { 'active_month' => 0 } }) end + + it 'returns the VAPID public key' do + expect(serialization['configuration']['vapid']).to eq({ + 'public_key' => Rails.configuration.x.vapid_public_key, + }) + end end end From 3e1e41054ba40294ecf70c1216759fc378f46ee0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:00:07 +0100 Subject: [PATCH 145/255] chore(deps): update dependency pghero to v3.4.0 (#28117) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 7440f1b32..40f85c7d4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -522,7 +522,7 @@ GEM pastel (0.8.0) tty-color (~> 0.5) pg (1.5.4) - pghero (3.3.4) + pghero (3.4.0) activerecord (>= 6) posix-spawn (0.3.15) premailer (1.21.0) From 186895fc887d8729185fc51f994dca93a30592b1 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 29 Nov 2023 05:00:52 -0500 Subject: [PATCH 146/255] Refactor, lint fix, and bug fix on admin/roles/form partial (#27558) --- app/helpers/admin/roles_helper.rb | 24 ++++++++++++++++++++++++ app/models/user_role.rb | 6 +++--- app/views/admin/roles/_form.html.haml | 2 +- 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 app/helpers/admin/roles_helper.rb diff --git a/app/helpers/admin/roles_helper.rb b/app/helpers/admin/roles_helper.rb new file mode 100644 index 000000000..7b4702e26 --- /dev/null +++ b/app/helpers/admin/roles_helper.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Admin + module RolesHelper + def privilege_label(privilege) + safe_join( + [ + t("admin.roles.privileges.#{privilege}"), + content_tag(:span, t("admin.roles.privileges.#{privilege}_description"), class: 'hint'), + ] + ) + end + + def disable_permissions?(permissions) + permissions.filter { |privilege| role_flag_value(privilege).zero? } + end + + private + + def role_flag_value(privilege) + UserRole::FLAGS[privilege] & current_user.role.computed_permissions + end + end +end diff --git a/app/models/user_role.rb b/app/models/user_role.rb index 5472646c6..89354da54 100644 --- a/app/models/user_role.rb +++ b/app/models/user_role.rb @@ -49,7 +49,7 @@ class UserRole < ApplicationRecord invite_users ).freeze, - moderation: %w( + moderation: %i( view_dashboard view_audit_log manage_users @@ -63,7 +63,7 @@ class UserRole < ApplicationRecord manage_invites ).freeze, - administration: %w( + administration: %i( manage_settings manage_rules manage_roles @@ -72,7 +72,7 @@ class UserRole < ApplicationRecord manage_announcements ).freeze, - devops: %w( + devops: %i( view_devops ).freeze, diff --git a/app/views/admin/roles/_form.html.haml b/app/views/admin/roles/_form.html.haml index 240033214..46a1c537a 100644 --- a/app/views/admin/roles/_form.html.haml +++ b/app/views/admin/roles/_form.html.haml @@ -31,6 +31,6 @@ - (form.object.everyone? ? UserRole::Flags::CATEGORIES.slice(:invites) : UserRole::Flags::CATEGORIES).each do |category, permissions| %h4= t(category, scope: 'admin.roles.categories') - = form.input :permissions_as_keys, collection: permissions, wrapper: :with_block_label, include_blank: false, label_method: ->(privilege) { safe_join([t("admin.roles.privileges.#{privilege}"), content_tag(:span, t("admin.roles.privileges.#{privilege}_description"), class: 'hint')]) }, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', label: false, hint: false, disabled: permissions.filter { |privilege| UserRole::FLAGS[privilege] & current_user.role.computed_permissions == 0 } + = form.input :permissions_as_keys, collection: permissions, wrapper: :with_block_label, include_blank: false, label_method: ->(privilege) { privilege_label(privilege) }, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', label: false, hint: false, disabled: disable_permissions?(permissions) %hr.spacer/ From 9b47c5d53c24cd5bd9ee84169f4f05bb81f3ed88 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 29 Nov 2023 05:02:59 -0500 Subject: [PATCH 147/255] Extract helper methods for labels from filters/_filter_fields (#27574) --- app/helpers/filters_helper.rb | 12 ++++++++++++ app/views/filters/_filter_fields.html.haml | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 app/helpers/filters_helper.rb diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb new file mode 100644 index 000000000..22a1c172d --- /dev/null +++ b/app/helpers/filters_helper.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module FiltersHelper + def filter_action_label(action) + safe_join( + [ + t("simple_form.labels.filters.actions.#{action}"), + content_tag(:span, t("simple_form.hints.filters.actions.#{action}"), class: 'hint'), + ] + ) + end +end diff --git a/app/views/filters/_filter_fields.html.haml b/app/views/filters/_filter_fields.html.haml index 0690e8dd5..a3260816e 100644 --- a/app/views/filters/_filter_fields.html.haml +++ b/app/views/filters/_filter_fields.html.haml @@ -10,7 +10,7 @@ %hr.spacer/ .fields-group - = f.input :filter_action, as: :radio_buttons, collection: %i(warn hide), include_blank: false, wrapper: :with_block_label, label_method: ->(action) { safe_join([t("simple_form.labels.filters.actions.#{action}"), content_tag(:span, t("simple_form.hints.filters.actions.#{action}"), class: 'hint')]) }, hint: t('simple_form.hints.filters.action'), required: true + = f.input :filter_action, as: :radio_buttons, collection: %i(warn hide), include_blank: false, wrapper: :with_block_label, label_method: ->(action) { filter_action_label(action) }, hint: t('simple_form.hints.filters.action'), required: true %hr.spacer/ From 72b7cd349ccffb557d2c55f4ba76b525ff47ef9e Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 29 Nov 2023 05:06:19 -0500 Subject: [PATCH 148/255] Extract helper methods for form label in admin/ area views (#27575) --- app/helpers/admin/account_actions_helper.rb | 12 ++++++++++++ app/helpers/admin/accounts_helper.rb | 19 +++++++++++++++++++ app/helpers/admin/ip_blocks_helper.rb | 12 ++++++++++++ .../admin/settings/discovery_helper.rb | 15 +++++++++++++++ app/views/admin/account_actions/new.html.haml | 2 +- app/views/admin/accounts/index.html.haml | 2 +- app/views/admin/ip_blocks/new.html.haml | 2 +- .../admin/settings/discovery/show.html.haml | 2 +- 8 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 app/helpers/admin/account_actions_helper.rb create mode 100644 app/helpers/admin/accounts_helper.rb create mode 100644 app/helpers/admin/ip_blocks_helper.rb create mode 100644 app/helpers/admin/settings/discovery_helper.rb diff --git a/app/helpers/admin/account_actions_helper.rb b/app/helpers/admin/account_actions_helper.rb new file mode 100644 index 000000000..e132680a6 --- /dev/null +++ b/app/helpers/admin/account_actions_helper.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Admin::AccountActionsHelper + def account_action_type_label(type) + safe_join( + [ + I18n.t("simple_form.labels.admin_account_action.types.#{type}"), + content_tag(:span, I18n.t("simple_form.hints.admin_account_action.types.#{type}"), class: 'hint'), + ] + ) + end +end diff --git a/app/helpers/admin/accounts_helper.rb b/app/helpers/admin/accounts_helper.rb new file mode 100644 index 000000000..a936797e8 --- /dev/null +++ b/app/helpers/admin/accounts_helper.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Admin::AccountsHelper + def admin_accounts_moderation_options + [ + [t('admin.accounts.moderation.active'), 'active'], + [t('admin.accounts.moderation.silenced'), 'silenced'], + [t('admin.accounts.moderation.disabled'), 'disabled'], + [t('admin.accounts.moderation.suspended'), 'suspended'], + [safe_join([t('admin.accounts.moderation.pending'), "(#{pending_user_count_label})"], ' '), 'pending'], + ] + end + + private + + def pending_user_count_label + number_with_delimiter User.pending.count + end +end diff --git a/app/helpers/admin/ip_blocks_helper.rb b/app/helpers/admin/ip_blocks_helper.rb new file mode 100644 index 000000000..4aae3aae7 --- /dev/null +++ b/app/helpers/admin/ip_blocks_helper.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Admin::IpBlocksHelper + def ip_blocks_severity_label(severity) + safe_join( + [ + I18n.t("simple_form.labels.ip_block.severities.#{severity}"), + content_tag(:span, I18n.t("simple_form.hints.ip_block.severities.#{severity}"), class: 'hint'), + ] + ) + end +end diff --git a/app/helpers/admin/settings/discovery_helper.rb b/app/helpers/admin/settings/discovery_helper.rb new file mode 100644 index 000000000..0aa4d4368 --- /dev/null +++ b/app/helpers/admin/settings/discovery_helper.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Admin::Settings::DiscoveryHelper + def discovery_warning_hint_text + authorized_fetch_overridden? ? t('admin.settings.security.authorized_fetch_overridden_hint') : nil + end + + def discovery_hint_text + t('admin.settings.security.authorized_fetch_hint') + end + + def discovery_recommended_value + authorized_fetch_overridden? ? :overridden : nil + end +end diff --git a/app/views/admin/account_actions/new.html.haml b/app/views/admin/account_actions/new.html.haml index 2a0cae15a..4cb4401c7 100644 --- a/app/views/admin/account_actions/new.html.haml +++ b/app/views/admin/account_actions/new.html.haml @@ -5,7 +5,7 @@ = f.input :report_id, as: :hidden .fields-group - = f.input :type, as: :radio_buttons, collection: Admin::AccountAction.types_for_account(@account), include_blank: false, wrapper: :with_block_label, label_method: ->(type) { safe_join([I18n.t("simple_form.labels.admin_account_action.types.#{type}"), content_tag(:span, I18n.t("simple_form.hints.admin_account_action.types.#{type}"), class: 'hint')]) }, hint: t('simple_form.hints.admin_account_action.type_html', acct: @account.pretty_acct) + = f.input :type, as: :radio_buttons, collection: Admin::AccountAction.types_for_account(@account), include_blank: false, wrapper: :with_block_label, label_method: ->(type) { account_action_type_label(type) }, hint: t('simple_form.hints.admin_account_action.type_html', acct: @account.pretty_acct) - if @account.local? %hr.spacer/ diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml index 9cec8d632..835444189 100644 --- a/app/views/admin/accounts/index.html.haml +++ b/app/views/admin/accounts/index.html.haml @@ -10,7 +10,7 @@ .filter-subset.filter-subset--with-select %strong= t('admin.accounts.moderation.title') .input.select.optional - = select_tag :status, options_for_select([[t('admin.accounts.moderation.active'), 'active'], [t('admin.accounts.moderation.silenced'), 'silenced'], [t('admin.accounts.moderation.disabled'), 'disabled'], [t('admin.accounts.moderation.suspended'), 'suspended'], [safe_join([t('admin.accounts.moderation.pending'), "(#{number_with_delimiter(User.pending.count)})"], ' '), 'pending']], params[:status]), prompt: I18n.t('generic.all') + = select_tag :status, options_for_select(admin_accounts_moderation_options, params[:status]), prompt: I18n.t('generic.all') .filter-subset.filter-subset--with-select %strong= t('admin.accounts.role') .input.select.optional diff --git a/app/views/admin/ip_blocks/new.html.haml b/app/views/admin/ip_blocks/new.html.haml index 405c73c90..ecaf04315 100644 --- a/app/views/admin/ip_blocks/new.html.haml +++ b/app/views/admin/ip_blocks/new.html.haml @@ -11,7 +11,7 @@ = f.input :expires_in, wrapper: :with_block_label, collection: [1.day, 2.weeks, 1.month, 6.months, 1.year, 3.years].map(&:to_i), label_method: ->(i) { I18n.t("admin.ip_blocks.expires_in.#{i}") }, prompt: I18n.t('invites.expires_in_prompt') .fields-group - = f.input :severity, as: :radio_buttons, collection: IpBlock.severities.keys, include_blank: false, wrapper: :with_block_label, label_method: ->(severity) { safe_join([I18n.t("simple_form.labels.ip_block.severities.#{severity}"), content_tag(:span, I18n.t("simple_form.hints.ip_block.severities.#{severity}"), class: 'hint')]) } + = f.input :severity, as: :radio_buttons, collection: IpBlock.severities.keys, include_blank: false, wrapper: :with_block_label, label_method: ->(severity) { ip_blocks_severity_label(severity) } .fields-group = f.input :comment, as: :string, wrapper: :with_block_label diff --git a/app/views/admin/settings/discovery/show.html.haml b/app/views/admin/settings/discovery/show.html.haml index 62011d5c5..59fc3226a 100644 --- a/app/views/admin/settings/discovery/show.html.haml +++ b/app/views/admin/settings/discovery/show.html.haml @@ -42,7 +42,7 @@ %h4= t('admin.settings.security.federation_authentication') .fields-group - = f.input :authorized_fetch, as: :boolean, wrapper: :with_label, label: t('admin.settings.security.authorized_fetch'), warning_hint: authorized_fetch_overridden? ? t('admin.settings.security.authorized_fetch_overridden_hint') : nil, hint: t('admin.settings.security.authorized_fetch_hint'), disabled: authorized_fetch_overridden?, recommended: authorized_fetch_overridden? ? :overridden : nil + = f.input :authorized_fetch, as: :boolean, wrapper: :with_label, label: t('admin.settings.security.authorized_fetch'), warning_hint: discovery_warning_hint_text, hint: discovery_hint_text, disabled: authorized_fetch_overridden?, recommended: discovery_recommended_value %h4= t('admin.settings.discovery.follow_recommendations') From 31bef99b9edf8ad52182f9dcc5012d3c799b9fe4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 29 Nov 2023 05:08:55 -0500 Subject: [PATCH 149/255] Move lib/mastodon/premailer_webpack_strategy to lib/ (#27636) --- .rubocop_todo.yml | 2 +- config/initializers/premailer_rails.rb | 2 +- lib/{mastodon => }/premailer_webpack_strategy.rb | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename lib/{mastodon => }/premailer_webpack_strategy.rb (100%) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 167204604..a79f88f97 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -307,7 +307,7 @@ Style/FetchEnvVar: - 'config/initializers/devise.rb' - 'config/initializers/paperclip.rb' - 'config/initializers/vapid.rb' - - 'lib/mastodon/premailer_webpack_strategy.rb' + - 'lib/premailer_webpack_strategy.rb' - 'lib/mastodon/redis_config.rb' - 'lib/tasks/repo.rake' - 'spec/features/profile_spec.rb' diff --git a/config/initializers/premailer_rails.rb b/config/initializers/premailer_rails.rb index 98b208271..52576ef88 100644 --- a/config/initializers/premailer_rails.rb +++ b/config/initializers/premailer_rails.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require_relative '../../lib/mastodon/premailer_webpack_strategy' +require_relative '../../lib/premailer_webpack_strategy' Premailer::Rails.config.merge!(remove_ids: true, adapter: :nokogiri, diff --git a/lib/mastodon/premailer_webpack_strategy.rb b/lib/premailer_webpack_strategy.rb similarity index 100% rename from lib/mastodon/premailer_webpack_strategy.rb rename to lib/premailer_webpack_strategy.rb From a1636fce7f2eb630b6c8d0a4524b1687b61e3496 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 29 Nov 2023 05:10:21 -0500 Subject: [PATCH 150/255] Move lib/devise/* to lib/devise/strategies/* (#27638) --- .rubocop_todo.yml | 8 ++++---- config/application.rb | 4 ++-- .../{ => strategies}/two_factor_ldap_authenticatable.rb | 0 .../{ => strategies}/two_factor_pam_authenticatable.rb | 0 4 files changed, 6 insertions(+), 6 deletions(-) rename lib/devise/{ => strategies}/two_factor_ldap_authenticatable.rb (100%) rename lib/devise/{ => strategies}/two_factor_pam_authenticatable.rb (100%) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index a79f88f97..43af4f670 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -357,8 +357,8 @@ Style/GuardClause: - 'config/initializers/devise.rb' - 'db/migrate/20170901141119_truncate_preview_cards.rb' - 'db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb' - - 'lib/devise/two_factor_ldap_authenticatable.rb' - - 'lib/devise/two_factor_pam_authenticatable.rb' + - 'lib/devise/strategies/two_factor_ldap_authenticatable.rb' + - 'lib/devise/strategies/two_factor_pam_authenticatable.rb' - 'lib/mastodon/cli/accounts.rb' - 'lib/mastodon/cli/maintenance.rb' - 'lib/mastodon/cli/media.rb' @@ -493,8 +493,8 @@ Style/SafeNavigation: # SupportedStyles: only_raise, only_fail, semantic Style/SignalException: Exclude: - - 'lib/devise/two_factor_ldap_authenticatable.rb' - - 'lib/devise/two_factor_pam_authenticatable.rb' + - 'lib/devise/strategies/two_factor_ldap_authenticatable.rb' + - 'lib/devise/strategies/two_factor_pam_authenticatable.rb' # This cop supports unsafe autocorrection (--autocorrect-all). Style/SingleArgumentDig: diff --git a/config/application.rb b/config/application.rb index 387827784..99ee4ffd7 100644 --- a/config/application.rb +++ b/config/application.rb @@ -39,8 +39,8 @@ require_relative '../lib/mastodon/snowflake' require_relative '../lib/mastodon/version' require_relative '../lib/mastodon/rack_middleware' require_relative '../lib/public_file_server_middleware' -require_relative '../lib/devise/two_factor_ldap_authenticatable' -require_relative '../lib/devise/two_factor_pam_authenticatable' +require_relative '../lib/devise/strategies/two_factor_ldap_authenticatable' +require_relative '../lib/devise/strategies/two_factor_pam_authenticatable' require_relative '../lib/chewy/settings_extensions' require_relative '../lib/chewy/index_extensions' require_relative '../lib/chewy/strategy/mastodon' diff --git a/lib/devise/two_factor_ldap_authenticatable.rb b/lib/devise/strategies/two_factor_ldap_authenticatable.rb similarity index 100% rename from lib/devise/two_factor_ldap_authenticatable.rb rename to lib/devise/strategies/two_factor_ldap_authenticatable.rb diff --git a/lib/devise/two_factor_pam_authenticatable.rb b/lib/devise/strategies/two_factor_pam_authenticatable.rb similarity index 100% rename from lib/devise/two_factor_pam_authenticatable.rb rename to lib/devise/strategies/two_factor_pam_authenticatable.rb From 291dc04e67f963313958a23de7ba935fa7130996 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 29 Nov 2023 05:38:05 -0500 Subject: [PATCH 151/255] Remove un-needed `action` and `template` options to `render` in controllers (#28022) --- .../admin/account_moderation_notes_controller.rb | 2 +- app/controllers/admin/relays_controller.rb | 2 +- app/controllers/admin/report_notes_controller.rb | 2 +- app/controllers/concerns/challengable_concern.rb | 2 +- app/controllers/disputes/appeals_controller.rb | 2 +- app/controllers/filters_controller.rb | 4 ++-- app/controllers/statuses_cleanup_controller.rb | 2 +- spec/controllers/concerns/challengable_concern_spec.rb | 6 +++--- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/controllers/admin/account_moderation_notes_controller.rb b/app/controllers/admin/account_moderation_notes_controller.rb index 4f36f33f4..8b6c1a445 100644 --- a/app/controllers/admin/account_moderation_notes_controller.rb +++ b/app/controllers/admin/account_moderation_notes_controller.rb @@ -16,7 +16,7 @@ module Admin @moderation_notes = @account.targeted_moderation_notes.latest @warnings = @account.strikes.custom.latest - render template: 'admin/accounts/show' + render 'admin/accounts/show' end end diff --git a/app/controllers/admin/relays_controller.rb b/app/controllers/admin/relays_controller.rb index c1297c8b9..c89380215 100644 --- a/app/controllers/admin/relays_controller.rb +++ b/app/controllers/admin/relays_controller.rb @@ -24,7 +24,7 @@ module Admin @relay.enable! redirect_to admin_relays_path else - render action: :new + render :new end end diff --git a/app/controllers/admin/report_notes_controller.rb b/app/controllers/admin/report_notes_controller.rb index 3fd815b60..b5f04a1ca 100644 --- a/app/controllers/admin/report_notes_controller.rb +++ b/app/controllers/admin/report_notes_controller.rb @@ -26,7 +26,7 @@ module Admin @form = Admin::StatusBatchAction.new @statuses = @report.statuses.with_includes - render template: 'admin/reports/show' + render 'admin/reports/show' end end diff --git a/app/controllers/concerns/challengable_concern.rb b/app/controllers/concerns/challengable_concern.rb index 2995a25e0..09874fb40 100644 --- a/app/controllers/concerns/challengable_concern.rb +++ b/app/controllers/concerns/challengable_concern.rb @@ -43,7 +43,7 @@ module ChallengableConcern def render_challenge @body_classes = 'lighter' - render template: 'auth/challenges/new', layout: 'auth' + render 'auth/challenges/new', layout: 'auth' end def challenge_passed? diff --git a/app/controllers/disputes/appeals_controller.rb b/app/controllers/disputes/appeals_controller.rb index eefd92b5a..98b58d211 100644 --- a/app/controllers/disputes/appeals_controller.rb +++ b/app/controllers/disputes/appeals_controller.rb @@ -11,7 +11,7 @@ class Disputes::AppealsController < Disputes::BaseController redirect_to disputes_strike_path(@strike), notice: I18n.t('disputes.strikes.appealed_msg') rescue ActiveRecord::RecordInvalid => e @appeal = e.record - render template: 'disputes/strikes/show' + render 'disputes/strikes/show' end private diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb index bbe177ead..bd9964426 100644 --- a/app/controllers/filters_controller.rb +++ b/app/controllers/filters_controller.rb @@ -25,7 +25,7 @@ class FiltersController < ApplicationController if @filter.save redirect_to filters_path else - render action: :new + render :new end end @@ -33,7 +33,7 @@ class FiltersController < ApplicationController if @filter.update(resource_params) redirect_to filters_path else - render action: :edit + render :edit end end diff --git a/app/controllers/statuses_cleanup_controller.rb b/app/controllers/statuses_cleanup_controller.rb index 19ae971ce..4a3fc10ca 100644 --- a/app/controllers/statuses_cleanup_controller.rb +++ b/app/controllers/statuses_cleanup_controller.rb @@ -14,7 +14,7 @@ class StatusesCleanupController < ApplicationController if @policy.update(resource_params) redirect_to statuses_cleanup_path, notice: I18n.t('generic.changes_saved_msg') else - render action: :show + render :show end rescue ActionController::ParameterMissing # Do nothing diff --git a/spec/controllers/concerns/challengable_concern_spec.rb b/spec/controllers/concerns/challengable_concern_spec.rb index 3324bdd24..169e2122f 100644 --- a/spec/controllers/concerns/challengable_concern_spec.rb +++ b/spec/controllers/concerns/challengable_concern_spec.rb @@ -85,7 +85,7 @@ RSpec.describe ChallengableConcern do before { get :foo } it 'renders challenge' do - expect(response).to render_template('auth/challenges/new') + expect(response).to render_template('auth/challenges/new', layout: :auth) end # See Auth::ChallengesControllerSpec @@ -95,7 +95,7 @@ RSpec.describe ChallengableConcern do before { post :bar } it 'renders challenge' do - expect(response).to render_template('auth/challenges/new') + expect(response).to render_template('auth/challenges/new', layout: :auth) end it 'accepts correct password' do @@ -106,7 +106,7 @@ RSpec.describe ChallengableConcern do it 'rejects wrong password' do post :bar, params: { form_challenge: { current_password: 'dddfff888123' } } - expect(response.body).to render_template('auth/challenges/new') + expect(response.body).to render_template('auth/challenges/new', layout: :auth) expect(session[:challenge_passed_at]).to be_nil end end From e48ecd29294ec2790fd38fd1a35b8490d1350c4e Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 29 Nov 2023 05:39:59 -0500 Subject: [PATCH 152/255] Remove `default_scope` from `Admin::ActionLog` (#28026) --- app/controllers/admin/action_logs_controller.rb | 2 +- app/models/admin/action_log.rb | 4 ++-- app/models/admin/action_log_filter.rb | 12 ++++++++---- app/models/report.rb | 10 +++++----- ...on_log_fabricator.rb => action_log_fabricator.rb} | 2 +- spec/models/report_spec.rb | 6 +++--- 6 files changed, 20 insertions(+), 16 deletions(-) rename spec/fabricators/{admin_action_log_fabricator.rb => action_log_fabricator.rb} (68%) diff --git a/app/controllers/admin/action_logs_controller.rb b/app/controllers/admin/action_logs_controller.rb index 42edec15a..37a00ad22 100644 --- a/app/controllers/admin/action_logs_controller.rb +++ b/app/controllers/admin/action_logs_controller.rb @@ -6,7 +6,7 @@ module Admin def index authorize :audit_log, :index? - @auditable_accounts = Account.where(id: Admin::ActionLog.reorder(nil).select('distinct account_id')).select(:id, :username) + @auditable_accounts = Account.where(id: Admin::ActionLog.select('distinct account_id')).select(:id, :username) end private diff --git a/app/models/admin/action_log.rb b/app/models/admin/action_log.rb index f2c121d75..49ae67980 100644 --- a/app/models/admin/action_log.rb +++ b/app/models/admin/action_log.rb @@ -24,12 +24,12 @@ class Admin::ActionLog < ApplicationRecord belongs_to :account belongs_to :target, polymorphic: true, optional: true - default_scope -> { order('id desc') } - before_validation :set_human_identifier before_validation :set_route_param before_validation :set_permalink + scope :latest, -> { order(id: :desc) } + def action super.to_sym end diff --git a/app/models/admin/action_log_filter.rb b/app/models/admin/action_log_filter.rb index 011797462..d413cb386 100644 --- a/app/models/admin/action_log_filter.rb +++ b/app/models/admin/action_log_filter.rb @@ -72,7 +72,7 @@ class Admin::ActionLogFilter end def results - scope = Admin::ActionLog.includes(:target) + scope = latest_action_logs.includes(:target) params.each do |key, value| next if key.to_s == 'page' @@ -88,14 +88,18 @@ class Admin::ActionLogFilter def scope_for(key, value) case key when 'action_type' - Admin::ActionLog.where(ACTION_TYPE_MAP[value.to_sym]) + latest_action_logs.where(ACTION_TYPE_MAP[value.to_sym]) when 'account_id' - Admin::ActionLog.where(account_id: value) + latest_action_logs.where(account_id: value) when 'target_account_id' account = Account.find_or_initialize_by(id: value) - Admin::ActionLog.where(target: [account, account.user].compact) + latest_action_logs.where(target: [account, account.user].compact) else raise Mastodon::InvalidParameterError, "Unknown filter: #{key}" end end + + def latest_action_logs + Admin::ActionLog.latest + end end diff --git a/app/models/report.rb b/app/models/report.rb index 81ad721df..c565362cc 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -131,25 +131,25 @@ class Report < ApplicationRecord Admin::ActionLog.where( target_type: 'Report', target_id: id - ).unscope(:order).arel, + ).arel, Admin::ActionLog.where( target_type: 'Account', target_id: target_account_id - ).unscope(:order).arel, + ).arel, Admin::ActionLog.where( target_type: 'Status', target_id: status_ids - ).unscope(:order).arel, + ).arel, Admin::ActionLog.where( target_type: 'AccountWarning', target_id: AccountWarning.where(report_id: id).select(:id) - ).unscope(:order).arel, + ).arel, ].reduce { |union, query| Arel::Nodes::UnionAll.new(union, query) } - Admin::ActionLog.from(Arel::Nodes::As.new(subquery, Admin::ActionLog.arel_table)) + Admin::ActionLog.latest.from(Arel::Nodes::As.new(subquery, Admin::ActionLog.arel_table)) end private diff --git a/spec/fabricators/admin_action_log_fabricator.rb b/spec/fabricators/action_log_fabricator.rb similarity index 68% rename from spec/fabricators/admin_action_log_fabricator.rb rename to spec/fabricators/action_log_fabricator.rb index 3acedbffd..ce52cb73a 100644 --- a/spec/fabricators/admin_action_log_fabricator.rb +++ b/spec/fabricators/action_log_fabricator.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -Fabricator('Admin::ActionLog') do +Fabricator(:action_log, from: Admin::ActionLog) do account { Fabricate.build(:account) } action 'MyString' target nil diff --git a/spec/models/report_spec.rb b/spec/models/report_spec.rb index 0093dcd8d..c514c63b3 100644 --- a/spec/models/report_spec.rb +++ b/spec/models/report_spec.rb @@ -110,9 +110,9 @@ describe Report do let(:status) { Fabricate(:status) } before do - Fabricate('Admin::ActionLog', target_type: 'Report', account_id: target_account.id, target_id: report.id, created_at: 2.days.ago) - Fabricate('Admin::ActionLog', target_type: 'Account', account_id: target_account.id, target_id: report.target_account_id, created_at: 2.days.ago) - Fabricate('Admin::ActionLog', target_type: 'Status', account_id: target_account.id, target_id: status.id, created_at: 2.days.ago) + Fabricate(:action_log, target_type: 'Report', account_id: target_account.id, target_id: report.id, created_at: 2.days.ago) + Fabricate(:action_log, target_type: 'Account', account_id: target_account.id, target_id: report.target_account_id, created_at: 2.days.ago) + Fabricate(:action_log, target_type: 'Status', account_id: target_account.id, target_id: status.id, created_at: 2.days.ago) end it 'returns right logs' do From 6e55ff964325694c9a06914e59733babfc4854c7 Mon Sep 17 00:00:00 2001 From: Filippo Giunchedi <filippog@users.noreply.github.com> Date: Thu, 30 Nov 2023 11:46:06 +0100 Subject: [PATCH 153/255] Change Vagrant to install Node 20 (#28100) Co-authored-by: Filippo Giunchedi <filippo@debian.org> --- Vagrantfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Vagrantfile b/Vagrantfile index e2c66a476..6f0f51109 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -10,7 +10,11 @@ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - sudo apt-add-repository 'deb https://dl.yarnpkg.com/debian/ stable main' # Add repo for NodeJS -curl -sL https://deb.nodesource.com/setup_16.x | sudo bash - +sudo mkdir -p /etc/apt/keyrings +curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg +NODE_MAJOR=20 +echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list +sudo apt-get update # Add firewall rule to redirect 80 to PORT and save sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{ENV["PORT"]} From b696ca6b1a0fee1e56fcf70f4c561ff2661ad81d Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 30 Nov 2023 05:48:46 -0500 Subject: [PATCH 154/255] Move self destruct CLI command definition code to module (#28131) --- lib/mastodon/cli/federation.rb | 74 ++++++++++++++++++++++++++++++++++ lib/mastodon/cli/main.rb | 62 +--------------------------- 2 files changed, 76 insertions(+), 60 deletions(-) create mode 100644 lib/mastodon/cli/federation.rb diff --git a/lib/mastodon/cli/federation.rb b/lib/mastodon/cli/federation.rb new file mode 100644 index 000000000..1b4cb467a --- /dev/null +++ b/lib/mastodon/cli/federation.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require 'tty-prompt' + +module Mastodon::CLI + module Federation + extend ActiveSupport::Concern + + included do + desc 'self-destruct', 'Erase the server from the federation' + long_desc <<~LONG_DESC + Erase the server from the federation by broadcasting account delete + activities to all known other servers. This allows a "clean exit" from + running a Mastodon server, as it leaves next to no cache behind on + other servers. + + This command is always interactive and requires confirmation twice. + + No local data is actually deleted, because emptying the + database or removing files is much faster through other, external + means, such as e.g. deleting the entire VPS. However, because other + servers will delete data about local users, but no local data will be + updated (such as e.g. followers), there will be a state mismatch + that will lead to glitches and issues if you then continue to run and use + the server. + + So either you know exactly what you are doing, or you are starting + from a blank slate afterwards by manually clearing out all the local + data! + LONG_DESC + def self_destruct + if SelfDestructHelper.self_destruct? + prompt.ok('Self-destruct mode is already enabled for this Mastodon server') + + pending_accounts = Account.local.without_suspended.count + Account.local.suspended.joins(:deletion_request).count + sidekiq_stats = Sidekiq::Stats.new + + if pending_accounts.positive? + prompt.warn("#{pending_accounts} accounts are still pending deletion.") + elsif sidekiq_stats.enqueued.positive? + prompt.warn('Deletion notices are still being processed') + elsif sidekiq_stats.retry_size.positive? + prompt.warn('At least one delivery attempt for each deletion notice has been made, but some have failed and are scheduled for retry') + else + prompt.ok('Every deletion notice has been sent! You can safely delete all data and decomission your servers!') + end + + exit(0) + end + + exit(1) unless prompt.ask('Type in the domain of the server to confirm:', required: true) == Rails.configuration.x.local_domain + + prompt.warn('This operation WILL NOT be reversible.') + prompt.warn('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.') + prompt.warn('The deletion process itself may take a long time, and will be handled by Sidekiq, so do not shut it down until it has finished (you will be able to re-run this command to see the state of the self-destruct process).') + + exit(1) if prompt.no?('Are you sure you want to proceed?') + + self_destruct_value = Rails.application.message_verifier('self-destruct').generate(Rails.configuration.x.local_domain) + prompt.ok('To switch Mastodon to self-destruct mode, add the following variable to your evironment (e.g. by adding a line to your `.env.production`) and restart all Mastodon processes:') + prompt.ok(" SELF_DESTRUCT=#{self_destruct_value}") + prompt.ok("\nYou can re-run this command to see the state of the self-destruct process.") + rescue TTY::Reader::InputInterrupt + exit(1) + end + + private + + def prompt + @prompt ||= TTY::Prompt.new + end + end + end +end diff --git a/lib/mastodon/cli/main.rb b/lib/mastodon/cli/main.rb index 64f1646f4..ef40b81f3 100644 --- a/lib/mastodon/cli/main.rb +++ b/lib/mastodon/cli/main.rb @@ -8,6 +8,7 @@ require_relative 'canonical_email_blocks' require_relative 'domains' require_relative 'email_domain_blocks' require_relative 'emoji' +require_relative 'federation' require_relative 'feeds' require_relative 'ip_blocks' require_relative 'maintenance' @@ -65,66 +66,7 @@ module Mastodon::CLI desc 'maintenance SUBCOMMAND ...ARGS', 'Various maintenance utilities' subcommand 'maintenance', Maintenance - desc 'self-destruct', 'Erase the server from the federation' - long_desc <<~LONG_DESC - Erase the server from the federation by broadcasting account delete - activities to all known other servers. This allows a "clean exit" from - running a Mastodon server, as it leaves next to no cache behind on - other servers. - - This command is always interactive and requires confirmation twice. - - No local data is actually deleted, because emptying the - database or removing files is much faster through other, external - means, such as e.g. deleting the entire VPS. However, because other - servers will delete data about local users, but no local data will be - updated (such as e.g. followers), there will be a state mismatch - that will lead to glitches and issues if you then continue to run and use - the server. - - So either you know exactly what you are doing, or you are starting - from a blank slate afterwards by manually clearing out all the local - data! - LONG_DESC - def self_destruct - require 'tty-prompt' - - prompt = TTY::Prompt.new - - if SelfDestructHelper.self_destruct? - prompt.ok('Self-destruct mode is already enabled for this Mastodon server') - - pending_accounts = Account.local.without_suspended.count + Account.local.suspended.joins(:deletion_request).count - sidekiq_stats = Sidekiq::Stats.new - - if pending_accounts.positive? - prompt.warn("#{pending_accounts} accounts are still pending deletion.") - elsif sidekiq_stats.enqueued.positive? - prompt.warn('Deletion notices are still being processed') - elsif sidekiq_stats.retry_size.positive? - prompt.warn('At least one delivery attempt for each deletion notice has been made, but some have failed and are scheduled for retry') - else - prompt.ok('Every deletion notice has been sent! You can safely delete all data and decomission your servers!') - end - - exit(0) - end - - exit(1) unless prompt.ask('Type in the domain of the server to confirm:', required: true) == Rails.configuration.x.local_domain - - prompt.warn('This operation WILL NOT be reversible.') - prompt.warn('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.') - prompt.warn('The deletion process itself may take a long time, and will be handled by Sidekiq, so do not shut it down until it has finished (you will be able to re-run this command to see the state of the self-destruct process).') - - exit(1) if prompt.no?('Are you sure you want to proceed?') - - self_destruct_value = Rails.application.message_verifier('self-destruct').generate(Rails.configuration.x.local_domain) - prompt.ok('To switch Mastodon to self-destruct mode, add the following variable to your evironment (e.g. by adding a line to your `.env.production`) and restart all Mastodon processes:') - prompt.ok(" SELF_DESTRUCT=#{self_destruct_value}") - prompt.ok("\nYou can re-run this command to see the state of the self-destruct process.") - rescue TTY::Reader::InputInterrupt - exit(1) - end + include Federation map %w(--version -v) => :version From c761cc4738c74519c65a99c5ab24874584605d2d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 11:53:49 +0100 Subject: [PATCH 155/255] fix(deps): update babel monorepo to v7.23.5 (#28122) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 260 +++++++++++++++++++++++++++--------------------------- 1 file changed, 130 insertions(+), 130 deletions(-) diff --git a/yarn.lock b/yarn.lock index 11c2724d5..69464dfa2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,55 +42,55 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.22.13": - version: 7.22.13 - resolution: "@babel/code-frame@npm:7.22.13" +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/code-frame@npm:7.23.5" dependencies: - "@babel/highlight": "npm:^7.22.13" + "@babel/highlight": "npm:^7.23.4" chalk: "npm:^2.4.2" - checksum: f4cc8ae1000265677daf4845083b72f88d00d311adb1a93c94eb4b07bf0ed6828a81ae4ac43ee7d476775000b93a28a9cddec18fbdc5796212d8dcccd5de72bd + checksum: a10e843595ddd9f97faa99917414813c06214f4d9205294013e20c70fbdf4f943760da37dec1d998bf3e6fc20fa2918a47c0e987a7e458663feb7698063ad7c6 languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9, @babel/compat-data@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/compat-data@npm:7.23.3" - checksum: c6af331753c34ee8a5678bc94404320826cb56b1dda3efc1311ec8fb0774e78225132f3c1acc988440ace667f14a838e297a822692b95758aa63da406e1f97a1 +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9, @babel/compat-data@npm:^7.23.3, @babel/compat-data@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/compat-data@npm:7.23.5" + checksum: 081278ed46131a890ad566a59c61600a5f9557bd8ee5e535890c8548192532ea92590742fd74bd9db83d74c669ef8a04a7e1c85cdea27f960233e3b83c3a957c languageName: node linkType: hard "@babel/core@npm:^7.10.4, @babel/core@npm:^7.11.1, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1": - version: 7.23.3 - resolution: "@babel/core@npm:7.23.3" + version: 7.23.5 + resolution: "@babel/core@npm:7.23.5" dependencies: "@ampproject/remapping": "npm:^2.2.0" - "@babel/code-frame": "npm:^7.22.13" - "@babel/generator": "npm:^7.23.3" + "@babel/code-frame": "npm:^7.23.5" + "@babel/generator": "npm:^7.23.5" "@babel/helper-compilation-targets": "npm:^7.22.15" "@babel/helper-module-transforms": "npm:^7.23.3" - "@babel/helpers": "npm:^7.23.2" - "@babel/parser": "npm:^7.23.3" + "@babel/helpers": "npm:^7.23.5" + "@babel/parser": "npm:^7.23.5" "@babel/template": "npm:^7.22.15" - "@babel/traverse": "npm:^7.23.3" - "@babel/types": "npm:^7.23.3" + "@babel/traverse": "npm:^7.23.5" + "@babel/types": "npm:^7.23.5" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 08d43b749e24052d12713a7fb1f0c0d1275d4fb056d00846faeb8da79ecf6d0ba91a11b6afec407b8b0f9388d00e2c2f485f282bef0ade4d6d0a17de191a4287 + checksum: 311a512a870ee330a3f9a7ea89e5df790b2b5af0b1bd98b10b4edc0de2ac440f0df4d69ea2c0ee38a4b89041b9a495802741d93603be7d4fd834ec8bb6970bd2 languageName: node linkType: hard -"@babel/generator@npm:^7.23.3, @babel/generator@npm:^7.7.2": - version: 7.23.3 - resolution: "@babel/generator@npm:7.23.3" +"@babel/generator@npm:^7.23.5, @babel/generator@npm:^7.7.2": + version: 7.23.5 + resolution: "@babel/generator@npm:7.23.5" dependencies: - "@babel/types": "npm:^7.23.3" + "@babel/types": "npm:^7.23.5" "@jridgewell/gen-mapping": "npm:^0.3.2" "@jridgewell/trace-mapping": "npm:^0.3.17" jsesc: "npm:^2.5.1" - checksum: d5fff1417eecfada040e01a7c77a4968e81c436aeb35815ce85b4e80cd01e731423613d61033044a6cb5563bb8449ee260e3379b63eb50b38ec0a9ea9c00abfd + checksum: 14c6e874f796c4368e919bed6003bb0adc3ce837760b08f9e646d20aeb5ae7d309723ce6e4f06bcb4a2b5753145446c8e4425851380f695e40e71e1760f49e7b languageName: node linkType: hard @@ -310,10 +310,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-string-parser@npm:7.22.5" - checksum: 6b0ff8af724377ec41e5587fffa7605198da74cb8e7d8d48a36826df0c0ba210eb9fedb3d9bef4d541156e0bd11040f021945a6cbb731ccec4aefb4affa17aa4 +"@babel/helper-string-parser@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/helper-string-parser@npm:7.23.4" + checksum: f348d5637ad70b6b54b026d6544bd9040f78d24e7ec245a0fc42293968181f6ae9879c22d89744730d246ce8ec53588f716f102addd4df8bbc79b73ea10004ac languageName: node linkType: hard @@ -324,10 +324,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/helper-validator-option@npm:7.22.15" - checksum: e9661bf80ba18e2dd978217b350fb07298e57ac417f4f1ab9fa011505e20e4857f2c3b4b538473516a9dc03af5ce3a831e5ed973311c28326f4c330b6be981c2 +"@babel/helper-validator-option@npm:^7.22.15, @babel/helper-validator-option@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/helper-validator-option@npm:7.23.5" + checksum: af45d5c0defb292ba6fd38979e8f13d7da63f9623d8ab9ededc394f67eb45857d2601278d151ae9affb6e03d5d608485806cd45af08b4468a0515cf506510e94 languageName: node linkType: hard @@ -342,34 +342,34 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.23.2": - version: 7.23.2 - resolution: "@babel/helpers@npm:7.23.2" +"@babel/helpers@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/helpers@npm:7.23.5" dependencies: "@babel/template": "npm:^7.22.15" - "@babel/traverse": "npm:^7.23.2" - "@babel/types": "npm:^7.23.0" - checksum: 3a6a939c5277a27486e7c626812f0643b35d1c053ac2eb66911f5ae6c0a4e4bcdd40750eba36b766b0ee8a753484287f50ae56232a5f8f2947116723e44b9e35 + "@babel/traverse": "npm:^7.23.5" + "@babel/types": "npm:^7.23.5" + checksum: a37e2728eb4378a4888e5d614e28de7dd79b55ac8acbecd0e5c761273e2a02a8f33b34b1932d9069db55417ace2937cbf8ec37c42f1030ce6d228857d7ccaa4f languageName: node linkType: hard -"@babel/highlight@npm:^7.22.13": - version: 7.22.20 - resolution: "@babel/highlight@npm:7.22.20" +"@babel/highlight@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/highlight@npm:7.23.4" dependencies: "@babel/helper-validator-identifier": "npm:^7.22.20" chalk: "npm:^2.4.2" js-tokens: "npm:^4.0.0" - checksum: f3c3a193afad23434297d88e81d1d6c0c2cf02423de2139ada7ce0a7fc62d8559abf4cc996533c1a9beca7fc990010eb8d544097f75e818ac113bf39ed810aa2 + checksum: fbff9fcb2f5539289c3c097d130e852afd10d89a3a08ac0b5ebebbc055cc84a4bcc3dcfed463d488cde12dd0902ef1858279e31d7349b2e8cee43913744bda33 languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/parser@npm:7.23.3" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/parser@npm:7.23.5" bin: parser: ./bin/babel-parser.js - checksum: 0fe11eadd4146a9155305b5bfece0f8223a3b1b97357ffa163c0156940de92e76cd0e7a173de819b8692767147e62f33389b312d1537f84cede51092672df6ef + checksum: 3356aa90d7bafb4e2c7310e7c2c3d443c4be4db74913f088d3d577a1eb914ea4188e05fd50a47ce907a27b755c4400c4e3cbeee73dbeb37761f6ca85954f5a20 languageName: node linkType: hard @@ -661,9 +661,9 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.23.3" +"@babel/plugin-transform-async-generator-functions@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.23.4" dependencies: "@babel/helper-environment-visitor": "npm:^7.22.20" "@babel/helper-plugin-utils": "npm:^7.22.5" @@ -671,7 +671,7 @@ __metadata: "@babel/plugin-syntax-async-generators": "npm:^7.8.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e846f282658e097fce4fccf3ee29289bf05f0654846a5994727a36f0cdc2e47abdffd4be4fa65787e94aa975824fae894c90afbfdc8caacd46c12c7f43e99d7f + checksum: f2eef4de609975a3f7da7832576b5ffc93e43c80f87e1a99e886b0f8591096cfc4c37e2d5f52fdeaa2a9c09a25a59f3e621159abaca75d3193922a5c0e4cbe0c languageName: node linkType: hard @@ -699,14 +699,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-block-scoping@npm:7.23.3" +"@babel/plugin-transform-block-scoping@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-block-scoping@npm:7.23.4" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: ccaeded7954c196811d22a35322579254cda52676e823682b6234885a3aaf88fe0d5152dacaec43db9031dcf35a050a5343e36028e5905b0ba9c02d36b30a57f + checksum: 83006804dddf980ab1bcd6d67bc381e24b58c776507c34f990468f820d0da71dba3697355ca4856532fa2eeb2a1e3e73c780f03760b5507a511cbedb0308e276 languageName: node linkType: hard @@ -722,22 +722,22 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-class-static-block@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-class-static-block@npm:7.23.3" +"@babel/plugin-transform-class-static-block@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-class-static-block@npm:7.23.4" dependencies: "@babel/helper-create-class-features-plugin": "npm:^7.22.15" "@babel/helper-plugin-utils": "npm:^7.22.5" "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.12.0 - checksum: 89cdb66d7bc834cd51659eb7286a6bee23add0bc114943d68c4b6c0c834178cf0d55183df0cf508fec9c55ed4155641360e6f55a91c16fe826ccaf1adf381922 + checksum: fdca96640ef29d8641a7f8de106f65f18871b38cc01c0f7b696d2b49c76b77816b30a812c08e759d06dd10b4d9b3af6b5e4ac22a2017a88c4077972224b77ab0 languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-classes@npm:7.23.3" +"@babel/plugin-transform-classes@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/plugin-transform-classes@npm:7.23.5" dependencies: "@babel/helper-annotate-as-pure": "npm:^7.22.5" "@babel/helper-compilation-targets": "npm:^7.22.15" @@ -750,7 +750,7 @@ __metadata: globals: "npm:^11.1.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 88bfd332db0ba5cbfb8557a2ba5a7185151aebc9cfe3035b014aa6d795556acbe672bb8c78da3c9fd1d23f55a333d14b5daa127ef037f5ced5198b6d79a146d6 + checksum: 07988f52b4893151887d1ea6ff79e5fe834078c5731bd09babd5659edbbae21ea4e2de326a02443a63fd776b4c945da6177f07875b56fe66e0b7899e830a9e92 languageName: node linkType: hard @@ -800,15 +800,15 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-dynamic-import@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-dynamic-import@npm:7.23.3" +"@babel/plugin-transform-dynamic-import@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.23.4" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: df3fd130312dc53d068fa76333991dce5e86987b023af8c3b502bd7d36a8e67da6f718e61dc838576a9fbacd06628e29607ee22d9bae30705485c14130eab201 + checksum: 19ae4a4a2ca86d35224734c41c48b2aa6a13139f3cfa1cbd18c0e65e461de8b65687dec7e52b7a72bb49db04465394c776aa1b13a2af5dc975b2a0cde3dcab67 languageName: node linkType: hard @@ -824,15 +824,15 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-export-namespace-from@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-export-namespace-from@npm:7.23.3" +"@babel/plugin-transform-export-namespace-from@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.23.4" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 390c6626dcda99023629049d92090242b4575351a4a7b47f97febabd2381f2cd0f624de661d8de8d1f715fedd63753cfd1feddead19e5960c27b88e447465b81 + checksum: 38bf04f851e36240bbe83ace4169da626524f4107bfb91f05b4ad93a5fb6a36d5b3d30b8883c1ba575ccfc1bac7938e90ca2e3cb227f7b3f4a9424beec6fd4a7 languageName: node linkType: hard @@ -860,15 +860,15 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-json-strings@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-json-strings@npm:7.23.3" +"@babel/plugin-transform-json-strings@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-json-strings@npm:7.23.4" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" "@babel/plugin-syntax-json-strings": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e1cef6a485b9da32aba9449fb459dac062dfc401f3d6ad48e7fbdcb73bbe470c995cc15ce5c421b95efe1e9a90d5507eb606360fe10b6d8cb869dd5dae7a2562 + checksum: 39e82223992a9ad857722ae051291935403852ad24b0dd64c645ca1c10517b6bf9822377d88643fed8b3e61a4e3f7e5ae41cf90eb07c40a786505d47d5970e54 languageName: node linkType: hard @@ -883,15 +883,15 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-logical-assignment-operators@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.23.3" +"@babel/plugin-transform-logical-assignment-operators@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.23.4" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 23b7588b26d420c8b132bd08916d49871ca0c8db892f6b58637b10e2a0d918163d413c505db880a9157fc2e61d089040f139298a60d837ccbd0efca0474ac7ca + checksum: 87b034dd13143904e405887e6125d76c27902563486efc66b7d9a9d8f9406b76c6ac42d7b37224014af5783d7edb465db0cdecd659fa3227baad0b3a6a35deff languageName: node linkType: hard @@ -980,7 +980,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.3, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.23.3": +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.3, @babel/plugin-transform-nullish-coalescing-operator@npm:^7.23.4": version: 7.23.4 resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.23.4" dependencies: @@ -992,21 +992,21 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-numeric-separator@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-numeric-separator@npm:7.23.3" +"@babel/plugin-transform-numeric-separator@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.23.4" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d3748cce20e8752e61dfda55e275c699459a3ff8d0bb46585da813136e04066b1ce70b71beef504fcdc8d4cca3c955112cea96d5e9fd5a42a5bc8956d05236c2 + checksum: e34902da4f5588dc4812c92cb1f6a5e3e3647baf7b4623e30942f551bf1297621abec4e322ebfa50b320c987c0f34d9eb4355b3d289961d9035e2126e3119c12 languageName: node linkType: hard -"@babel/plugin-transform-object-rest-spread@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-object-rest-spread@npm:7.23.3" +"@babel/plugin-transform-object-rest-spread@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.23.4" dependencies: "@babel/compat-data": "npm:^7.23.3" "@babel/helper-compilation-targets": "npm:^7.22.15" @@ -1015,7 +1015,7 @@ __metadata: "@babel/plugin-transform-parameters": "npm:^7.23.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 31ab631aaba945c118662943e5f1f54a21f07d64f06e06b25d55871168c460f3eeeccdf7b05aa74a1340e2cfbe781ad3c7ceccd0c2585d39f7b73ba11ebaa9d0 + checksum: b56017992ffe7fcd1dd9a9da67c39995a141820316266bcf7d77dc912980d228ccbd3f36191d234f5cc389b09157b5d2a955e33e8fb368319534affd1c72b262 languageName: node linkType: hard @@ -1031,28 +1031,28 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-optional-catch-binding@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.23.3" +"@babel/plugin-transform-optional-catch-binding@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.23.4" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 85ac1e94ee8f21648816151628ff931cc16143ec8c904649a1ecfd8960160290eccc5a197b4ae3ee7a1c7a27a7c4189e61b4de24483d5bad4040784afe2d206f + checksum: 4ef61812af0e4928485e28301226ce61139a8b8cea9e9a919215ebec4891b9fea2eb7a83dc3090e2679b7d7b2c8653da601fbc297d2addc54a908b315173991e languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.23.3" +"@babel/plugin-transform-optional-chaining@npm:^7.23.3, @babel/plugin-transform-optional-chaining@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.23.4" dependencies: "@babel/helper-plugin-utils": "npm:^7.22.5" "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2b358962169d871392aa292a67527e5335909438da0ddbb0d19e7838c0f8a2081cc751a49e6e534ac4d6c932254531a205ac22b197f64fc4c89f41bf9f595497 + checksum: 305b773c29ad61255b0e83ec1e92b2f7af6aa58be4cba1e3852bddaa14f7d2afd7b4438f41c28b179d6faac7eb8d4fb5530a17920294f25d459b8f84406bfbfb languageName: node linkType: hard @@ -1079,9 +1079,9 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-private-property-in-object@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/plugin-transform-private-property-in-object@npm:7.23.3" +"@babel/plugin-transform-private-property-in-object@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.23.4" dependencies: "@babel/helper-annotate-as-pure": "npm:^7.22.5" "@babel/helper-create-class-features-plugin": "npm:^7.22.15" @@ -1089,7 +1089,7 @@ __metadata: "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9211dd25a6e87a01535f2d97a663fa6de3472b963c8dcfaacce229a2e3fa6500f2e9fc690bc100a540fc7b66c8364faf7ef19b32e9c9b9791e4561b742c15ed3 + checksum: 8d31b28f24204b4d13514cd3a8f3033abf575b1a6039759ddd6e1d82dd33ba7281f9bc85c9f38072a665d69bfa26dc40737eefaf9d397b024654a483d2357bf5 languageName: node linkType: hard @@ -1333,13 +1333,13 @@ __metadata: linkType: hard "@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.12.1, @babel/preset-env@npm:^7.22.4": - version: 7.23.3 - resolution: "@babel/preset-env@npm:7.23.3" + version: 7.23.5 + resolution: "@babel/preset-env@npm:7.23.5" dependencies: - "@babel/compat-data": "npm:^7.23.3" + "@babel/compat-data": "npm:^7.23.5" "@babel/helper-compilation-targets": "npm:^7.22.15" "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-validator-option": "npm:^7.22.15" + "@babel/helper-validator-option": "npm:^7.23.5" "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.23.3" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.23.3" "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.23.3" @@ -1363,25 +1363,25 @@ __metadata: "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" "@babel/plugin-syntax-unicode-sets-regex": "npm:^7.18.6" "@babel/plugin-transform-arrow-functions": "npm:^7.23.3" - "@babel/plugin-transform-async-generator-functions": "npm:^7.23.3" + "@babel/plugin-transform-async-generator-functions": "npm:^7.23.4" "@babel/plugin-transform-async-to-generator": "npm:^7.23.3" "@babel/plugin-transform-block-scoped-functions": "npm:^7.23.3" - "@babel/plugin-transform-block-scoping": "npm:^7.23.3" + "@babel/plugin-transform-block-scoping": "npm:^7.23.4" "@babel/plugin-transform-class-properties": "npm:^7.23.3" - "@babel/plugin-transform-class-static-block": "npm:^7.23.3" - "@babel/plugin-transform-classes": "npm:^7.23.3" + "@babel/plugin-transform-class-static-block": "npm:^7.23.4" + "@babel/plugin-transform-classes": "npm:^7.23.5" "@babel/plugin-transform-computed-properties": "npm:^7.23.3" "@babel/plugin-transform-destructuring": "npm:^7.23.3" "@babel/plugin-transform-dotall-regex": "npm:^7.23.3" "@babel/plugin-transform-duplicate-keys": "npm:^7.23.3" - "@babel/plugin-transform-dynamic-import": "npm:^7.23.3" + "@babel/plugin-transform-dynamic-import": "npm:^7.23.4" "@babel/plugin-transform-exponentiation-operator": "npm:^7.23.3" - "@babel/plugin-transform-export-namespace-from": "npm:^7.23.3" + "@babel/plugin-transform-export-namespace-from": "npm:^7.23.4" "@babel/plugin-transform-for-of": "npm:^7.23.3" "@babel/plugin-transform-function-name": "npm:^7.23.3" - "@babel/plugin-transform-json-strings": "npm:^7.23.3" + "@babel/plugin-transform-json-strings": "npm:^7.23.4" "@babel/plugin-transform-literals": "npm:^7.23.3" - "@babel/plugin-transform-logical-assignment-operators": "npm:^7.23.3" + "@babel/plugin-transform-logical-assignment-operators": "npm:^7.23.4" "@babel/plugin-transform-member-expression-literals": "npm:^7.23.3" "@babel/plugin-transform-modules-amd": "npm:^7.23.3" "@babel/plugin-transform-modules-commonjs": "npm:^7.23.3" @@ -1389,15 +1389,15 @@ __metadata: "@babel/plugin-transform-modules-umd": "npm:^7.23.3" "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.22.5" "@babel/plugin-transform-new-target": "npm:^7.23.3" - "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.23.3" - "@babel/plugin-transform-numeric-separator": "npm:^7.23.3" - "@babel/plugin-transform-object-rest-spread": "npm:^7.23.3" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.23.4" + "@babel/plugin-transform-numeric-separator": "npm:^7.23.4" + "@babel/plugin-transform-object-rest-spread": "npm:^7.23.4" "@babel/plugin-transform-object-super": "npm:^7.23.3" - "@babel/plugin-transform-optional-catch-binding": "npm:^7.23.3" - "@babel/plugin-transform-optional-chaining": "npm:^7.23.3" + "@babel/plugin-transform-optional-catch-binding": "npm:^7.23.4" + "@babel/plugin-transform-optional-chaining": "npm:^7.23.4" "@babel/plugin-transform-parameters": "npm:^7.23.3" "@babel/plugin-transform-private-methods": "npm:^7.23.3" - "@babel/plugin-transform-private-property-in-object": "npm:^7.23.3" + "@babel/plugin-transform-private-property-in-object": "npm:^7.23.4" "@babel/plugin-transform-property-literals": "npm:^7.23.3" "@babel/plugin-transform-regenerator": "npm:^7.23.3" "@babel/plugin-transform-reserved-words": "npm:^7.23.3" @@ -1418,7 +1418,7 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 36b02a86817ab5474bb74a8d62a110723b0b05904a52ddc5627cf89457525b8d5ac0739b8e435a6ae12ef8b90cd5fc191169898c3dc2ac9d2c84026b02f2580a + checksum: 2a0e1274dec045186e131c6433659b75492583290e8d41633c616f6bff829cb2e4b2f9a57f556283a54db3bd6aa697911e56a36f607911a29b731c445a5b5a06 languageName: node linkType: hard @@ -1502,32 +1502,32 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:7, @babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/traverse@npm:7.23.3" +"@babel/traverse@npm:7, @babel/traverse@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/traverse@npm:7.23.5" dependencies: - "@babel/code-frame": "npm:^7.22.13" - "@babel/generator": "npm:^7.23.3" + "@babel/code-frame": "npm:^7.23.5" + "@babel/generator": "npm:^7.23.5" "@babel/helper-environment-visitor": "npm:^7.22.20" "@babel/helper-function-name": "npm:^7.23.0" "@babel/helper-hoist-variables": "npm:^7.22.5" "@babel/helper-split-export-declaration": "npm:^7.22.6" - "@babel/parser": "npm:^7.23.3" - "@babel/types": "npm:^7.23.3" + "@babel/parser": "npm:^7.23.5" + "@babel/types": "npm:^7.23.5" debug: "npm:^4.1.0" globals: "npm:^11.1.0" - checksum: 3c2784f4765185126d64fd5eebce0413b7aee6d54f779998594a343a7f973a9693a441ba27533df84e7ab7ce22f1239c6837f35e903132a1b25f7fc7a67bc30f + checksum: c5ea793080ca6719b0a1612198fd25e361cee1f3c14142d7a518d2a1eeb5c1d21f7eec1b26c20ea6e1ddd8ed12ab50b960ff95ffd25be353b6b46e1b54d6f825 languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.3, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.23.3 - resolution: "@babel/types@npm:7.23.3" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.23.5 + resolution: "@babel/types@npm:7.23.5" dependencies: - "@babel/helper-string-parser": "npm:^7.22.5" + "@babel/helper-string-parser": "npm:^7.23.4" "@babel/helper-validator-identifier": "npm:^7.22.20" to-fast-properties: "npm:^2.0.0" - checksum: 371a10dd9c8d8ebf48fc5d9e1b327dafd74453f8ea582dcbddd1cee5ae34e8881b743e783a86c08c04dcd1849b1842455472a911ae8a1c185484fe9b7b5f1595 + checksum: 7dd5e2f59828ed046ad0b06b039df2524a8b728d204affb4fc08da2502b9dd3140b1356b5166515d229dc811539a8b70dcd4bc507e06d62a89f4091a38d0b0fb languageName: node linkType: hard From e6fd9a59e6f7a37fcd1276c75aadfddd79c784ca Mon Sep 17 00:00:00 2001 From: Filippo Giunchedi <filippog@users.noreply.github.com> Date: Thu, 30 Nov 2023 11:58:40 +0100 Subject: [PATCH 156/255] Fix FamiliarFollowersController test response comparison (#28121) Co-authored-by: Filippo Giunchedi <filippo@debian.org> --- .../api/v1/accounts/familiar_followers_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb b/spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb index 226177309..3c7c7e8b8 100644 --- a/spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb @@ -28,7 +28,7 @@ describe Api::V1::Accounts::FamiliarFollowersController do account_ids = [account_a, account_b, account_b, account_a, account_a].map { |a| a.id.to_s } get :index, params: { id: account_ids } - expect(body_as_json.pluck(:id)).to eq [account_a.id.to_s, account_b.id.to_s] + expect(body_as_json.pluck(:id)).to contain_exactly(account_a.id.to_s, account_b.id.to_s) end end end From ce78a9c9ac3e579d9de1c410d005860a80774a3c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 30 Nov 2023 06:44:42 -0500 Subject: [PATCH 157/255] Clean up `two_factor_authentication/confirmations` controller spec (#28128) --- .../confirmations_controller_spec.rb | 126 +++++++++--------- 1 file changed, 64 insertions(+), 62 deletions(-) diff --git a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb index a5a35e91d..1b3b0cb0a 100644 --- a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb +++ b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb @@ -20,37 +20,30 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do [true, false].each do |with_otp_secret| let(:user) { Fabricate(:user, email: 'local-part@domain', otp_secret: with_otp_secret ? 'oldotpsecret' : nil) } - describe 'GET #new' do - context 'when signed in and a new otp secret has been set in the session' do - subject do - sign_in user, scope: :user - get :new, session: { challenge_passed_at: Time.now.utc, new_otp_secret: 'thisisasecretforthespecofnewview' } + context 'when signed in' do + before { sign_in user, scope: :user } + + describe 'GET #new' do + context 'when a new otp secret has been set in the session' do + subject do + get :new, session: { challenge_passed_at: Time.now.utc, new_otp_secret: 'thisisasecretforthespecofnewview' } + end + + include_examples 'renders :new' end - include_examples 'renders :new' - end + it 'redirects if a new otp_secret has not been set in the session' do + get :new, session: { challenge_passed_at: Time.now.utc } - it 'redirects if not signed in' do - get :new - expect(response).to redirect_to('/auth/sign_in') - end - - it 'redirects if a new otp_secret has not been set in the session' do - sign_in user, scope: :user - get :new, session: { challenge_passed_at: Time.now.utc } - expect(response).to redirect_to('/settings/otp_authentication') - end - end - - describe 'POST #create' do - context 'when signed in' do - before do - sign_in user, scope: :user + expect(response).to redirect_to('/settings/otp_authentication') end + end + describe 'POST #create' do describe 'when form_two_factor_confirmation parameter is not provided' do it 'raises ActionController::ParameterMissing' do post :create, params: {}, session: { challenge_passed_at: Time.now.utc, new_otp_secret: 'thisisasecretforthespecofnewview' } + expect(response).to have_http_status(400) end end @@ -58,69 +51,78 @@ describe Settings::TwoFactorAuthentication::ConfirmationsController do describe 'when creation succeeds' do let!(:otp_backup_codes) { user.generate_otp_backup_codes! } - it 'renders page with success' do + before do prepare_user_otp_generation - prepare_user_otp_consumption + prepare_user_otp_consumption_response(true) allow(controller).to receive(:current_user).and_return(user) + end - expect do - post :create, - params: { form_two_factor_confirmation: { otp_attempt: '123456' } }, - session: { challenge_passed_at: Time.now.utc, new_otp_secret: 'thisisasecretforthespecofnewview' } - end.to change { user.reload.otp_secret }.to 'thisisasecretforthespecofnewview' + it 'renders page with success' do + expect { post_create_with_options } + .to change { user.reload.otp_secret }.to 'thisisasecretforthespecofnewview' expect(assigns(:recovery_codes)).to eq otp_backup_codes expect(flash[:notice]).to eq 'Two-factor authentication successfully enabled' expect(response).to have_http_status(200) expect(response).to render_template('settings/two_factor_authentication/recovery_codes/index') end - - def prepare_user_otp_generation - allow(user) - .to receive(:generate_otp_backup_codes!) - .and_return(otp_backup_codes) - end - - def prepare_user_otp_consumption - options = { otp_secret: 'thisisasecretforthespecofnewview' } - allow(user) - .to receive(:validate_and_consume_otp!) - .with('123456', options) - .and_return(true) - end end describe 'when creation fails' do subject do - options = { otp_secret: 'thisisasecretforthespecofnewview' } - allow(user) - .to receive(:validate_and_consume_otp!) - .with('123456', options) - .and_return(false) - allow(controller).to receive(:current_user).and_return(user) - - expect do - post :create, - params: { form_two_factor_confirmation: { otp_attempt: '123456' } }, - session: { challenge_passed_at: Time.now.utc, new_otp_secret: 'thisisasecretforthespecofnewview' } - end.to(not_change { user.reload.otp_secret }) + expect { post_create_with_options } + .to(not_change { user.reload.otp_secret }) end - it 'renders the new view' do + before do + prepare_user_otp_consumption_response(false) + allow(controller).to receive(:current_user).and_return(user) + end + + it 'renders page with error message' do subject expect(response.body).to include 'The entered code was invalid! Are server time and device time correct?' end include_examples 'renders :new' end - end - context 'when not signed in' do - it 'redirects if not signed in' do - post :create, params: { form_two_factor_confirmation: { otp_attempt: '123456' } } - expect(response).to redirect_to('/auth/sign_in') + private + + def post_create_with_options + post :create, + params: { form_two_factor_confirmation: { otp_attempt: '123456' } }, + session: { challenge_passed_at: Time.now.utc, new_otp_secret: 'thisisasecretforthespecofnewview' } + end + + def prepare_user_otp_generation + allow(user) + .to receive(:generate_otp_backup_codes!) + .and_return(otp_backup_codes) + end + + def prepare_user_otp_consumption_response(result) + options = { otp_secret: 'thisisasecretforthespecofnewview' } + allow(user) + .to receive(:validate_and_consume_otp!) + .with('123456', options) + .and_return(result) end end end end + + context 'when not signed in' do + it 'redirects on POST to create' do + post :create, params: { form_two_factor_confirmation: { otp_attempt: '123456' } } + + expect(response).to redirect_to('/auth/sign_in') + end + + it 'redirects on GET to new' do + get :new + + expect(response).to redirect_to('/auth/sign_in') + end + end end From 7faa27e17de515b8718075d89a00942c06c0ef48 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Thu, 30 Nov 2023 12:45:54 +0100 Subject: [PATCH 158/255] Change dismissed banners to be stored server-side (#27055) --- .../components/dismissable_banner.tsx | 25 ++++++++++++++++--- app/javascript/mastodon/reducers/settings.js | 9 +++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/components/dismissable_banner.tsx b/app/javascript/mastodon/components/dismissable_banner.tsx index 4feb74a3a..4e6d3bb9a 100644 --- a/app/javascript/mastodon/components/dismissable_banner.tsx +++ b/app/javascript/mastodon/components/dismissable_banner.tsx @@ -1,11 +1,18 @@ +/* eslint-disable @typescript-eslint/no-unsafe-call, + @typescript-eslint/no-unsafe-return, + @typescript-eslint/no-unsafe-assignment, + @typescript-eslint/no-unsafe-member-access + -- the settings store is not yet typed */ import type { PropsWithChildren } from 'react'; -import { useCallback, useState } from 'react'; +import { useCallback, useState, useEffect } from 'react'; import { defineMessages, useIntl } from 'react-intl'; import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg'; +import { changeSetting } from 'mastodon/actions/settings'; import { bannerSettings } from 'mastodon/settings'; +import { useAppSelector, useAppDispatch } from 'mastodon/store'; import { IconButton } from './icon_button'; @@ -21,13 +28,25 @@ export const DismissableBanner: React.FC<PropsWithChildren<Props>> = ({ id, children, }) => { - const [visible, setVisible] = useState(!bannerSettings.get(id)); + const dismissed = useAppSelector((state) => + state.settings.getIn(['dismissed_banners', id], false), + ); + const dispatch = useAppDispatch(); + + const [visible, setVisible] = useState(!bannerSettings.get(id) && !dismissed); const intl = useIntl(); const handleDismiss = useCallback(() => { setVisible(false); bannerSettings.set(id, true); - }, [id]); + dispatch(changeSetting(['dismissed_banners', id], true)); + }, [id, dispatch]); + + useEffect(() => { + if (!visible && !dismissed) { + dispatch(changeSetting(['dismissed_banners', id], true)); + } + }, [id, dispatch, visible, dismissed]); if (!visible) { return null; diff --git a/app/javascript/mastodon/reducers/settings.js b/app/javascript/mastodon/reducers/settings.js index 07d1bda0f..a605ecbb8 100644 --- a/app/javascript/mastodon/reducers/settings.js +++ b/app/javascript/mastodon/reducers/settings.js @@ -100,6 +100,15 @@ const initialState = ImmutableMap({ body: '', }), }), + + dismissed_banners: ImmutableMap({ + 'public_timeline': false, + 'community_timeline': false, + 'home.explore_prompt': false, + 'explore/links': false, + 'explore/statuses': false, + 'explore/tags': false, + }), }); const defaultColumns = fromJS([ From 0212e0cfbfe4b50b5286165ec9887523f82513d1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:22:25 +0100 Subject: [PATCH 159/255] fix(deps): update dependency @babel/runtime to v7.23.5 (#28136) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 69464dfa2..580407f34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1483,11 +1483,11 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.23.4 - resolution: "@babel/runtime@npm:7.23.4" + version: 7.23.5 + resolution: "@babel/runtime@npm:7.23.5" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: db2bf183cd0119599b903ca51ca0aeea8e0ab478a16be1aae10dd90473ed614159d3e5adfdd8f8f3d840402428ce0d90b5c01aae95da9e45a2dd83e02d85ca27 + checksum: ca679cc91bb7e424bc2db87bb58cc3b06ade916b9adb21fbbdc43e54cdaacb3eea201ceba2a0464b11d2eb65b9fe6a6ffcf4d7521fa52994f19be96f1af14788 languageName: node linkType: hard From 02a98210e891dff32b1cb958f799213ccfbbc29c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:22:40 +0100 Subject: [PATCH 160/255] fix(deps): update dependency jsdom to v23.0.1 (#28135) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 580407f34..ad792d26c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10640,8 +10640,8 @@ __metadata: linkType: hard "jsdom@npm:^23.0.0": - version: 23.0.0 - resolution: "jsdom@npm:23.0.0" + version: 23.0.1 + resolution: "jsdom@npm:23.0.1" dependencies: cssstyle: "npm:^3.0.0" data-urls: "npm:^5.0.0" @@ -10665,11 +10665,11 @@ __metadata: ws: "npm:^8.14.2" xml-name-validator: "npm:^5.0.0" peerDependencies: - canvas: ^3.0.0 + canvas: ^2.11.2 peerDependenciesMeta: canvas: optional: true - checksum: 2c876a02de49e0ed6b667a4eb9b08b8e76ac189a5571ff97791cc9564e713259314deea6d657cc7f59fc30af41b900e7d833c95017e576dfcaf25f32565722af + checksum: 13b2b3693ccb40215d1cce77bac7a295414ee4c0a06e30167f8087c9867145ba23dbd592bd95a801cadd7b3698bfd20b9c3f2c26fd8422607f22609ed2e404ef languageName: node linkType: hard From bb0efe16e62636895079b3a968e444cd6e80b467 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 30 Nov 2023 08:30:35 -0500 Subject: [PATCH 161/255] Remove `default_scope` from `MediaAttachment` class (#28043) --- app/controllers/accounts_controller.rb | 2 +- app/lib/account_statuses_filter.rb | 2 +- app/lib/vacuum/media_attachments_vacuum.rb | 4 ++-- app/models/admin/status_filter.rb | 2 +- app/models/media_attachment.rb | 9 ++++----- app/services/backup_service.rb | 2 +- app/services/clear_domain_media_service.rb | 2 +- app/services/delete_account_service.rb | 2 +- app/services/suspend_account_service.rb | 2 +- app/services/unsuspend_account_service.rb | 2 +- .../activitypub/process_status_update_service_spec.rb | 2 +- 11 files changed, 15 insertions(+), 16 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 850bf881f..4e475fe78 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -50,7 +50,7 @@ class AccountsController < ApplicationController end def only_media_scope - Status.joins(:media_attachments).merge(@account.media_attachments.reorder(nil)).group(:id) + Status.joins(:media_attachments).merge(@account.media_attachments).group(:id) end def no_replies_scope diff --git a/app/lib/account_statuses_filter.rb b/app/lib/account_statuses_filter.rb index b34ebb477..d1365de58 100644 --- a/app/lib/account_statuses_filter.rb +++ b/app/lib/account_statuses_filter.rb @@ -70,7 +70,7 @@ class AccountStatusesFilter end def only_media_scope - Status.joins(:media_attachments).merge(account.media_attachments.reorder(nil)).group(Status.arel_table[:id]) + Status.joins(:media_attachments).merge(account.media_attachments).group(Status.arel_table[:id]) end def no_replies_scope diff --git a/app/lib/vacuum/media_attachments_vacuum.rb b/app/lib/vacuum/media_attachments_vacuum.rb index 7b21c84bb..ab7ea4092 100644 --- a/app/lib/vacuum/media_attachments_vacuum.rb +++ b/app/lib/vacuum/media_attachments_vacuum.rb @@ -27,11 +27,11 @@ class Vacuum::MediaAttachmentsVacuum end def media_attachments_past_retention_period - MediaAttachment.unscoped.remote.cached.where(MediaAttachment.arel_table[:created_at].lt(@retention_period.ago)).where(MediaAttachment.arel_table[:updated_at].lt(@retention_period.ago)) + MediaAttachment.remote.cached.where(MediaAttachment.arel_table[:created_at].lt(@retention_period.ago)).where(MediaAttachment.arel_table[:updated_at].lt(@retention_period.ago)) end def orphaned_media_attachments - MediaAttachment.unscoped.unattached.where(MediaAttachment.arel_table[:created_at].lt(TTL.ago)) + MediaAttachment.unattached.where(MediaAttachment.arel_table[:created_at].lt(TTL.ago)) end def retention_period? diff --git a/app/models/admin/status_filter.rb b/app/models/admin/status_filter.rb index 645c2e620..4708785e7 100644 --- a/app/models/admin/status_filter.rb +++ b/app/models/admin/status_filter.rb @@ -32,7 +32,7 @@ class Admin::StatusFilter def scope_for(key, _value) case key.to_s when 'media' - Status.joins(:media_attachments).merge(@account.media_attachments.reorder(nil)).group(:id).reorder('statuses.id desc') + Status.joins(:media_attachments).merge(@account.media_attachments).group(:id).reorder('statuses.id desc') else raise Mastodon::InvalidParameterError, "Unknown filter: #{key}" end diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index b567003fb..1f40e5725 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -205,12 +205,11 @@ class MediaAttachment < ApplicationRecord validates :thumbnail, absence: true, if: -> { local? && !audio_or_video? } scope :attached, -> { where.not(status_id: nil).or(where.not(scheduled_status_id: nil)) } - scope :unattached, -> { where(status_id: nil, scheduled_status_id: nil) } - scope :local, -> { where(remote_url: '') } - scope :remote, -> { where.not(remote_url: '') } scope :cached, -> { remote.where.not(file_file_name: nil) } - - default_scope { order(id: :asc) } + scope :local, -> { where(remote_url: '') } + scope :ordered, -> { order(id: :asc) } + scope :remote, -> { where.not(remote_url: '') } + scope :unattached, -> { where(status_id: nil, scheduled_status_id: nil) } attr_accessor :skip_download diff --git a/app/services/backup_service.rb b/app/services/backup_service.rb index 3ef0366c3..886bab1eb 100644 --- a/app/services/backup_service.rb +++ b/app/services/backup_service.rb @@ -72,7 +72,7 @@ class BackupService < BaseService end def dump_media_attachments!(zipfile) - MediaAttachment.attached.where(account: account).reorder(nil).find_in_batches do |media_attachments| + MediaAttachment.attached.where(account: account).find_in_batches do |media_attachments| media_attachments.each do |m| path = m.file&.path next unless path diff --git a/app/services/clear_domain_media_service.rb b/app/services/clear_domain_media_service.rb index 7bf2d62fb..d3ad43e70 100644 --- a/app/services/clear_domain_media_service.rb +++ b/app/services/clear_domain_media_service.rb @@ -43,7 +43,7 @@ class ClearDomainMediaService < BaseService end def media_from_blocked_domain - MediaAttachment.joins(:account).merge(blocked_domain_accounts).reorder(nil) + MediaAttachment.joins(:account).merge(blocked_domain_accounts) end def emojis_from_blocked_domains diff --git a/app/services/delete_account_service.rb b/app/services/delete_account_service.rb index 190a72e5c..7c7cb97df 100644 --- a/app/services/delete_account_service.rb +++ b/app/services/delete_account_service.rb @@ -165,7 +165,7 @@ class DeleteAccountService < BaseService end def purge_media_attachments! - @account.media_attachments.reorder(nil).find_each do |media_attachment| + @account.media_attachments.find_each do |media_attachment| next if keep_account_record? && reported_status_ids.include?(media_attachment.status_id) media_attachment.destroy diff --git a/app/services/suspend_account_service.rb b/app/services/suspend_account_service.rb index e79c2d3d8..8d5446f1a 100644 --- a/app/services/suspend_account_service.rb +++ b/app/services/suspend_account_service.rb @@ -65,7 +65,7 @@ class SuspendAccountService < BaseService def privatize_media_attachments! attachment_names = MediaAttachment.attachment_definitions.keys - @account.media_attachments.reorder(nil).find_each do |media_attachment| + @account.media_attachments.find_each do |media_attachment| attachment_names.each do |attachment_name| attachment = media_attachment.public_send(attachment_name) styles = MediaAttachment::DEFAULT_STYLES | attachment.styles.keys diff --git a/app/services/unsuspend_account_service.rb b/app/services/unsuspend_account_service.rb index 93cd04a94..652dd6a84 100644 --- a/app/services/unsuspend_account_service.rb +++ b/app/services/unsuspend_account_service.rb @@ -61,7 +61,7 @@ class UnsuspendAccountService < BaseService def publish_media_attachments! attachment_names = MediaAttachment.attachment_definitions.keys - @account.media_attachments.reorder(nil).find_each do |media_attachment| + @account.media_attachments.find_each do |media_attachment| attachment_names.each do |attachment_name| attachment = media_attachment.public_send(attachment_name) styles = MediaAttachment::DEFAULT_STYLES | attachment.styles.keys diff --git a/spec/services/activitypub/process_status_update_service_spec.rb b/spec/services/activitypub/process_status_update_service_spec.rb index 9d91f31cc..53cbaf4cc 100644 --- a/spec/services/activitypub/process_status_update_service_spec.rb +++ b/spec/services/activitypub/process_status_update_service_spec.rb @@ -384,7 +384,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do end it 'updates the existing media attachment in-place' do - media_attachment = status.media_attachments.reload.first + media_attachment = status.media_attachments.ordered.reload.first expect(media_attachment).to_not be_nil expect(media_attachment.remote_url).to eq 'https://example.com/foo.png' From 85662a5a57531af5402a6777d0b1089e78c56815 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Thu, 30 Nov 2023 14:47:01 +0100 Subject: [PATCH 162/255] Change `img-src` and `media-src` CSP directives to not include `https:` (#28025) --- app/lib/content_security_policy.rb | 4 ++-- config/initializers/content_security_policy.rb | 10 +++++----- spec/lib/content_security_policy_spec.rb | 14 +++++++------- spec/requests/content_security_policy_spec.rb | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/lib/content_security_policy.rb b/app/lib/content_security_policy.rb index e8fcf76a6..966e41f03 100644 --- a/app/lib/content_security_policy.rb +++ b/app/lib/content_security_policy.rb @@ -9,8 +9,8 @@ class ContentSecurityPolicy url_from_configured_asset_host || url_from_base_host end - def media_host - cdn_host_value || assets_host + def media_hosts + [assets_host, cdn_host_value].compact end private diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 3fb80bac4..a8b61e356 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -10,7 +10,7 @@ require_relative '../../app/lib/content_security_policy' policy = ContentSecurityPolicy.new assets_host = policy.assets_host -media_host = policy.media_host +media_hosts = policy.media_hosts def sso_host return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true' @@ -35,9 +35,9 @@ Rails.application.config.content_security_policy do |p| p.default_src :none p.frame_ancestors :none p.font_src :self, assets_host - p.img_src :self, :https, :data, :blob, assets_host + p.img_src :self, :data, :blob, *media_hosts p.style_src :self, assets_host - p.media_src :self, :https, :data, assets_host + p.media_src :self, :data, *media_hosts p.frame_src :self, :https p.manifest_src :self, assets_host @@ -54,10 +54,10 @@ Rails.application.config.content_security_policy do |p| webpacker_public_host = ENV.fetch('WEBPACKER_DEV_SERVER_PUBLIC', Webpacker.config.dev_server[:public]) webpacker_urls = %w(ws http).map { |protocol| "#{protocol}#{Webpacker.dev_server.https? ? 's' : ''}://#{webpacker_public_host}" } - p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url, *webpacker_urls + p.connect_src :self, :data, :blob, *media_hosts, Rails.configuration.x.streaming_api_base_url, *webpacker_urls p.script_src :self, :unsafe_inline, :unsafe_eval, assets_host else - p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url + p.connect_src :self, :data, :blob, *media_hosts, Rails.configuration.x.streaming_api_base_url p.script_src :self, assets_host, "'wasm-unsafe-eval'" end end diff --git a/spec/lib/content_security_policy_spec.rb b/spec/lib/content_security_policy_spec.rb index 2e92f815a..4286f1498 100644 --- a/spec/lib/content_security_policy_spec.rb +++ b/spec/lib/content_security_policy_spec.rb @@ -59,10 +59,10 @@ describe ContentSecurityPolicy do end end - describe '#media_host' do + describe '#media_hosts' do context 'when there is no configured CDN' do it 'defaults to using the assets_host value' do - expect(subject.media_host).to eq(subject.assets_host) + expect(subject.media_hosts).to contain_exactly(subject.assets_host) end end @@ -74,7 +74,7 @@ describe ContentSecurityPolicy do end it 'uses the s3 alias host value' do - expect(subject.media_host).to eq 'https://asset-host.s3-alias.example' + expect(subject.media_hosts).to contain_exactly(subject.assets_host, 'https://asset-host.s3-alias.example') end end @@ -86,7 +86,7 @@ describe ContentSecurityPolicy do end it 'uses the s3 alias host value and preserves the path' do - expect(subject.media_host).to eq 'https://asset-host.s3-alias.example/pathname/' + expect(subject.media_hosts).to contain_exactly(subject.assets_host, 'https://asset-host.s3-alias.example/pathname/') end end @@ -98,7 +98,7 @@ describe ContentSecurityPolicy do end it 'uses the s3 cloudfront host value' do - expect(subject.media_host).to eq 'https://asset-host.s3-cloudfront.example' + expect(subject.media_hosts).to contain_exactly(subject.assets_host, 'https://asset-host.s3-cloudfront.example') end end @@ -110,7 +110,7 @@ describe ContentSecurityPolicy do end it 'uses the azure alias host value' do - expect(subject.media_host).to eq 'https://asset-host.azure-alias.example' + expect(subject.media_hosts).to contain_exactly(subject.assets_host, 'https://asset-host.azure-alias.example') end end @@ -122,7 +122,7 @@ describe ContentSecurityPolicy do end it 'uses the s3 hostname host value' do - expect(subject.media_host).to eq 'https://asset-host.s3.example' + expect(subject.media_hosts).to contain_exactly(subject.assets_host, 'https://asset-host.s3.example') end end end diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb index 7eb27d61d..7610e698c 100644 --- a/spec/requests/content_security_policy_spec.rb +++ b/spec/requests/content_security_policy_spec.rb @@ -12,15 +12,15 @@ describe 'Content-Security-Policy' do "default-src 'none'", "frame-ancestors 'none'", "font-src 'self' https://cb6e6126.ngrok.io", - "img-src 'self' https: data: blob: https://cb6e6126.ngrok.io", + "img-src 'self' data: blob: https://cb6e6126.ngrok.io", "style-src 'self' https://cb6e6126.ngrok.io 'nonce-ZbA+JmE7+bK8F5qvADZHuQ=='", - "media-src 'self' https: data: https://cb6e6126.ngrok.io", + "media-src 'self' data: https://cb6e6126.ngrok.io", "frame-src 'self' https:", "manifest-src 'self' https://cb6e6126.ngrok.io", "form-action 'self'", "child-src 'self' blob: https://cb6e6126.ngrok.io", "worker-src 'self' blob: https://cb6e6126.ngrok.io", - "connect-src 'self' data: blob: https://cb6e6126.ngrok.io https://cb6e6126.ngrok.io ws://localhost:4000", + "connect-src 'self' data: blob: https://cb6e6126.ngrok.io ws://localhost:4000", "script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'" ) end From b20af17a2c7dec49bc7ad1ec6706c5b02bf4f498 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Thu, 30 Nov 2023 14:47:07 +0100 Subject: [PATCH 163/255] Fix onboarding step descriptions being truncated on narrow screens (#28021) --- app/javascript/styles/mastodon/components.scss | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 9c3d9dc2c..2106b529d 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -2732,22 +2732,16 @@ $ui-header-height: 55px; &__description { flex: 1 1 auto; line-height: 20px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; h6 { color: $highlight-text-color; font-weight: 500; font-size: 14px; - overflow: hidden; - text-overflow: ellipsis; } p { color: $darker-text-color; overflow: hidden; - text-overflow: ellipsis; } } } From a8473f582d0d25ac0a2ad385cf3915e8012a3646 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 30 Nov 2023 08:55:20 -0500 Subject: [PATCH 164/255] Add zeitwerk inflector for cli->CLI (#27635) --- config/initializers/inflections.rb | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 3d1750945..ba459e19f 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -13,21 +13,22 @@ # end ActiveSupport::Inflector.inflections(:en) do |inflect| - inflect.acronym 'StatsD' - inflect.acronym 'OEmbed' - inflect.acronym 'OStatus' inflect.acronym 'ActivityPub' - inflect.acronym 'PubSubHubbub' inflect.acronym 'ActivityStreams' - inflect.acronym 'JsonLd' - inflect.acronym 'Ed25519' - inflect.acronym 'TOC' - inflect.acronym 'RSS' - inflect.acronym 'REST' - inflect.acronym 'URL' inflect.acronym 'ASCII' + inflect.acronym 'CLI' inflect.acronym 'DeepL' inflect.acronym 'DSL' + inflect.acronym 'Ed25519' + inflect.acronym 'JsonLd' + inflect.acronym 'OEmbed' + inflect.acronym 'OStatus' + inflect.acronym 'PubSubHubbub' + inflect.acronym 'REST' + inflect.acronym 'RSS' + inflect.acronym 'StatsD' + inflect.acronym 'TOC' + inflect.acronym 'URL' inflect.singular 'data', 'data' end From e7c340a63475713d7f55b92fb8c963478f4d622a Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 30 Nov 2023 08:59:46 -0500 Subject: [PATCH 165/255] Spec coverage for missing `q` param and error conditions in `api/v2/search` controller (#27842) --- app/controllers/api/v2/search_controller.rb | 31 ++++++++++-- .../api/v2/search_controller_spec.rb | 48 +++++++++++++++++++ 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v2/search_controller.rb b/app/controllers/api/v2/search_controller.rb index 35be54930..4339bee21 100644 --- a/app/controllers/api/v2/search_controller.rb +++ b/app/controllers/api/v2/search_controller.rb @@ -8,6 +8,11 @@ class Api::V2::SearchController < Api::BaseController before_action -> { authorize_if_got_token! :read, :'read:search' } before_action :validate_search_params! + with_options unless: :user_signed_in? do + before_action :query_pagination_error, if: :pagination_requested? + before_action :remote_resolve_error, if: :remote_resolve_requested? + end + def index @search = Search.new(search_results) render json: @search, serializer: REST::SearchSerializer @@ -21,12 +26,22 @@ class Api::V2::SearchController < Api::BaseController def validate_search_params! params.require(:q) + end - return if user_signed_in? + def query_pagination_error + render json: { error: 'Search queries pagination is not supported without authentication' }, status: 401 + end - return render json: { error: 'Search queries pagination is not supported without authentication' }, status: 401 if params[:offset].present? + def remote_resolve_error + render json: { error: 'Search queries that resolve remote resources are not supported without authentication' }, status: 401 + end - render json: { error: 'Search queries that resolve remote resources are not supported without authentication' }, status: 401 if truthy_param?(:resolve) + def remote_resolve_requested? + truthy_param?(:resolve) + end + + def pagination_requested? + params[:offset].present? end def search_results @@ -34,7 +49,15 @@ class Api::V2::SearchController < Api::BaseController params[:q], current_account, limit_param(RESULTS_LIMIT), - search_params.merge(resolve: truthy_param?(:resolve), exclude_unreviewed: truthy_param?(:exclude_unreviewed), following: truthy_param?(:following)) + combined_search_params + ) + end + + def combined_search_params + search_params.merge( + resolve: truthy_param?(:resolve), + exclude_unreviewed: truthy_param?(:exclude_unreviewed), + following: truthy_param?(:following) ) end diff --git a/spec/controllers/api/v2/search_controller_spec.rb b/spec/controllers/api/v2/search_controller_spec.rb index d3ff42d6a..a16716a10 100644 --- a/spec/controllers/api/v2/search_controller_spec.rb +++ b/spec/controllers/api/v2/search_controller_spec.rb @@ -34,6 +34,26 @@ RSpec.describe Api::V2::SearchController do expect(body_as_json[:accounts].pluck(:id)).to contain_exactly(bob.id.to_s, ana.id.to_s, tom.id.to_s) end + context 'with truthy `resolve`' do + let(:params) { { q: 'test1', resolve: '1' } } + + it 'returns http unauthorized' do + get :index, params: params + + expect(response).to have_http_status(200) + end + end + + context 'with `offset`' do + let(:params) { { q: 'test1', offset: 1 } } + + it 'returns http unauthorized' do + get :index, params: params + + expect(response).to have_http_status(200) + end + end + context 'with following=true' do let(:params) { { q: 'test', type: 'accounts', following: 'true' } } @@ -48,6 +68,26 @@ RSpec.describe Api::V2::SearchController do end end end + + context 'when search raises syntax error' do + before { allow(Search).to receive(:new).and_raise(Mastodon::SyntaxError) } + + it 'returns http unprocessable_entity' do + get :index, params: params + + expect(response).to have_http_status(422) + end + end + + context 'when search raises not found error' do + before { allow(Search).to receive(:new).and_raise(ActiveRecord::RecordNotFound) } + + it 'returns http not_found' do + get :index, params: params + + expect(response).to have_http_status(404) + end + end end end @@ -59,6 +99,12 @@ RSpec.describe Api::V2::SearchController do get :index, params: search_params end + context 'without a `q` param' do + it 'returns http bad_request' do + expect(response).to have_http_status(400) + end + end + context 'with a `q` shorter than 5 characters' do let(:search_params) { { q: 'test' } } @@ -79,6 +125,7 @@ RSpec.describe Api::V2::SearchController do it 'returns http unauthorized' do expect(response).to have_http_status(401) + expect(response.body).to match('resolve remote resources') end end @@ -87,6 +134,7 @@ RSpec.describe Api::V2::SearchController do it 'returns http unauthorized' do expect(response).to have_http_status(401) + expect(response.body).to match('pagination is not supported') end end end From 0530ce5e9575c09464847412f43852f438b0494e Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 30 Nov 2023 09:28:05 -0500 Subject: [PATCH 166/255] Convert accounts controller spec to request spec (#28126) --- .../accounts_spec.rb} | 158 +++++++++--------- 1 file changed, 80 insertions(+), 78 deletions(-) rename spec/{controllers/accounts_controller_spec.rb => requests/accounts_spec.rb} (56%) diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/requests/accounts_spec.rb similarity index 56% rename from spec/controllers/accounts_controller_spec.rb rename to spec/requests/accounts_spec.rb index 542a74878..bf067cdc3 100644 --- a/spec/controllers/accounts_controller_spec.rb +++ b/spec/requests/accounts_spec.rb @@ -2,23 +2,22 @@ require 'rails_helper' -RSpec.describe AccountsController do - render_views - +describe 'Accounts show response' do let(:account) { Fabricate(:account) } - describe 'unapproved account check' do + context 'with an unapproved account' do before { account.user.update(approved: false) } it 'returns http not found' do %w(html json rss).each do |format| - get :show, params: { username: account.username, format: format } + get short_account_path(username: account.username), as: format + expect(response).to have_http_status(404) end end end - describe 'permanently suspended account check' do + context 'with a permanently suspended account' do before do account.suspend! account.deletion_request.destroy @@ -26,25 +25,26 @@ RSpec.describe AccountsController do it 'returns http gone' do %w(html json rss).each do |format| - get :show, params: { username: account.username, format: format } + get short_account_path(username: account.username), as: format + expect(response).to have_http_status(410) end end end - describe 'temporarily suspended account check' do + context 'with a temporarily suspended account' do before { account.suspend! } it 'returns appropriate http response code' do { html: 403, json: 200, rss: 403 }.each do |format, code| - get :show, params: { username: account.username, format: format } + get short_account_path(username: account.username), as: format expect(response).to have_http_status(code) end end end - describe 'GET #show' do + describe 'GET to short username paths' do context 'with existing statuses' do let!(:status) { Fabricate(:status, account: account) } let!(:status_reply) { Fabricate(:status, account: account, thread: Fabricate(:status)) } @@ -66,17 +66,17 @@ RSpec.describe AccountsController do shared_examples 'common HTML response' do it 'returns a standard HTML response', :aggregate_failures do - expect(response).to have_http_status(200) + expect(response) + .to have_http_status(200) + .and render_template(:show) expect(response.headers['Link'].to_s).to include ActivityPub::TagManager.instance.uri_for(account) - - expect(response).to render_template(:show) end end context 'with a normal account in an HTML request' do before do - get :show, params: { username: account.username, format: format } + get short_account_path(username: account.username), as: format end it_behaves_like 'common HTML response' @@ -84,8 +84,7 @@ RSpec.describe AccountsController do context 'with replies' do before do - allow(controller).to receive(:replies_requested?).and_return(true) - get :show, params: { username: account.username, format: format } + get short_account_with_replies_path(username: account.username), as: format end it_behaves_like 'common HTML response' @@ -93,8 +92,7 @@ RSpec.describe AccountsController do context 'with media' do before do - allow(controller).to receive(:media_requested?).and_return(true) - get :show, params: { username: account.username, format: format } + get short_account_media_path(username: account.username), as: format end it_behaves_like 'common HTML response' @@ -106,9 +104,8 @@ RSpec.describe AccountsController do let!(:status_tag) { Fabricate(:status, account: account) } before do - allow(controller).to receive(:tag_requested?).and_return(true) status_tag.tags << tag - get :show, params: { username: account.username, format: format, tag: tag.to_param } + get short_account_tag_path(username: account.username, tag: tag), as: format end it_behaves_like 'common HTML response' @@ -117,21 +114,25 @@ RSpec.describe AccountsController do context 'with JSON' do let(:authorized_fetch_mode) { false } - let(:format) { 'json' } + let(:headers) { { 'ACCEPT' => 'application/json' } } - before do - allow(controller).to receive(:authorized_fetch_mode?).and_return(authorized_fetch_mode) + around do |example| + ClimateControl.modify AUTHORIZED_FETCH: authorized_fetch_mode.to_s do + example.run + end end context 'with a normal account in a JSON request' do before do - get :show, params: { username: account.username, format: format } + get short_account_path(username: account.username), headers: headers end it 'returns a JSON version of the account', :aggregate_failures do - expect(response).to have_http_status(200) - - expect(response.media_type).to eq 'application/activity+json' + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: eq('application/activity+json') + ) expect(body_as_json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary) end @@ -152,13 +153,15 @@ RSpec.describe AccountsController do before do sign_in(user) - get :show, params: { username: account.username, format: format } + get short_account_path(username: account.username), headers: headers.merge({ 'Cookie' => '123' }) end it 'returns a private JSON version of the account', :aggregate_failures do - expect(response).to have_http_status(200) - - expect(response.media_type).to eq 'application/activity+json' + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: eq('application/activity+json') + ) expect(response.headers['Cache-Control']).to include 'private' @@ -170,14 +173,15 @@ RSpec.describe AccountsController do let(:remote_account) { Fabricate(:account, domain: 'example.com') } before do - allow(controller).to receive(:signed_request_actor).and_return(remote_account) - get :show, params: { username: account.username, format: format } + get short_account_path(username: account.username), headers: headers, sign_with: remote_account end it 'returns a JSON version of the account', :aggregate_failures do - expect(response).to have_http_status(200) - - expect(response.media_type).to eq 'application/activity+json' + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: eq('application/activity+json') + ) expect(body_as_json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary) end @@ -188,12 +192,13 @@ RSpec.describe AccountsController do let(:authorized_fetch_mode) { true } it 'returns a private signature JSON version of the account', :aggregate_failures do - expect(response).to have_http_status(200) - - expect(response.media_type).to eq 'application/activity+json' + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: eq('application/activity+json') + ) expect(response.headers['Cache-Control']).to include 'private' - expect(response.headers['Vary']).to include 'Signature' expect(body_as_json).to include(:id, :type, :preferredUsername, :inbox, :publicKey, :name, :summary) @@ -207,60 +212,58 @@ RSpec.describe AccountsController do context 'with a normal account in an RSS request' do before do - get :show, params: { username: account.username, format: format } + get short_account_path(username: account.username, format: format) end it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie' it 'responds with correct statuses', :aggregate_failures do expect(response).to have_http_status(200) - expect(response.body).to include_status_tag(status_media) - expect(response.body).to include_status_tag(status_self_reply) - expect(response.body).to include_status_tag(status) - expect(response.body).to_not include_status_tag(status_direct) - expect(response.body).to_not include_status_tag(status_private) - expect(response.body).to_not include_status_tag(status_reblog.reblog) - expect(response.body).to_not include_status_tag(status_reply) + expect(response.body).to include(status_tag_for(status_media)) + expect(response.body).to include(status_tag_for(status_self_reply)) + expect(response.body).to include(status_tag_for(status)) + expect(response.body).to_not include(status_tag_for(status_direct)) + expect(response.body).to_not include(status_tag_for(status_private)) + expect(response.body).to_not include(status_tag_for(status_reblog.reblog)) + expect(response.body).to_not include(status_tag_for(status_reply)) end end context 'with replies' do before do - allow(controller).to receive(:replies_requested?).and_return(true) - get :show, params: { username: account.username, format: format } + get short_account_with_replies_path(username: account.username, format: format) end it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie' it 'responds with correct statuses with replies', :aggregate_failures do expect(response).to have_http_status(200) - expect(response.body).to include_status_tag(status_media) - expect(response.body).to include_status_tag(status_reply) - expect(response.body).to include_status_tag(status_self_reply) - expect(response.body).to include_status_tag(status) - expect(response.body).to_not include_status_tag(status_direct) - expect(response.body).to_not include_status_tag(status_private) - expect(response.body).to_not include_status_tag(status_reblog.reblog) + expect(response.body).to include(status_tag_for(status_media)) + expect(response.body).to include(status_tag_for(status_reply)) + expect(response.body).to include(status_tag_for(status_self_reply)) + expect(response.body).to include(status_tag_for(status)) + expect(response.body).to_not include(status_tag_for(status_direct)) + expect(response.body).to_not include(status_tag_for(status_private)) + expect(response.body).to_not include(status_tag_for(status_reblog.reblog)) end end context 'with media' do before do - allow(controller).to receive(:media_requested?).and_return(true) - get :show, params: { username: account.username, format: format } + get short_account_media_path(username: account.username, format: format) end it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie' it 'responds with correct statuses with media', :aggregate_failures do expect(response).to have_http_status(200) - expect(response.body).to include_status_tag(status_media) - expect(response.body).to_not include_status_tag(status_direct) - expect(response.body).to_not include_status_tag(status_private) - expect(response.body).to_not include_status_tag(status_reblog.reblog) - expect(response.body).to_not include_status_tag(status_reply) - expect(response.body).to_not include_status_tag(status_self_reply) - expect(response.body).to_not include_status_tag(status) + expect(response.body).to include(status_tag_for(status_media)) + expect(response.body).to_not include(status_tag_for(status_direct)) + expect(response.body).to_not include(status_tag_for(status_private)) + expect(response.body).to_not include(status_tag_for(status_reblog.reblog)) + expect(response.body).to_not include(status_tag_for(status_reply)) + expect(response.body).to_not include(status_tag_for(status_self_reply)) + expect(response.body).to_not include(status_tag_for(status)) end end @@ -270,30 +273,29 @@ RSpec.describe AccountsController do let!(:status_tag) { Fabricate(:status, account: account) } before do - allow(controller).to receive(:tag_requested?).and_return(true) status_tag.tags << tag - get :show, params: { username: account.username, format: format, tag: tag.to_param } + get short_account_tag_path(username: account.username, tag: tag, format: format) end it_behaves_like 'cacheable response', expects_vary: 'Accept, Accept-Language, Cookie' it 'responds with correct statuses with a tag', :aggregate_failures do expect(response).to have_http_status(200) - expect(response.body).to include_status_tag(status_tag) - expect(response.body).to_not include_status_tag(status_direct) - expect(response.body).to_not include_status_tag(status_media) - expect(response.body).to_not include_status_tag(status_private) - expect(response.body).to_not include_status_tag(status_reblog.reblog) - expect(response.body).to_not include_status_tag(status_reply) - expect(response.body).to_not include_status_tag(status_self_reply) - expect(response.body).to_not include_status_tag(status) + expect(response.body).to include(status_tag_for(status_tag)) + expect(response.body).to_not include(status_tag_for(status_direct)) + expect(response.body).to_not include(status_tag_for(status_media)) + expect(response.body).to_not include(status_tag_for(status_private)) + expect(response.body).to_not include(status_tag_for(status_reblog.reblog)) + expect(response.body).to_not include(status_tag_for(status_reply)) + expect(response.body).to_not include(status_tag_for(status_self_reply)) + expect(response.body).to_not include(status_tag_for(status)) end end end end end - def include_status_tag(status) - include ActivityPub::TagManager.instance.url_for(status) + def status_tag_for(status) + ActivityPub::TagManager.instance.url_for(status) end end From 1f1c75bba56f4b22c5f4c745b8f50a002001213c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 30 Nov 2023 09:39:41 -0500 Subject: [PATCH 167/255] File cleanup/organization in `controllers/concerns` (#27846) --- app/controllers/admin/export_domain_allows_controller.rb | 2 +- app/controllers/admin/export_domain_blocks_controller.rb | 2 +- app/controllers/api/base_controller.rb | 6 +++--- app/controllers/auth/confirmations_controller.rb | 2 +- app/controllers/auth/registrations_controller.rb | 2 +- app/controllers/auth/sessions_controller.rb | 2 +- .../export_controller_concern.rb} | 2 +- .../concerns/{ => api}/access_token_tracking_concern.rb | 2 +- .../{api_caching_concern.rb => api/caching_concern.rb} | 2 +- app/controllers/concerns/{ => api}/rate_limit_headers.rb | 2 +- app/controllers/concerns/{ => auth}/captcha_concern.rb | 2 +- .../concerns/{ => auth}/registration_spam_concern.rb | 2 +- .../{ => auth}/two_factor_authentication_concern.rb | 2 +- .../concerns/{ => settings}/export_controller_concern.rb | 2 +- .../settings/exports/blocked_accounts_controller.rb | 2 +- .../settings/exports/blocked_domains_controller.rb | 2 +- app/controllers/settings/exports/bookmarks_controller.rb | 2 +- .../settings/exports/following_accounts_controller.rb | 2 +- app/controllers/settings/exports/lists_controller.rb | 2 +- .../settings/exports/muted_accounts_controller.rb | 2 +- .../concerns/{ => api}/rate_limit_headers_spec.rb | 4 ++-- .../{ => settings}/export_controller_concern_spec.rb | 4 ++-- 22 files changed, 26 insertions(+), 26 deletions(-) rename app/controllers/concerns/{admin_export_controller_concern.rb => admin/export_controller_concern.rb} (92%) rename app/controllers/concerns/{ => api}/access_token_tracking_concern.rb (92%) rename app/controllers/concerns/{api_caching_concern.rb => api/caching_concern.rb} (93%) rename app/controllers/concerns/{ => api}/rate_limit_headers.rb (98%) rename app/controllers/concerns/{ => auth}/captcha_concern.rb (98%) rename app/controllers/concerns/{ => auth}/registration_spam_concern.rb (81%) rename app/controllers/concerns/{ => auth}/two_factor_authentication_concern.rb (98%) rename app/controllers/concerns/{ => settings}/export_controller_concern.rb (93%) rename spec/controllers/concerns/{ => api}/rate_limit_headers_spec.rb (95%) rename spec/controllers/concerns/{ => settings}/export_controller_concern_spec.rb (89%) diff --git a/app/controllers/admin/export_domain_allows_controller.rb b/app/controllers/admin/export_domain_allows_controller.rb index adfc39da2..ca88c6525 100644 --- a/app/controllers/admin/export_domain_allows_controller.rb +++ b/app/controllers/admin/export_domain_allows_controller.rb @@ -4,7 +4,7 @@ require 'csv' module Admin class ExportDomainAllowsController < BaseController - include AdminExportControllerConcern + include Admin::ExportControllerConcern before_action :set_dummy_import!, only: [:new] diff --git a/app/controllers/admin/export_domain_blocks_controller.rb b/app/controllers/admin/export_domain_blocks_controller.rb index 816422d4f..433b8a158 100644 --- a/app/controllers/admin/export_domain_blocks_controller.rb +++ b/app/controllers/admin/export_domain_blocks_controller.rb @@ -4,7 +4,7 @@ require 'csv' module Admin class ExportDomainBlocksController < BaseController - include AdminExportControllerConcern + include Admin::ExportControllerConcern before_action :set_dummy_import!, only: [:new] diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index 135c57565..dc760297d 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -4,9 +4,9 @@ class Api::BaseController < ApplicationController DEFAULT_STATUSES_LIMIT = 20 DEFAULT_ACCOUNTS_LIMIT = 40 - include RateLimitHeaders - include AccessTokenTrackingConcern - include ApiCachingConcern + include Api::RateLimitHeaders + include Api::AccessTokenTrackingConcern + include Api::CachingConcern include Api::ContentSecurityPolicy skip_before_action :require_functional!, unless: :limited_federation_mode? diff --git a/app/controllers/auth/confirmations_controller.rb b/app/controllers/auth/confirmations_controller.rb index 05e4605f4..9f6be9c42 100644 --- a/app/controllers/auth/confirmations_controller.rb +++ b/app/controllers/auth/confirmations_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Auth::ConfirmationsController < Devise::ConfirmationsController - include CaptchaConcern + include Auth::CaptchaConcern layout 'auth' diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index 8be7c5f19..4535ecdbd 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -2,7 +2,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController include RegistrationHelper - include RegistrationSpamConcern + include Auth::RegistrationSpamConcern layout :determine_layout diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb index 84d9d5e11..148ad5375 100644 --- a/app/controllers/auth/sessions_controller.rb +++ b/app/controllers/auth/sessions_controller.rb @@ -10,7 +10,7 @@ class Auth::SessionsController < Devise::SessionsController prepend_before_action :check_suspicious!, only: [:create] - include TwoFactorAuthenticationConcern + include Auth::TwoFactorAuthenticationConcern before_action :set_body_classes diff --git a/app/controllers/concerns/admin_export_controller_concern.rb b/app/controllers/concerns/admin/export_controller_concern.rb similarity index 92% rename from app/controllers/concerns/admin_export_controller_concern.rb rename to app/controllers/concerns/admin/export_controller_concern.rb index 4ac48a04b..6228ae67f 100644 --- a/app/controllers/concerns/admin_export_controller_concern.rb +++ b/app/controllers/concerns/admin/export_controller_concern.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module AdminExportControllerConcern +module Admin::ExportControllerConcern extend ActiveSupport::Concern private diff --git a/app/controllers/concerns/access_token_tracking_concern.rb b/app/controllers/concerns/api/access_token_tracking_concern.rb similarity index 92% rename from app/controllers/concerns/access_token_tracking_concern.rb rename to app/controllers/concerns/api/access_token_tracking_concern.rb index cf60cfb99..bc6ae51c7 100644 --- a/app/controllers/concerns/access_token_tracking_concern.rb +++ b/app/controllers/concerns/api/access_token_tracking_concern.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module AccessTokenTrackingConcern +module Api::AccessTokenTrackingConcern extend ActiveSupport::Concern ACCESS_TOKEN_UPDATE_FREQUENCY = 24.hours.freeze diff --git a/app/controllers/concerns/api_caching_concern.rb b/app/controllers/concerns/api/caching_concern.rb similarity index 93% rename from app/controllers/concerns/api_caching_concern.rb rename to app/controllers/concerns/api/caching_concern.rb index 12264d514..55d7fe56d 100644 --- a/app/controllers/concerns/api_caching_concern.rb +++ b/app/controllers/concerns/api/caching_concern.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module ApiCachingConcern +module Api::CachingConcern extend ActiveSupport::Concern def cache_if_unauthenticated! diff --git a/app/controllers/concerns/rate_limit_headers.rb b/app/controllers/concerns/api/rate_limit_headers.rb similarity index 98% rename from app/controllers/concerns/rate_limit_headers.rb rename to app/controllers/concerns/api/rate_limit_headers.rb index 5b83d8575..fe57b6f6b 100644 --- a/app/controllers/concerns/rate_limit_headers.rb +++ b/app/controllers/concerns/api/rate_limit_headers.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module RateLimitHeaders +module Api::RateLimitHeaders extend ActiveSupport::Concern class_methods do diff --git a/app/controllers/concerns/captcha_concern.rb b/app/controllers/concerns/auth/captcha_concern.rb similarity index 98% rename from app/controllers/concerns/captcha_concern.rb rename to app/controllers/concerns/auth/captcha_concern.rb index 170c8f5e0..cfd93978c 100644 --- a/app/controllers/concerns/captcha_concern.rb +++ b/app/controllers/concerns/auth/captcha_concern.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module CaptchaConcern +module Auth::CaptchaConcern extend ActiveSupport::Concern include Hcaptcha::Adapters::ViewMethods diff --git a/app/controllers/concerns/registration_spam_concern.rb b/app/controllers/concerns/auth/registration_spam_concern.rb similarity index 81% rename from app/controllers/concerns/registration_spam_concern.rb rename to app/controllers/concerns/auth/registration_spam_concern.rb index af434c985..9f4798b53 100644 --- a/app/controllers/concerns/registration_spam_concern.rb +++ b/app/controllers/concerns/auth/registration_spam_concern.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module RegistrationSpamConcern +module Auth::RegistrationSpamConcern extend ActiveSupport::Concern def set_registration_form_time diff --git a/app/controllers/concerns/two_factor_authentication_concern.rb b/app/controllers/concerns/auth/two_factor_authentication_concern.rb similarity index 98% rename from app/controllers/concerns/two_factor_authentication_concern.rb rename to app/controllers/concerns/auth/two_factor_authentication_concern.rb index bc2d194c3..effdb8d21 100644 --- a/app/controllers/concerns/two_factor_authentication_concern.rb +++ b/app/controllers/concerns/auth/two_factor_authentication_concern.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module TwoFactorAuthenticationConcern +module Auth::TwoFactorAuthenticationConcern extend ActiveSupport::Concern included do diff --git a/app/controllers/concerns/export_controller_concern.rb b/app/controllers/concerns/settings/export_controller_concern.rb similarity index 93% rename from app/controllers/concerns/export_controller_concern.rb rename to app/controllers/concerns/settings/export_controller_concern.rb index e1792fd6b..2cf28cced 100644 --- a/app/controllers/concerns/export_controller_concern.rb +++ b/app/controllers/concerns/settings/export_controller_concern.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module ExportControllerConcern +module Settings::ExportControllerConcern extend ActiveSupport::Concern included do diff --git a/app/controllers/settings/exports/blocked_accounts_controller.rb b/app/controllers/settings/exports/blocked_accounts_controller.rb index 2190caa36..906564a3d 100644 --- a/app/controllers/settings/exports/blocked_accounts_controller.rb +++ b/app/controllers/settings/exports/blocked_accounts_controller.rb @@ -3,7 +3,7 @@ module Settings module Exports class BlockedAccountsController < BaseController - include ExportControllerConcern + include Settings::ExportControllerConcern def index send_export_file diff --git a/app/controllers/settings/exports/blocked_domains_controller.rb b/app/controllers/settings/exports/blocked_domains_controller.rb index bee4b2431..09dc52392 100644 --- a/app/controllers/settings/exports/blocked_domains_controller.rb +++ b/app/controllers/settings/exports/blocked_domains_controller.rb @@ -3,7 +3,7 @@ module Settings module Exports class BlockedDomainsController < BaseController - include ExportControllerConcern + include Settings::ExportControllerConcern def index send_export_file diff --git a/app/controllers/settings/exports/bookmarks_controller.rb b/app/controllers/settings/exports/bookmarks_controller.rb index c12e2f147..0321565b9 100644 --- a/app/controllers/settings/exports/bookmarks_controller.rb +++ b/app/controllers/settings/exports/bookmarks_controller.rb @@ -3,7 +3,7 @@ module Settings module Exports class BookmarksController < BaseController - include ExportControllerConcern + include Settings::ExportControllerConcern def index send_export_file diff --git a/app/controllers/settings/exports/following_accounts_controller.rb b/app/controllers/settings/exports/following_accounts_controller.rb index acefcb15d..0ac9031fb 100644 --- a/app/controllers/settings/exports/following_accounts_controller.rb +++ b/app/controllers/settings/exports/following_accounts_controller.rb @@ -3,7 +3,7 @@ module Settings module Exports class FollowingAccountsController < BaseController - include ExportControllerConcern + include Settings::ExportControllerConcern def index send_export_file diff --git a/app/controllers/settings/exports/lists_controller.rb b/app/controllers/settings/exports/lists_controller.rb index bc65f56a0..d90c71e24 100644 --- a/app/controllers/settings/exports/lists_controller.rb +++ b/app/controllers/settings/exports/lists_controller.rb @@ -3,7 +3,7 @@ module Settings module Exports class ListsController < BaseController - include ExportControllerConcern + include Settings::ExportControllerConcern def index send_export_file diff --git a/app/controllers/settings/exports/muted_accounts_controller.rb b/app/controllers/settings/exports/muted_accounts_controller.rb index 50b7bf1f7..e4b115890 100644 --- a/app/controllers/settings/exports/muted_accounts_controller.rb +++ b/app/controllers/settings/exports/muted_accounts_controller.rb @@ -3,7 +3,7 @@ module Settings module Exports class MutedAccountsController < BaseController - include ExportControllerConcern + include Settings::ExportControllerConcern def index send_export_file diff --git a/spec/controllers/concerns/rate_limit_headers_spec.rb b/spec/controllers/concerns/api/rate_limit_headers_spec.rb similarity index 95% rename from spec/controllers/concerns/rate_limit_headers_spec.rb rename to spec/controllers/concerns/api/rate_limit_headers_spec.rb index 1cdf741f4..2050de2ae 100644 --- a/spec/controllers/concerns/rate_limit_headers_spec.rb +++ b/spec/controllers/concerns/api/rate_limit_headers_spec.rb @@ -2,9 +2,9 @@ require 'rails_helper' -describe RateLimitHeaders do +describe Api::RateLimitHeaders do controller(ApplicationController) do - include RateLimitHeaders + include Api::RateLimitHeaders def show head 200 diff --git a/spec/controllers/concerns/export_controller_concern_spec.rb b/spec/controllers/concerns/settings/export_controller_concern_spec.rb similarity index 89% rename from spec/controllers/concerns/export_controller_concern_spec.rb rename to spec/controllers/concerns/settings/export_controller_concern_spec.rb index 7f0a7c5b5..a19af8689 100644 --- a/spec/controllers/concerns/export_controller_concern_spec.rb +++ b/spec/controllers/concerns/settings/export_controller_concern_spec.rb @@ -2,9 +2,9 @@ require 'rails_helper' -describe ExportControllerConcern do +describe Settings::ExportControllerConcern do controller(ApplicationController) do - include ExportControllerConcern + include Settings::ExportControllerConcern def index send_export_file From 35deaaf90bec91f34b3e1f2afa472d5c3f2cdc75 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 30 Nov 2023 10:41:26 -0500 Subject: [PATCH 168/255] Reduce AbcSize complexity in `InitialStateSerializer` (#27782) --- .rubocop_todo.yml | 2 +- app/serializers/initial_state_serializer.rb | 48 ++++++++++++--------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 43af4f670..dbd5beac2 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -26,7 +26,7 @@ Lint/NonLocalExitFromIterator: # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. Metrics/AbcSize: - Max: 144 + Max: 125 # Configuration parameters: CountBlocks, Max. Metrics/BlockNesting: diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index b707d6fcb..a8af45990 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -39,18 +39,18 @@ class InitialStateSerializer < ActiveModel::Serializer if object.current_account store[:me] = object.current_account.id.to_s - store[:unfollow_modal] = object.current_account.user.setting_unfollow_modal - store[:boost_modal] = object.current_account.user.setting_boost_modal - store[:delete_modal] = object.current_account.user.setting_delete_modal - store[:auto_play_gif] = object.current_account.user.setting_auto_play_gif - store[:display_media] = object.current_account.user.setting_display_media - store[:expand_spoilers] = object.current_account.user.setting_expand_spoilers - store[:reduce_motion] = object.current_account.user.setting_reduce_motion - store[:disable_swiping] = object.current_account.user.setting_disable_swiping - store[:advanced_layout] = object.current_account.user.setting_advanced_layout - store[:use_blurhash] = object.current_account.user.setting_use_blurhash - store[:use_pending_items] = object.current_account.user.setting_use_pending_items - store[:show_trends] = Setting.trends && object.current_account.user.setting_trends + store[:unfollow_modal] = object_account_user.setting_unfollow_modal + store[:boost_modal] = object_account_user.setting_boost_modal + store[:delete_modal] = object_account_user.setting_delete_modal + store[:auto_play_gif] = object_account_user.setting_auto_play_gif + store[:display_media] = object_account_user.setting_display_media + store[:expand_spoilers] = object_account_user.setting_expand_spoilers + store[:reduce_motion] = object_account_user.setting_reduce_motion + store[:disable_swiping] = object_account_user.setting_disable_swiping + store[:advanced_layout] = object_account_user.setting_advanced_layout + store[:use_blurhash] = object_account_user.setting_use_blurhash + store[:use_pending_items] = object_account_user.setting_use_pending_items + store[:show_trends] = Setting.trends && object_account_user.setting_trends else store[:auto_play_gif] = Setting.auto_play_gif store[:display_media] = Setting.display_media @@ -71,9 +71,9 @@ class InitialStateSerializer < ActiveModel::Serializer if object.current_account store[:me] = object.current_account.id.to_s - store[:default_privacy] = object.visibility || object.current_account.user.setting_default_privacy - store[:default_sensitive] = object.current_account.user.setting_default_sensitive - store[:default_language] = object.current_account.user.preferred_posting_language + store[:default_privacy] = object.visibility || object_account_user.setting_default_privacy + store[:default_sensitive] = object_account_user.setting_default_sensitive + store[:default_language] = object_account_user.preferred_posting_language end store[:text] = object.text if object.text @@ -89,11 +89,11 @@ class InitialStateSerializer < ActiveModel::Serializer associations: [:account_stat, :user, { moved_to_account: [:account_stat, :user] }] ) - store[object.current_account.id.to_s] = ActiveModelSerializers::SerializableResource.new(object.current_account, serializer: REST::AccountSerializer) if object.current_account - store[object.admin.id.to_s] = ActiveModelSerializers::SerializableResource.new(object.admin, serializer: REST::AccountSerializer) if object.admin - store[object.owner.id.to_s] = ActiveModelSerializers::SerializableResource.new(object.owner, serializer: REST::AccountSerializer) if object.owner - store[object.disabled_account.id.to_s] = ActiveModelSerializers::SerializableResource.new(object.disabled_account, serializer: REST::AccountSerializer) if object.disabled_account - store[object.moved_to_account.id.to_s] = ActiveModelSerializers::SerializableResource.new(object.moved_to_account, serializer: REST::AccountSerializer) if object.moved_to_account + store[object.current_account.id.to_s] = serialized_account(object.current_account) if object.current_account + store[object.admin.id.to_s] = serialized_account(object.admin) if object.admin + store[object.owner.id.to_s] = serialized_account(object.owner) if object.owner + store[object.disabled_account.id.to_s] = serialized_account(object.disabled_account) if object.disabled_account + store[object.moved_to_account.id.to_s] = serialized_account(object.moved_to_account) if object.moved_to_account store end @@ -108,6 +108,14 @@ class InitialStateSerializer < ActiveModel::Serializer private + def object_account_user + object.current_account.user + end + + def serialized_account(account) + ActiveModelSerializers::SerializableResource.new(account, serializer: REST::AccountSerializer) + end + def instance_presenter @instance_presenter ||= InstancePresenter.new end From 963354978a0ba27c6ecea4a419b3330b3ad97733 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Thu, 30 Nov 2023 16:43:26 +0100 Subject: [PATCH 169/255] Add `Account#unavailable?` and `Account#permanently_unavailable?` aliases (#28053) --- app/controllers/api/base_controller.rb | 2 +- .../accounts/follower_accounts_controller.rb | 2 +- .../accounts/following_accounts_controller.rb | 2 +- .../api/v1/accounts/statuses_controller.rb | 2 +- .../auth/registrations_controller.rb | 2 +- .../concerns/account_owned_concern.rb | 6 ++-- .../authorized_applications_controller.rb | 2 +- app/controllers/settings/base_controller.rb | 2 +- .../settings/deletes_controller.rb | 2 +- .../well_known/webfinger_controller.rb | 2 +- app/lib/account_statuses_filter.rb | 6 +--- app/lib/activitypub/activity/move.rb | 2 +- app/models/account.rb | 3 ++ app/models/user.rb | 2 +- app/policies/status_policy.rb | 2 +- .../activitypub/actor_serializer.rb | 22 +++++++------- app/serializers/rest/account_serializer.rb | 30 +++++++++---------- app/services/follow_service.rb | 2 +- app/services/notify_service.rb | 2 +- app/services/process_mentions_service.rb | 2 +- app/services/report_service.rb | 2 +- app/views/admin/accounts/_account.html.haml | 8 ++--- .../authorized_applications/index.html.haml | 2 +- app/workers/account_deletion_worker.rb | 2 +- .../suspended_user_cleanup_scheduler.rb | 4 +-- 25 files changed, 57 insertions(+), 58 deletions(-) diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index dc760297d..c81ba32b0 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -105,7 +105,7 @@ class Api::BaseController < ApplicationController end def require_not_suspended! - render json: { error: 'Your login is currently disabled' }, status: 403 if current_user&.account&.suspended? + render json: { error: 'Your login is currently disabled' }, status: 403 if current_user&.account&.unavailable? end def require_user! diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb index 1a996d362..21b1095f1 100644 --- a/app/controllers/api/v1/accounts/follower_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb @@ -26,7 +26,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController end def hide_results? - @account.suspended? || (@account.hides_followers? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account)) + @account.unavailable? || (@account.hides_followers? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account)) end def default_accounts diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb index 6e6ebae43..1db521f79 100644 --- a/app/controllers/api/v1/accounts/following_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb @@ -26,7 +26,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController end def hide_results? - @account.suspended? || (@account.hides_following? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account)) + @account.unavailable? || (@account.hides_following? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account)) end def default_accounts diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb index 51f541bd2..fe4279302 100644 --- a/app/controllers/api/v1/accounts/statuses_controller.rb +++ b/app/controllers/api/v1/accounts/statuses_controller.rb @@ -19,7 +19,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController end def load_statuses - @account.suspended? ? [] : cached_account_statuses + @account.unavailable? ? [] : cached_account_statuses end def cached_account_statuses diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index 4535ecdbd..acfc0af0d 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -120,7 +120,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController end def require_not_suspended! - forbidden if current_account.suspended? + forbidden if current_account.unavailable? end def set_rules diff --git a/app/controllers/concerns/account_owned_concern.rb b/app/controllers/concerns/account_owned_concern.rb index 3fc0938bf..2b132417f 100644 --- a/app/controllers/concerns/account_owned_concern.rb +++ b/app/controllers/concerns/account_owned_concern.rb @@ -34,8 +34,8 @@ module AccountOwnedConcern end def check_account_suspension - if @account.suspended_permanently? - permanent_suspension_response + if @account.permanently_unavailable? + permanent_unavailability_response elsif @account.suspended? && !skip_temporary_suspension_response? temporary_suspension_response end @@ -45,7 +45,7 @@ module AccountOwnedConcern false end - def permanent_suspension_response + def permanent_unavailability_response expires_in(3.minutes, public: true) gone end diff --git a/app/controllers/oauth/authorized_applications_controller.rb b/app/controllers/oauth/authorized_applications_controller.rb index 350ae2e90..8440df6b7 100644 --- a/app/controllers/oauth/authorized_applications_controller.rb +++ b/app/controllers/oauth/authorized_applications_controller.rb @@ -31,7 +31,7 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio end def require_not_suspended! - forbidden if current_account.suspended? + forbidden if current_account.unavailable? end def set_cache_headers diff --git a/app/controllers/settings/base_controller.rb b/app/controllers/settings/base_controller.rb index 64dcd47d1..f15140aa2 100644 --- a/app/controllers/settings/base_controller.rb +++ b/app/controllers/settings/base_controller.rb @@ -18,6 +18,6 @@ class Settings::BaseController < ApplicationController end def require_not_suspended! - forbidden if current_account.suspended? + forbidden if current_account.unavailable? end end diff --git a/app/controllers/settings/deletes_controller.rb b/app/controllers/settings/deletes_controller.rb index bb096567a..16c201b6b 100644 --- a/app/controllers/settings/deletes_controller.rb +++ b/app/controllers/settings/deletes_controller.rb @@ -25,7 +25,7 @@ class Settings::DeletesController < Settings::BaseController end def require_not_suspended! - forbidden if current_account.suspended? + forbidden if current_account.unavailable? end def challenge_passed? diff --git a/app/controllers/well_known/webfinger_controller.rb b/app/controllers/well_known/webfinger_controller.rb index 4748940f7..364fbf8a1 100644 --- a/app/controllers/well_known/webfinger_controller.rb +++ b/app/controllers/well_known/webfinger_controller.rb @@ -42,7 +42,7 @@ module WellKnown end def check_account_suspension - gone if @account.suspended_permanently? + gone if @account.permanently_unavailable? end def gone diff --git a/app/lib/account_statuses_filter.rb b/app/lib/account_statuses_filter.rb index d1365de58..eb7592cdc 100644 --- a/app/lib/account_statuses_filter.rb +++ b/app/lib/account_statuses_filter.rb @@ -32,7 +32,7 @@ class AccountStatusesFilter private def initial_scope - return Status.none if suspended? + return Status.none if account.unavailable? if anonymous? account.statuses.where(visibility: %i(public unlisted)) @@ -95,10 +95,6 @@ class AccountStatusesFilter end end - def suspended? - account.suspended? - end - def anonymous? current_account.nil? end diff --git a/app/lib/activitypub/activity/move.rb b/app/lib/activitypub/activity/move.rb index 8576ceccd..7bd7e238e 100644 --- a/app/lib/activitypub/activity/move.rb +++ b/app/lib/activitypub/activity/move.rb @@ -9,7 +9,7 @@ class ActivityPub::Activity::Move < ActivityPub::Activity target_account = ActivityPub::FetchRemoteAccountService.new.call(target_uri) - if target_account.nil? || target_account.suspended? || !target_account.also_known_as.include?(origin_account.uri) + if target_account.nil? || target_account.unavailable? || !target_account.also_known_as.include?(origin_account.uri) unmark_as_processing! return end diff --git a/app/models/account.rb b/app/models/account.rb index a25ebc4aa..03edcb2a2 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -246,6 +246,9 @@ class Account < ApplicationRecord suspended? && deletion_request.present? end + alias unavailable? suspended? + alias permanently_unavailable? suspended_permanently? + def suspend!(date: Time.now.utc, origin: :local, block_email: true) transaction do create_deletion_request! diff --git a/app/models/user.rb b/app/models/user.rb index 5185343af..b0eba97c3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -250,7 +250,7 @@ class User < ApplicationRecord end def functional_or_moved? - confirmed? && approved? && !disabled? && !account.suspended? && !account.memorial? + confirmed? && approved? && !disabled? && !account.unavailable? && !account.memorial? end def unconfirmed? diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb index f3d0ffdba..322d3aec5 100644 --- a/app/policies/status_policy.rb +++ b/app/policies/status_policy.rb @@ -8,7 +8,7 @@ class StatusPolicy < ApplicationPolicy end def show? - return false if author.suspended? + return false if author.unavailable? if requires_mention? owned? || mention_exists? diff --git a/app/serializers/activitypub/actor_serializer.rb b/app/serializers/activitypub/actor_serializer.rb index 31f39954f..4ab48ff20 100644 --- a/app/serializers/activitypub/actor_serializer.rb +++ b/app/serializers/activitypub/actor_serializer.rb @@ -96,19 +96,19 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer end def discoverable - object.suspended? ? false : (object.discoverable || false) + object.unavailable? ? false : (object.discoverable || false) end def indexable - object.suspended? ? false : (object.indexable || false) + object.unavailable? ? false : (object.indexable || false) end def name - object.suspended? ? object.username : (object.display_name.presence || object.username) + object.unavailable? ? object.username : (object.display_name.presence || object.username) end def summary - object.suspended? ? '' : account_bio_format(object) + object.unavailable? ? '' : account_bio_format(object) end def icon @@ -132,23 +132,23 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer end def avatar_exists? - !object.suspended? && object.avatar? + !object.unavailable? && object.avatar? end def header_exists? - !object.suspended? && object.header? + !object.unavailable? && object.header? end def manually_approves_followers - object.suspended? ? false : object.locked + object.unavailable? ? false : object.locked end def virtual_tags - object.suspended? ? [] : (object.emojis + object.tags) + object.unavailable? ? [] : (object.emojis + object.tags) end def virtual_attachments - object.suspended? ? [] : object.fields + object.unavailable? ? [] : object.fields end def moved_to @@ -156,11 +156,11 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer end def moved? - !object.suspended? && object.moved? + !object.unavailable? && object.moved? end def also_known_as? - !object.suspended? && !object.also_known_as.empty? + !object.unavailable? && !object.also_known_as.empty? end def published diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb index 5d1292a6b..354d38446 100644 --- a/app/serializers/rest/account_serializer.rb +++ b/app/serializers/rest/account_serializer.rb @@ -61,7 +61,7 @@ class REST::AccountSerializer < ActiveModel::Serializer end def note - object.suspended? ? '' : account_bio_format(object) + object.unavailable? ? '' : account_bio_format(object) end def url @@ -73,19 +73,19 @@ class REST::AccountSerializer < ActiveModel::Serializer end def avatar - full_asset_url(object.suspended? ? object.avatar.default_url : object.avatar_original_url) + full_asset_url(object.unavailable? ? object.avatar.default_url : object.avatar_original_url) end def avatar_static - full_asset_url(object.suspended? ? object.avatar.default_url : object.avatar_static_url) + full_asset_url(object.unavailable? ? object.avatar.default_url : object.avatar_static_url) end def header - full_asset_url(object.suspended? ? object.header.default_url : object.header_original_url) + full_asset_url(object.unavailable? ? object.header.default_url : object.header_original_url) end def header_static - full_asset_url(object.suspended? ? object.header.default_url : object.header_static_url) + full_asset_url(object.unavailable? ? object.header.default_url : object.header_static_url) end def created_at @@ -97,39 +97,39 @@ class REST::AccountSerializer < ActiveModel::Serializer end def display_name - object.suspended? ? '' : object.display_name + object.unavailable? ? '' : object.display_name end def locked - object.suspended? ? false : object.locked + object.unavailable? ? false : object.locked end def bot - object.suspended? ? false : object.bot + object.unavailable? ? false : object.bot end def discoverable - object.suspended? ? false : object.discoverable + object.unavailable? ? false : object.discoverable end def indexable - object.suspended? ? false : object.indexable + object.unavailable? ? false : object.indexable end def moved_to_account - object.suspended? ? nil : AccountDecorator.new(object.moved_to_account) + object.unavailable? ? nil : AccountDecorator.new(object.moved_to_account) end def emojis - object.suspended? ? [] : object.emojis + object.unavailable? ? [] : object.emojis end def fields - object.suspended? ? [] : object.fields + object.unavailable? ? [] : object.fields end def suspended - object.suspended? + object.unavailable? end def silenced @@ -141,7 +141,7 @@ class REST::AccountSerializer < ActiveModel::Serializer end def roles - if object.suspended? || object.user.nil? + if object.unavailable? || object.user.nil? [] else [object.user.role].compact.filter(&:highlighted?) diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index 1aa0241fe..af5f99607 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -50,7 +50,7 @@ class FollowService < BaseService end def following_not_possible? - @target_account.nil? || @target_account.id == @source_account.id || @target_account.suspended? + @target_account.nil? || @target_account.id == @source_account.id || @target_account.unavailable? end def following_not_allowed? diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index 125883b15..13eb20986 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -108,7 +108,7 @@ class NotifyService < BaseService end def blocked? - blocked = @recipient.suspended? + blocked = @recipient.unavailable? blocked ||= from_self? && @notification.type != :poll return blocked if message? && from_staff? diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb index f3fbb8021..1c4c7805f 100644 --- a/app/services/process_mentions_service.rb +++ b/app/services/process_mentions_service.rb @@ -51,7 +51,7 @@ class ProcessMentionsService < BaseService # If after resolving it still isn't found or isn't the right # protocol, then give up - next match if mention_undeliverable?(mentioned_account) || mentioned_account&.suspended? + next match if mention_undeliverable?(mentioned_account) || mentioned_account&.unavailable? mention = @previous_mentions.find { |x| x.account_id == mentioned_account.id } mention ||= @current_mentions.find { |x| x.account_id == mentioned_account.id } diff --git a/app/services/report_service.rb b/app/services/report_service.rb index 38e55c5b6..fe546c383 100644 --- a/app/services/report_service.rb +++ b/app/services/report_service.rb @@ -12,7 +12,7 @@ class ReportService < BaseService @rule_ids = options.delete(:rule_ids).presence @options = options - raise ActiveRecord::RecordNotFound if @target_account.suspended? + raise ActiveRecord::RecordNotFound if @target_account.unavailable? create_report! notify_staff! diff --git a/app/views/admin/accounts/_account.html.haml b/app/views/admin/accounts/_account.html.haml index 755b987a8..d2f6652a0 100644 --- a/app/views/admin/accounts/_account.html.haml +++ b/app/views/admin/accounts/_account.html.haml @@ -1,4 +1,4 @@ -.batch-table__row{ class: [!account.suspended? && account.user_pending? && 'batch-table__row--attention', (account.suspended? || account.user_unconfirmed?) && 'batch-table__row--muted'] } +.batch-table__row{ class: [!account.unavailable? && account.user_pending? && 'batch-table__row--attention', (account.unavailable? || account.user_unconfirmed?) && 'batch-table__row--muted'] } %label.batch-table__row__select.batch-table__row__select--aligned.batch-checkbox = f.check_box :account_ids, { multiple: true, include_hidden: false }, account.id .batch-table__row__content.batch-table__row__content--unpadded @@ -8,13 +8,13 @@ %td = account_link_to account, path: admin_account_path(account.id) %td.accounts-table__count.optional - - if account.suspended? || account.user_pending? + - if account.unavailable? || account.user_pending? \- - else = friendly_number_to_human account.statuses_count %small= t('accounts.posts', count: account.statuses_count).downcase %td.accounts-table__count.optional - - if account.suspended? || account.user_pending? + - if account.unavailable? || account.user_pending? \- - else = friendly_number_to_human account.followers_count @@ -30,6 +30,6 @@ \- %br/ %samp.ellipsized-ip= relevant_account_ip(account, params[:ip]) - - if !account.suspended? && account.user_pending? && account.user&.invite_request&.text.present? + - if !account.unavailable? && account.user_pending? && account.user&.invite_request&.text.present? .batch-table__row__content__quote %p= account.user&.invite_request&.text diff --git a/app/views/oauth/authorized_applications/index.html.haml b/app/views/oauth/authorized_applications/index.html.haml index 40b09d87f..92e24d30c 100644 --- a/app/views/oauth/authorized_applications/index.html.haml +++ b/app/views/oauth/authorized_applications/index.html.haml @@ -27,7 +27,7 @@ = t('doorkeeper.authorized_applications.index.authorized_at', date: l(application.created_at.to_date)) - - unless application.superapp? || current_account.suspended? + - unless application.superapp? || current_account.unavailable? %div = table_link_to 'times', t('doorkeeper.authorized_applications.buttons.revoke'), oauth_authorized_application_path(application), method: :delete, data: { confirm: t('doorkeeper.authorized_applications.confirmations.revoke') } diff --git a/app/workers/account_deletion_worker.rb b/app/workers/account_deletion_worker.rb index e4f943fbd..070352f95 100644 --- a/app/workers/account_deletion_worker.rb +++ b/app/workers/account_deletion_worker.rb @@ -7,7 +7,7 @@ class AccountDeletionWorker def perform(account_id, options = {}) account = Account.find(account_id) - return unless account.suspended? + return unless account.unavailable? reserve_username = options.with_indifferent_access.fetch(:reserve_username, true) skip_activitypub = options.with_indifferent_access.fetch(:skip_activitypub, false) diff --git a/app/workers/scheduler/suspended_user_cleanup_scheduler.rb b/app/workers/scheduler/suspended_user_cleanup_scheduler.rb index 90feead67..4ea81c785 100644 --- a/app/workers/scheduler/suspended_user_cleanup_scheduler.rb +++ b/app/workers/scheduler/suspended_user_cleanup_scheduler.rb @@ -21,12 +21,12 @@ class Scheduler::SuspendedUserCleanupScheduler def perform return if Sidekiq::Queue.new('pull').size > MAX_PULL_SIZE - clean_suspended_accounts! + process_deletion_requests! end private - def clean_suspended_accounts! + def process_deletion_requests! # This should be fine because we only process a small amount of deletion requests at once and # `id` and `created_at` should follow the same order. AccountDeletionRequest.reorder(id: :asc).take(MAX_DELETIONS_PER_JOB).each do |deletion_request| From 8710bdb183073381250085ffa20e21e22d9069b6 Mon Sep 17 00:00:00 2001 From: Michael Stanclift <mx@vmstan.com> Date: Thu, 30 Nov 2023 10:11:21 -0600 Subject: [PATCH 170/255] Fix mastodon user not being owner of tmp folder in Dockerfile (#28137) --- Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ed5ebf1e0..4d5bd57f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -247,7 +247,9 @@ RUN \ RUN \ # Pre-create and chown system volume to Mastodon user mkdir -p /opt/mastodon/public/system; \ - chown mastodon:mastodon /opt/mastodon/public/system; + chown mastodon:mastodon /opt/mastodon/public/system; \ +# Set Mastodon user as owner of tmp folder + chown -R mastodon:mastodon /opt/mastodon/tmp; # Set the running user for resulting container USER mastodon From b751078fcd21d13f6e4b63d7a86dd2be893d2753 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 05:38:15 -0500 Subject: [PATCH 171/255] Eliminate double subject call in admin/ controller specs (#28158) --- .../account_moderation_notes_controller_spec.rb | 6 +++--- .../admin/custom_emojis_controller_spec.rb | 16 ++++++++-------- .../admin/report_notes_controller_spec.rb | 10 +++++----- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/spec/controllers/admin/account_moderation_notes_controller_spec.rb b/spec/controllers/admin/account_moderation_notes_controller_spec.rb index 3e1b4b280..8d24a7af3 100644 --- a/spec/controllers/admin/account_moderation_notes_controller_spec.rb +++ b/spec/controllers/admin/account_moderation_notes_controller_spec.rb @@ -20,7 +20,7 @@ RSpec.describe Admin::AccountModerationNotesController do it 'successfully creates a note' do expect { subject }.to change(AccountModerationNote, :count).by(1) - expect(subject).to redirect_to admin_account_path(target_account.id) + expect(response).to redirect_to admin_account_path(target_account.id) end end @@ -29,7 +29,7 @@ RSpec.describe Admin::AccountModerationNotesController do it 'falls to create a note' do expect { subject }.to_not change(AccountModerationNote, :count) - expect(subject).to render_template 'admin/accounts/show' + expect(response).to render_template 'admin/accounts/show' end end end @@ -42,7 +42,7 @@ RSpec.describe Admin::AccountModerationNotesController do it 'destroys note' do expect { subject }.to change(AccountModerationNote, :count).by(-1) - expect(subject).to redirect_to admin_account_path(target_account.id) + expect(response).to redirect_to admin_account_path(target_account.id) end end end diff --git a/spec/controllers/admin/custom_emojis_controller_spec.rb b/spec/controllers/admin/custom_emojis_controller_spec.rb index 6c32a3a57..9e732200d 100644 --- a/spec/controllers/admin/custom_emojis_controller_spec.rb +++ b/spec/controllers/admin/custom_emojis_controller_spec.rb @@ -12,24 +12,24 @@ describe Admin::CustomEmojisController do end describe 'GET #index' do - subject { get :index } - before do Fabricate(:custom_emoji) end it 'renders index page' do - expect(subject).to have_http_status 200 - expect(subject).to render_template :index + get :index + + expect(response).to have_http_status 200 + expect(response).to render_template :index end end describe 'GET #new' do - subject { get :new } - it 'renders new page' do - expect(subject).to have_http_status 200 - expect(subject).to render_template :new + get :new + + expect(response).to have_http_status 200 + expect(response).to render_template :new end end diff --git a/spec/controllers/admin/report_notes_controller_spec.rb b/spec/controllers/admin/report_notes_controller_spec.rb index b5ba4a84d..4ddf4a4e2 100644 --- a/spec/controllers/admin/report_notes_controller_spec.rb +++ b/spec/controllers/admin/report_notes_controller_spec.rb @@ -27,7 +27,7 @@ describe Admin::ReportNotesController do it 'creates a report note and resolves report' do expect { subject }.to change(ReportNote, :count).by(1) expect(report.reload).to be_action_taken - expect(subject).to redirect_to admin_reports_path + expect(response).to redirect_to admin_reports_path end end @@ -37,7 +37,7 @@ describe Admin::ReportNotesController do it 'creates a report note and does not resolve report' do expect { subject }.to change(ReportNote, :count).by(1) expect(report.reload).to_not be_action_taken - expect(subject).to redirect_to admin_report_path(report) + expect(response).to redirect_to admin_report_path(report) end end end @@ -52,7 +52,7 @@ describe Admin::ReportNotesController do it 'creates a report note and unresolves report' do expect { subject }.to change(ReportNote, :count).by(1) expect(report.reload).to_not be_action_taken - expect(subject).to redirect_to admin_report_path(report) + expect(response).to redirect_to admin_report_path(report) end end @@ -62,7 +62,7 @@ describe Admin::ReportNotesController do it 'creates a report note and does not unresolve report' do expect { subject }.to change(ReportNote, :count).by(1) expect(report.reload).to be_action_taken - expect(subject).to redirect_to admin_report_path(report) + expect(response).to redirect_to admin_report_path(report) end end end @@ -86,7 +86,7 @@ describe Admin::ReportNotesController do it 'deletes note' do expect { subject }.to change(ReportNote, :count).by(-1) - expect(subject).to redirect_to admin_report_path(report_note.report) + expect(response).to redirect_to admin_report_path(report_note.report) end end end From 440b80b2e795c21a22de4514160679e68561d98b Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 06:00:41 -0500 Subject: [PATCH 172/255] Model concerns organization into module namespaces (#28149) --- .rubocop_todo.yml | 18 ++++++------- app/models/account.rb | 25 ++++++++++--------- .../associations.rb} | 2 +- .../{account_avatar.rb => account/avatar.rb} | 2 +- .../counters.rb} | 2 +- .../finder_concern.rb} | 2 +- .../{account_header.rb => account/header.rb} | 2 +- .../interactions.rb} | 2 +- .../merging.rb} | 2 +- .../{account_search.rb => account/search.rb} | 2 +- .../statuses_search.rb} | 2 +- .../safe_reblog_insert.rb} | 2 +- .../search_concern.rb} | 2 +- .../snapshot_concern.rb} | 2 +- .../threading_concern.rb} | 2 +- .../has_settings.rb} | 2 +- .../concerns/{ => user}/ldap_authenticable.rb | 2 +- .../concerns/{ => user}/omniauthable.rb | 2 +- .../concerns/{ => user}/pam_authenticable.rb | 2 +- app/models/status.rb | 10 ++++---- app/models/user.rb | 11 ++++---- app/views/settings/profiles/show.html.haml | 4 +-- lib/mastodon/cli/maintenance.rb | 4 +-- spec/models/account_spec.rb | 4 +-- .../counters_spec.rb} | 2 +- .../finder_concern_spec.rb} | 2 +- .../interactions_spec.rb} | 2 +- .../statuses_search_spec.rb} | 2 +- .../threading_concern_spec.rb} | 2 +- .../search_spec.rb} | 2 +- .../statuses_search_spec.rb} | 2 +- 31 files changed, 62 insertions(+), 62 deletions(-) rename app/models/concerns/{account_associations.rb => account/associations.rb} (99%) rename app/models/concerns/{account_avatar.rb => account/avatar.rb} (98%) rename app/models/concerns/{account_counters.rb => account/counters.rb} (99%) rename app/models/concerns/{account_finder_concern.rb => account/finder_concern.rb} (98%) rename app/models/concerns/{account_header.rb => account/header.rb} (98%) rename app/models/concerns/{account_interactions.rb => account/interactions.rb} (99%) rename app/models/concerns/{account_merging.rb => account/merging.rb} (98%) rename app/models/concerns/{account_search.rb => account/search.rb} (99%) rename app/models/concerns/{account_statuses_search.rb => account/statuses_search.rb} (97%) rename app/models/concerns/{status_safe_reblog_insert.rb => status/safe_reblog_insert.rb} (98%) rename app/models/concerns/{status_search_concern.rb => status/search_concern.rb} (97%) rename app/models/concerns/{status_snapshot_concern.rb => status/snapshot_concern.rb} (96%) rename app/models/concerns/{status_threading_concern.rb => status/threading_concern.rb} (98%) rename app/models/concerns/{has_user_settings.rb => user/has_settings.rb} (99%) rename app/models/concerns/{ => user}/ldap_authenticable.rb (98%) rename app/models/concerns/{ => user}/omniauthable.rb (99%) rename app/models/concerns/{ => user}/pam_authenticable.rb (98%) rename spec/models/concerns/{account_counters_spec.rb => account/counters_spec.rb} (98%) rename spec/models/concerns/{account_finder_concern_spec.rb => account/finder_concern_spec.rb} (98%) rename spec/models/concerns/{account_interactions_spec.rb => account/interactions_spec.rb} (99%) rename spec/models/concerns/{account_statuses_search_spec.rb => account/statuses_search_spec.rb} (98%) rename spec/models/concerns/{status_threading_concern_spec.rb => status/threading_concern_spec.rb} (99%) rename spec/search/models/concerns/{account_search_spec.rb => account/search_spec.rb} (98%) rename spec/search/models/concerns/{account_statuses_search_spec.rb => account/statuses_search_spec.rb} (98%) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index dbd5beac2..9fb163ceb 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -107,7 +107,7 @@ Rails/ApplicationController: # Include: app/models/**/*.rb Rails/HasAndBelongsToMany: Exclude: - - 'app/models/concerns/account_associations.rb' + - 'app/models/concerns/account/associations.rb' - 'app/models/preview_card.rb' - 'app/models/status.rb' - 'app/models/tag.rb' @@ -116,7 +116,7 @@ Rails/HasAndBelongsToMany: # Include: app/models/**/*.rb Rails/HasManyOrHasOneDependent: Exclude: - - 'app/models/concerns/account_counters.rb' + - 'app/models/concerns/account/counters.rb' - 'app/models/conversation.rb' - 'app/models/custom_emoji.rb' - 'app/models/custom_emoji_category.rb' @@ -172,7 +172,7 @@ Rails/SkipsModelValidations: Exclude: - 'app/controllers/admin/invites_controller.rb' - 'app/controllers/concerns/session_tracking_concern.rb' - - 'app/models/concerns/account_merging.rb' + - 'app/models/concerns/account/merging.rb' - 'app/models/concerns/expireable.rb' - 'app/models/status.rb' - 'app/models/trends/links.rb' @@ -252,7 +252,7 @@ Rails/WhereExists: - 'app/lib/feed_manager.rb' - 'app/lib/status_cache_hydrator.rb' - 'app/lib/suspicious_sign_in_detector.rb' - - 'app/models/concerns/account_interactions.rb' + - 'app/models/concerns/account/interactions.rb' - 'app/models/featured_tag.rb' - 'app/models/poll.rb' - 'app/models/session_activation.rb' @@ -342,8 +342,8 @@ Style/GuardClause: - 'app/lib/request_pool.rb' - 'app/lib/webfinger.rb' - 'app/lib/webfinger_resource.rb' - - 'app/models/concerns/account_counters.rb' - - 'app/models/concerns/ldap_authenticable.rb' + - 'app/models/concerns/account/counters.rb' + - 'app/models/concerns/user/ldap_authenticable.rb' - 'app/models/tag.rb' - 'app/models/user.rb' - 'app/services/fan_out_on_write_service.rb' @@ -372,8 +372,8 @@ Style/HashAsLastArrayItem: Exclude: - 'app/controllers/admin/statuses_controller.rb' - 'app/controllers/api/v1/statuses_controller.rb' - - 'app/models/concerns/account_counters.rb' - - 'app/models/concerns/status_threading_concern.rb' + - 'app/models/concerns/account/counters.rb' + - 'app/models/concerns/status/threading_concern.rb' - 'app/models/status.rb' - 'app/services/batched_remove_status_service.rb' - 'app/services/notify_service.rb' @@ -486,7 +486,7 @@ Style/RedundantReturn: # AllowedMethods: present?, blank?, presence, try, try! Style/SafeNavigation: Exclude: - - 'app/models/concerns/account_finder_concern.rb' + - 'app/models/concerns/account/finder_concern.rb' # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: EnforcedStyle. diff --git a/app/models/account.rb b/app/models/account.rb index 03edcb2a2..4119944e5 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -70,19 +70,20 @@ class Account < ApplicationRecord URL_PREFIX_RE = %r{\Ahttp(s?)://[^/]+} USERNAME_ONLY_RE = /\A#{USERNAME_RE}\z/i - include Attachmentable - include AccountAssociations - include AccountAvatar - include AccountFinderConcern - include AccountHeader - include AccountInteractions - include Paginable - include AccountCounters - include DomainNormalizable + include Attachmentable # Load prior to Avatar & Header concerns + + include Account::Associations + include Account::Avatar + include Account::Counters + include Account::FinderConcern + include Account::Header + include Account::Interactions + include Account::Merging + include Account::Search + include Account::StatusesSearch include DomainMaterializable - include AccountMerging - include AccountSearch - include AccountStatusesSearch + include DomainNormalizable + include Paginable enum protocol: { ostatus: 0, activitypub: 1 } enum suspension_origin: { local: 0, remote: 1 }, _prefix: true diff --git a/app/models/concerns/account_associations.rb b/app/models/concerns/account/associations.rb similarity index 99% rename from app/models/concerns/account_associations.rb rename to app/models/concerns/account/associations.rb index 592812e96..31902ae21 100644 --- a/app/models/concerns/account_associations.rb +++ b/app/models/concerns/account/associations.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module AccountAssociations +module Account::Associations extend ActiveSupport::Concern included do diff --git a/app/models/concerns/account_avatar.rb b/app/models/concerns/account/avatar.rb similarity index 98% rename from app/models/concerns/account_avatar.rb rename to app/models/concerns/account/avatar.rb index b5919a9a2..39f599db1 100644 --- a/app/models/concerns/account_avatar.rb +++ b/app/models/concerns/account/avatar.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module AccountAvatar +module Account::Avatar extend ActiveSupport::Concern IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze diff --git a/app/models/concerns/account_counters.rb b/app/models/concerns/account/counters.rb similarity index 99% rename from app/models/concerns/account_counters.rb rename to app/models/concerns/account/counters.rb index 3fabb5205..fb69be9b7 100644 --- a/app/models/concerns/account_counters.rb +++ b/app/models/concerns/account/counters.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module AccountCounters +module Account::Counters extend ActiveSupport::Concern ALLOWED_COUNTER_KEYS = %i(statuses_count following_count followers_count).freeze diff --git a/app/models/concerns/account_finder_concern.rb b/app/models/concerns/account/finder_concern.rb similarity index 98% rename from app/models/concerns/account_finder_concern.rb rename to app/models/concerns/account/finder_concern.rb index 37c3b8895..7faaddeb4 100644 --- a/app/models/concerns/account_finder_concern.rb +++ b/app/models/concerns/account/finder_concern.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module AccountFinderConcern +module Account::FinderConcern extend ActiveSupport::Concern class_methods do diff --git a/app/models/concerns/account_header.rb b/app/models/concerns/account/header.rb similarity index 98% rename from app/models/concerns/account_header.rb rename to app/models/concerns/account/header.rb index e184880f9..44ae774e9 100644 --- a/app/models/concerns/account_header.rb +++ b/app/models/concerns/account/header.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module AccountHeader +module Account::Header extend ActiveSupport::Concern IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].freeze diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account/interactions.rb similarity index 99% rename from app/models/concerns/account_interactions.rb rename to app/models/concerns/account/interactions.rb index 3c64ebd9f..0ea26e628 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account/interactions.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module AccountInteractions +module Account::Interactions extend ActiveSupport::Concern class_methods do diff --git a/app/models/concerns/account_merging.rb b/app/models/concerns/account/merging.rb similarity index 98% rename from app/models/concerns/account_merging.rb rename to app/models/concerns/account/merging.rb index 14e157a3d..960ee1819 100644 --- a/app/models/concerns/account_merging.rb +++ b/app/models/concerns/account/merging.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module AccountMerging +module Account::Merging extend ActiveSupport::Concern def merge_with!(other_account) diff --git a/app/models/concerns/account_search.rb b/app/models/concerns/account/search.rb similarity index 99% rename from app/models/concerns/account_search.rb rename to app/models/concerns/account/search.rb index b855727b4..b02b9bd46 100644 --- a/app/models/concerns/account_search.rb +++ b/app/models/concerns/account/search.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module AccountSearch +module Account::Search extend ActiveSupport::Concern DISALLOWED_TSQUERY_CHARACTERS = /['?\\:‘’]/ diff --git a/app/models/concerns/account_statuses_search.rb b/app/models/concerns/account/statuses_search.rb similarity index 97% rename from app/models/concerns/account_statuses_search.rb rename to app/models/concerns/account/statuses_search.rb index 4b2bc4117..334b71450 100644 --- a/app/models/concerns/account_statuses_search.rb +++ b/app/models/concerns/account/statuses_search.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module AccountStatusesSearch +module Account::StatusesSearch extend ActiveSupport::Concern included do diff --git a/app/models/concerns/status_safe_reblog_insert.rb b/app/models/concerns/status/safe_reblog_insert.rb similarity index 98% rename from app/models/concerns/status_safe_reblog_insert.rb rename to app/models/concerns/status/safe_reblog_insert.rb index 0007b46d4..60ddb78e5 100644 --- a/app/models/concerns/status_safe_reblog_insert.rb +++ b/app/models/concerns/status/safe_reblog_insert.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module StatusSafeReblogInsert +module Status::SafeReblogInsert extend ActiveSupport::Concern class_methods do diff --git a/app/models/concerns/status_search_concern.rb b/app/models/concerns/status/search_concern.rb similarity index 97% rename from app/models/concerns/status_search_concern.rb rename to app/models/concerns/status/search_concern.rb index 7252fde73..c16db8bd8 100644 --- a/app/models/concerns/status_search_concern.rb +++ b/app/models/concerns/status/search_concern.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module StatusSearchConcern +module Status::SearchConcern extend ActiveSupport::Concern included do diff --git a/app/models/concerns/status_snapshot_concern.rb b/app/models/concerns/status/snapshot_concern.rb similarity index 96% rename from app/models/concerns/status_snapshot_concern.rb rename to app/models/concerns/status/snapshot_concern.rb index 9741b9aeb..ba624d943 100644 --- a/app/models/concerns/status_snapshot_concern.rb +++ b/app/models/concerns/status/snapshot_concern.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module StatusSnapshotConcern +module Status::SnapshotConcern extend ActiveSupport::Concern included do diff --git a/app/models/concerns/status_threading_concern.rb b/app/models/concerns/status/threading_concern.rb similarity index 98% rename from app/models/concerns/status_threading_concern.rb rename to app/models/concerns/status/threading_concern.rb index 2ca3b66c2..2606fd2f2 100644 --- a/app/models/concerns/status_threading_concern.rb +++ b/app/models/concerns/status/threading_concern.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module StatusThreadingConcern +module Status::ThreadingConcern extend ActiveSupport::Concern def ancestors(limit, account = nil) diff --git a/app/models/concerns/has_user_settings.rb b/app/models/concerns/user/has_settings.rb similarity index 99% rename from app/models/concerns/has_user_settings.rb rename to app/models/concerns/user/has_settings.rb index b7c7104a1..bfa8aa2ca 100644 --- a/app/models/concerns/has_user_settings.rb +++ b/app/models/concerns/user/has_settings.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module HasUserSettings +module User::HasSettings extend ActiveSupport::Concern included do diff --git a/app/models/concerns/ldap_authenticable.rb b/app/models/concerns/user/ldap_authenticable.rb similarity index 98% rename from app/models/concerns/ldap_authenticable.rb rename to app/models/concerns/user/ldap_authenticable.rb index 775df0817..d84ff084b 100644 --- a/app/models/concerns/ldap_authenticable.rb +++ b/app/models/concerns/user/ldap_authenticable.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module LdapAuthenticable +module User::LdapAuthenticable extend ActiveSupport::Concern class_methods do diff --git a/app/models/concerns/omniauthable.rb b/app/models/concerns/user/omniauthable.rb similarity index 99% rename from app/models/concerns/omniauthable.rb rename to app/models/concerns/user/omniauthable.rb index 3983fbcda..6d1d1b8cc 100644 --- a/app/models/concerns/omniauthable.rb +++ b/app/models/concerns/user/omniauthable.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Omniauthable +module User::Omniauthable extend ActiveSupport::Concern TEMP_EMAIL_PREFIX = 'change@me' diff --git a/app/models/concerns/pam_authenticable.rb b/app/models/concerns/user/pam_authenticable.rb similarity index 98% rename from app/models/concerns/pam_authenticable.rb rename to app/models/concerns/user/pam_authenticable.rb index f97f986a4..a682058cc 100644 --- a/app/models/concerns/pam_authenticable.rb +++ b/app/models/concerns/user/pam_authenticable.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module PamAuthenticable +module User::PamAuthenticable extend ActiveSupport::Concern included do diff --git a/app/models/status.rb b/app/models/status.rb index 41c895029..7b1ca69c7 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -30,14 +30,14 @@ # class Status < ApplicationRecord + include Cacheable include Discard::Model include Paginable - include Cacheable - include StatusThreadingConcern - include StatusSnapshotConcern include RateLimitable - include StatusSafeReblogInsert - include StatusSearchConcern + include Status::SafeReblogInsert + include Status::SearchConcern + include Status::SnapshotConcern + include Status::ThreadingConcern rate_limit by: :account, family: :statuses diff --git a/app/models/user.rb b/app/models/user.rb index b0eba97c3..550f8bfd3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -53,9 +53,12 @@ class User < ApplicationRecord filtered_languages ) - include Redisable include LanguagesHelper - include HasUserSettings + include Redisable + include User::HasSettings + include User::LdapAuthenticable + include User::Omniauthable + include User::PamAuthenticable # The home and list feeds will be stored in Redis for this amount # of time, and status fan-out to followers will include only people @@ -75,10 +78,6 @@ class User < ApplicationRecord devise :registerable, :recoverable, :validatable, :confirmable - include Omniauthable - include PamAuthenticable - include LdapAuthenticable - belongs_to :account, inverse_of: :user belongs_to :invite, counter_cache: :uses, optional: true belongs_to :created_by_application, class_name: 'Doorkeeper::Application', optional: true diff --git a/app/views/settings/profiles/show.html.haml b/app/views/settings/profiles/show.html.haml index 7c13dc7f4..5f9613c93 100644 --- a/app/views/settings/profiles/show.html.haml +++ b/app/views/settings/profiles/show.html.haml @@ -33,7 +33,7 @@ .fields-row .fields-row__column.fields-row__column-6 .fields-group - = f.input :avatar, wrapper: :with_block_label, input_html: { accept: AccountAvatar::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.avatar', dimensions: '400x400', size: number_to_human_size(AccountAvatar::LIMIT)) + = f.input :avatar, wrapper: :with_block_label, input_html: { accept: Account::Avatar::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.avatar', dimensions: '400x400', size: number_to_human_size(Account::Avatar::LIMIT)) .fields-row__column.fields-row__column-6 .fields-group @@ -46,7 +46,7 @@ .fields-row .fields-row__column.fields-row__column-6 .fields-group - = f.input :header, wrapper: :with_block_label, input_html: { accept: AccountHeader::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(AccountHeader::LIMIT)) + = f.input :header, wrapper: :with_block_label, input_html: { accept: Account::Header::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.header', dimensions: '1500x500', size: number_to_human_size(Account::Header::LIMIT)) .fields-row__column.fields-row__column-6 .fields-group diff --git a/lib/mastodon/cli/maintenance.rb b/lib/mastodon/cli/maintenance.rb index a95b7a30c..c53d74254 100644 --- a/lib/mastodon/cli/maintenance.rb +++ b/lib/mastodon/cli/maintenance.rb @@ -67,8 +67,8 @@ module Mastodon::CLI local? ? username : "#{username}@#{domain}" end - # This is a duplicate of the AccountMerging concern because we need it to - # be independent from code version. + # This is a duplicate of the Account::Merging concern because we need it + # to be independent from code version. def merge_with!(other_account) # Since it's the same remote resource, the remote resource likely # already believes we are following/blocking, so it's safe to diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 9652ea191..522549125 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -451,7 +451,7 @@ RSpec.describe Account do end it 'limits via constant by default' do - stub_const('AccountSearch::DEFAULT_LIMIT', 1) + stub_const('Account::Search::DEFAULT_LIMIT', 1) 2.times.each { Fabricate(:account, display_name: 'Display Name') } results = described_class.search_for('display') expect(results.size).to eq 1 @@ -595,7 +595,7 @@ RSpec.describe Account do end it 'limits by 10 by default' do - stub_const('AccountSearch::DEFAULT_LIMIT', 1) + stub_const('Account::Search::DEFAULT_LIMIT', 1) 2.times { Fabricate(:account, display_name: 'Display Name') } results = described_class.advanced_search_for('display', account) expect(results.size).to eq 1 diff --git a/spec/models/concerns/account_counters_spec.rb b/spec/models/concerns/account/counters_spec.rb similarity index 98% rename from spec/models/concerns/account_counters_spec.rb rename to spec/models/concerns/account/counters_spec.rb index fb02d79f1..2e1cd700b 100644 --- a/spec/models/concerns/account_counters_spec.rb +++ b/spec/models/concerns/account/counters_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe AccountCounters do +describe Account::Counters do let!(:account) { Fabricate(:account) } describe '#increment_count!' do diff --git a/spec/models/concerns/account_finder_concern_spec.rb b/spec/models/concerns/account/finder_concern_spec.rb similarity index 98% rename from spec/models/concerns/account_finder_concern_spec.rb rename to spec/models/concerns/account/finder_concern_spec.rb index 3a94c4d54..ab5149e98 100644 --- a/spec/models/concerns/account_finder_concern_spec.rb +++ b/spec/models/concerns/account/finder_concern_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe AccountFinderConcern do +describe Account::FinderConcern do describe 'local finders' do let!(:account) { Fabricate(:account, username: 'Alice') } diff --git a/spec/models/concerns/account_interactions_spec.rb b/spec/models/concerns/account/interactions_spec.rb similarity index 99% rename from spec/models/concerns/account_interactions_spec.rb rename to spec/models/concerns/account/interactions_spec.rb index 6687c8443..6fac41e07 100644 --- a/spec/models/concerns/account_interactions_spec.rb +++ b/spec/models/concerns/account/interactions_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe AccountInteractions do +describe Account::Interactions do let(:account) { Fabricate(:account, username: 'account') } let(:account_id) { account.id } let(:account_ids) { [account_id] } diff --git a/spec/models/concerns/account_statuses_search_spec.rb b/spec/models/concerns/account/statuses_search_spec.rb similarity index 98% rename from spec/models/concerns/account_statuses_search_spec.rb rename to spec/models/concerns/account/statuses_search_spec.rb index 46362936f..ab249d62d 100644 --- a/spec/models/concerns/account_statuses_search_spec.rb +++ b/spec/models/concerns/account/statuses_search_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe AccountStatusesSearch do +describe Account::StatusesSearch do let(:account) { Fabricate(:account, indexable: indexable) } before do diff --git a/spec/models/concerns/status_threading_concern_spec.rb b/spec/models/concerns/status/threading_concern_spec.rb similarity index 99% rename from spec/models/concerns/status_threading_concern_spec.rb rename to spec/models/concerns/status/threading_concern_spec.rb index 2eac1ca6e..09fb21856 100644 --- a/spec/models/concerns/status_threading_concern_spec.rb +++ b/spec/models/concerns/status/threading_concern_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe StatusThreadingConcern do +describe Status::ThreadingConcern do describe '#ancestors' do let!(:alice) { Fabricate(:account, username: 'alice') } let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') } diff --git a/spec/search/models/concerns/account_search_spec.rb b/spec/search/models/concerns/account/search_spec.rb similarity index 98% rename from spec/search/models/concerns/account_search_spec.rb rename to spec/search/models/concerns/account/search_spec.rb index 65e1e4de1..d8d7f355d 100644 --- a/spec/search/models/concerns/account_search_spec.rb +++ b/spec/search/models/concerns/account/search_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe AccountSearch do +describe Account::Search do describe 'a non-discoverable account becoming discoverable' do let(:account) { Account.find_by(username: 'search_test_account_1') } diff --git a/spec/search/models/concerns/account_statuses_search_spec.rb b/spec/search/models/concerns/account/statuses_search_spec.rb similarity index 98% rename from spec/search/models/concerns/account_statuses_search_spec.rb rename to spec/search/models/concerns/account/statuses_search_spec.rb index d35cfa563..bf2606eec 100644 --- a/spec/search/models/concerns/account_statuses_search_spec.rb +++ b/spec/search/models/concerns/account/statuses_search_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe AccountStatusesSearch do +describe Account::StatusesSearch do describe 'a non-indexable account becoming indexable' do let(:account) { Account.find_by(username: 'search_test_account_1') } From 272592d16d40e804ec325ef3b5e6de9bbad5f2dd Mon Sep 17 00:00:00 2001 From: Michael Stanclift <mx@vmstan.com> Date: Fri, 1 Dec 2023 05:06:37 -0600 Subject: [PATCH 173/255] Change startup command for Puma in Docker Compose (#28138) --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index bcfa4c85f..93451d961 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -59,7 +59,7 @@ services: image: ghcr.io/mastodon/mastodon:v4.2.0 restart: always env_file: .env.production - command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000" + command: bundle exec puma -C config/puma.rb networks: - external_network - internal_network From 92fa9b109f78647710c52d86fa777ab3972e2f1b Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 06:56:47 -0500 Subject: [PATCH 174/255] Add spec coverage for media CLI usage command (#28167) --- spec/lib/mastodon/cli/media_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/lib/mastodon/cli/media_spec.rb b/spec/lib/mastodon/cli/media_spec.rb index 9543640e9..305d67d28 100644 --- a/spec/lib/mastodon/cli/media_spec.rb +++ b/spec/lib/mastodon/cli/media_spec.rb @@ -78,4 +78,16 @@ describe Mastodon::CLI::Media do end end end + + describe '#usage' do + context 'without options' do + let(:options) { {} } + + it 'reports about storage size' do + expect { cli.invoke(:usage, [], options) }.to output( + a_string_including('0 Bytes') + ).to_stdout + end + end + end end From 7753e5f715ba105a8ec3dd335e8af4a9448aee63 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 07:00:34 -0500 Subject: [PATCH 175/255] Add shared example for CLI command specs (#28165) --- spec/lib/mastodon/cli/accounts_spec.rb | 8 ++------ spec/lib/mastodon/cli/cache_spec.rb | 6 +----- spec/lib/mastodon/cli/canonical_email_blocks_spec.rb | 6 +----- spec/lib/mastodon/cli/domains_spec.rb | 6 +----- spec/lib/mastodon/cli/email_domain_blocks_spec.rb | 6 +----- spec/lib/mastodon/cli/emoji_spec.rb | 6 +----- spec/lib/mastodon/cli/feeds_spec.rb | 6 +----- spec/lib/mastodon/cli/ip_blocks_spec.rb | 6 +----- spec/lib/mastodon/cli/main_spec.rb | 6 +----- spec/lib/mastodon/cli/maintenance_spec.rb | 6 +----- spec/lib/mastodon/cli/media_spec.rb | 6 +----- spec/lib/mastodon/cli/preview_cards_spec.rb | 6 +----- spec/lib/mastodon/cli/search_spec.rb | 6 +----- spec/lib/mastodon/cli/settings_spec.rb | 6 +----- spec/lib/mastodon/cli/statuses_spec.rb | 6 +----- spec/lib/mastodon/cli/upgrade_spec.rb | 6 +----- spec/support/examples/cli.rb | 11 +++++++++++ 17 files changed, 28 insertions(+), 81 deletions(-) create mode 100644 spec/support/examples/cli.rb diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index 626cf4778..3216d0d1b 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -6,6 +6,8 @@ require 'mastodon/cli/accounts' describe Mastodon::CLI::Accounts do let(:cli) { described_class.new } + it_behaves_like 'CLI Command' + # `parallelize_with_progress` cannot run in transactions, so instead, # stub it with an alternative implementation that runs sequentially # and can run in transactions. @@ -24,12 +26,6 @@ describe Mastodon::CLI::Accounts do end end - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end - describe '#create' do shared_examples 'a new user with given email address and username' do it 'creates a new user with the specified email address' do diff --git a/spec/lib/mastodon/cli/cache_spec.rb b/spec/lib/mastodon/cli/cache_spec.rb index 3ab42dc8c..c1ce04710 100644 --- a/spec/lib/mastodon/cli/cache_spec.rb +++ b/spec/lib/mastodon/cli/cache_spec.rb @@ -6,11 +6,7 @@ require 'mastodon/cli/cache' describe Mastodon::CLI::Cache do let(:cli) { described_class.new } - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' describe '#clear' do before { allow(Rails.cache).to receive(:clear) } diff --git a/spec/lib/mastodon/cli/canonical_email_blocks_spec.rb b/spec/lib/mastodon/cli/canonical_email_blocks_spec.rb index eb57a3cd1..6e4675748 100644 --- a/spec/lib/mastodon/cli/canonical_email_blocks_spec.rb +++ b/spec/lib/mastodon/cli/canonical_email_blocks_spec.rb @@ -6,11 +6,7 @@ require 'mastodon/cli/canonical_email_blocks' describe Mastodon::CLI::CanonicalEmailBlocks do let(:cli) { described_class.new } - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' describe '#find' do let(:arguments) { ['user@example.com'] } diff --git a/spec/lib/mastodon/cli/domains_spec.rb b/spec/lib/mastodon/cli/domains_spec.rb index ea58845c0..765b63e2a 100644 --- a/spec/lib/mastodon/cli/domains_spec.rb +++ b/spec/lib/mastodon/cli/domains_spec.rb @@ -4,9 +4,5 @@ require 'rails_helper' require 'mastodon/cli/domains' describe Mastodon::CLI::Domains do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' end diff --git a/spec/lib/mastodon/cli/email_domain_blocks_spec.rb b/spec/lib/mastodon/cli/email_domain_blocks_spec.rb index 333ae3f2b..060943b18 100644 --- a/spec/lib/mastodon/cli/email_domain_blocks_spec.rb +++ b/spec/lib/mastodon/cli/email_domain_blocks_spec.rb @@ -4,9 +4,5 @@ require 'rails_helper' require 'mastodon/cli/email_domain_blocks' describe Mastodon::CLI::EmailDomainBlocks do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' end diff --git a/spec/lib/mastodon/cli/emoji_spec.rb b/spec/lib/mastodon/cli/emoji_spec.rb index 9b5865372..5d109eb52 100644 --- a/spec/lib/mastodon/cli/emoji_spec.rb +++ b/spec/lib/mastodon/cli/emoji_spec.rb @@ -4,9 +4,5 @@ require 'rails_helper' require 'mastodon/cli/emoji' describe Mastodon::CLI::Emoji do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' end diff --git a/spec/lib/mastodon/cli/feeds_spec.rb b/spec/lib/mastodon/cli/feeds_spec.rb index 030f08721..e16113c85 100644 --- a/spec/lib/mastodon/cli/feeds_spec.rb +++ b/spec/lib/mastodon/cli/feeds_spec.rb @@ -6,11 +6,7 @@ require 'mastodon/cli/feeds' describe Mastodon::CLI::Feeds do let(:cli) { described_class.new } - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' describe '#build' do before { Fabricate(:account) } diff --git a/spec/lib/mastodon/cli/ip_blocks_spec.rb b/spec/lib/mastodon/cli/ip_blocks_spec.rb index 030d9fcb1..684314dc7 100644 --- a/spec/lib/mastodon/cli/ip_blocks_spec.rb +++ b/spec/lib/mastodon/cli/ip_blocks_spec.rb @@ -6,11 +6,7 @@ require 'mastodon/cli/ip_blocks' describe Mastodon::CLI::IpBlocks do let(:cli) { described_class.new } - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' describe '#add' do let(:ip_list) do diff --git a/spec/lib/mastodon/cli/main_spec.rb b/spec/lib/mastodon/cli/main_spec.rb index e3709afe3..b5b5d6906 100644 --- a/spec/lib/mastodon/cli/main_spec.rb +++ b/spec/lib/mastodon/cli/main_spec.rb @@ -4,11 +4,7 @@ require 'rails_helper' require 'mastodon/cli/main' describe Mastodon::CLI::Main do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' describe 'version' do it 'returns the Mastodon version' do diff --git a/spec/lib/mastodon/cli/maintenance_spec.rb b/spec/lib/mastodon/cli/maintenance_spec.rb index a6789ea5a..95e695ab5 100644 --- a/spec/lib/mastodon/cli/maintenance_spec.rb +++ b/spec/lib/mastodon/cli/maintenance_spec.rb @@ -6,11 +6,7 @@ require 'mastodon/cli/maintenance' describe Mastodon::CLI::Maintenance do let(:cli) { described_class.new } - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' describe '#fix_duplicates' do context 'when the database version is too old' do diff --git a/spec/lib/mastodon/cli/media_spec.rb b/spec/lib/mastodon/cli/media_spec.rb index 305d67d28..15f84c14b 100644 --- a/spec/lib/mastodon/cli/media_spec.rb +++ b/spec/lib/mastodon/cli/media_spec.rb @@ -6,11 +6,7 @@ require 'mastodon/cli/media' describe Mastodon::CLI::Media do let(:cli) { described_class.new } - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' describe '#remove' do context 'with --prune-profiles and --remove-headers' do diff --git a/spec/lib/mastodon/cli/preview_cards_spec.rb b/spec/lib/mastodon/cli/preview_cards_spec.rb index 1e064ed58..a766d250e 100644 --- a/spec/lib/mastodon/cli/preview_cards_spec.rb +++ b/spec/lib/mastodon/cli/preview_cards_spec.rb @@ -6,11 +6,7 @@ require 'mastodon/cli/preview_cards' describe Mastodon::CLI::PreviewCards do let(:cli) { described_class.new } - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' describe '#remove' do context 'with relevant preview cards' do diff --git a/spec/lib/mastodon/cli/search_spec.rb b/spec/lib/mastodon/cli/search_spec.rb index d5cae5bf4..785dc2bd6 100644 --- a/spec/lib/mastodon/cli/search_spec.rb +++ b/spec/lib/mastodon/cli/search_spec.rb @@ -4,9 +4,5 @@ require 'rails_helper' require 'mastodon/cli/search' describe Mastodon::CLI::Search do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' end diff --git a/spec/lib/mastodon/cli/settings_spec.rb b/spec/lib/mastodon/cli/settings_spec.rb index ae58e74e5..7dcd1110b 100644 --- a/spec/lib/mastodon/cli/settings_spec.rb +++ b/spec/lib/mastodon/cli/settings_spec.rb @@ -4,11 +4,7 @@ require 'rails_helper' require 'mastodon/cli/settings' describe Mastodon::CLI::Settings do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' describe 'subcommand "registrations"' do let(:cli) { Mastodon::CLI::Registrations.new } diff --git a/spec/lib/mastodon/cli/statuses_spec.rb b/spec/lib/mastodon/cli/statuses_spec.rb index 38ebcd993..70e4e2c08 100644 --- a/spec/lib/mastodon/cli/statuses_spec.rb +++ b/spec/lib/mastodon/cli/statuses_spec.rb @@ -6,11 +6,7 @@ require 'mastodon/cli/statuses' describe Mastodon::CLI::Statuses do let(:cli) { described_class.new } - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' describe '#remove', use_transactional_tests: false do context 'with small batch size' do diff --git a/spec/lib/mastodon/cli/upgrade_spec.rb b/spec/lib/mastodon/cli/upgrade_spec.rb index 9e0ab9d06..817044f7e 100644 --- a/spec/lib/mastodon/cli/upgrade_spec.rb +++ b/spec/lib/mastodon/cli/upgrade_spec.rb @@ -4,9 +4,5 @@ require 'rails_helper' require 'mastodon/cli/upgrade' describe Mastodon::CLI::Upgrade do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end + it_behaves_like 'CLI Command' end diff --git a/spec/support/examples/cli.rb b/spec/support/examples/cli.rb new file mode 100644 index 000000000..091c842bd --- /dev/null +++ b/spec/support/examples/cli.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +shared_examples 'CLI Command' do + it 'configures Thor to exit on failure' do + expect(described_class.exit_on_failure?).to be true + end + + it 'descends from the CLI base class' do + expect(described_class.new).to be_a(Mastodon::CLI::Base) + end +end From 1564799952ec4b8039eecb28125493814bd56ed0 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 09:18:45 -0500 Subject: [PATCH 176/255] Add spec coverage for media CLI `refresh` command (#28166) --- lib/mastodon/cli/media.rb | 1 + spec/lib/mastodon/cli/media_spec.rb | 73 +++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/lib/mastodon/cli/media.rb b/lib/mastodon/cli/media.rb index c90616177..c3275b799 100644 --- a/lib/mastodon/cli/media.rb +++ b/lib/mastodon/cli/media.rb @@ -265,6 +265,7 @@ module Mastodon::CLI elsif options[:days].present? scope = MediaAttachment.remote else + say('Specify the source of media attachments', :red) exit(1) end diff --git a/spec/lib/mastodon/cli/media_spec.rb b/spec/lib/mastodon/cli/media_spec.rb index 15f84c14b..6d510c1f5 100644 --- a/spec/lib/mastodon/cli/media_spec.rb +++ b/spec/lib/mastodon/cli/media_spec.rb @@ -86,4 +86,77 @@ describe Mastodon::CLI::Media do end end end + + describe '#refresh' do + context 'without any options' do + let(:options) { {} } + + it 'warns about usage and exits' do + expect { cli.invoke(:refresh, [], options) }.to output( + a_string_including('Specify the source') + ).to_stdout.and raise_error(SystemExit) + end + end + + context 'with --status option' do + before do + media_attachment.update(file_file_name: nil) + end + + let(:media_attachment) { Fabricate(:media_attachment, status: status, remote_url: 'https://host.example/asset.jpg') } + let(:options) { { status: status.id } } + let(:status) { Fabricate(:status) } + + it 'redownloads the attachment file' do + expect { cli.invoke(:refresh, [], options) }.to output( + a_string_including('Downloaded 1 media') + ).to_stdout + end + end + + context 'with --account option' do + context 'when the account does not exist' do + let(:options) { { account: 'not-real-user@example.host' } } + + it 'warns about usage and exits' do + expect { cli.invoke(:refresh, [], options) }.to output( + a_string_including('No such account') + ).to_stdout.and raise_error(SystemExit) + end + end + + context 'when the account exists' do + before do + media_attachment.update(file_file_name: nil) + end + + let(:media_attachment) { Fabricate(:media_attachment, account: account) } + let(:options) { { account: account.acct } } + let(:account) { Fabricate(:account) } + + it 'redownloads the attachment file' do + expect { cli.invoke(:refresh, [], options) }.to output( + a_string_including('Downloaded 1 media') + ).to_stdout + end + end + end + + context 'with --domain option' do + before do + media_attachment.update(file_file_name: nil) + end + + let(:domain) { 'example.host' } + let(:media_attachment) { Fabricate(:media_attachment, account: account) } + let(:options) { { domain: domain } } + let(:account) { Fabricate(:account, domain: domain) } + + it 'redownloads the attachment file' do + expect { cli.invoke(:refresh, [], options) }.to output( + a_string_including('Downloaded 1 media') + ).to_stdout + end + end + end end From f70f39dd04886c2ced6d424cdcb8690fcddd52f7 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 10:52:47 -0500 Subject: [PATCH 177/255] Add explicit `dependent: nil` to associations (#28169) --- .rubocop_todo.yml | 14 -------------- app/models/concerns/account/counters.rb | 2 +- app/models/conversation.rb | 2 +- app/models/custom_emoji.rb | 2 +- app/models/custom_emoji_category.rb | 2 +- app/models/domain_block.rb | 2 +- app/models/invite.rb | 2 +- app/models/status.rb | 14 +++++++++----- app/models/user.rb | 8 ++++---- app/models/web/push_subscription.rb | 2 +- 10 files changed, 20 insertions(+), 30 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 9fb163ceb..03543c8e0 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -112,20 +112,6 @@ Rails/HasAndBelongsToMany: - 'app/models/status.rb' - 'app/models/tag.rb' -# Configuration parameters: Include. -# Include: app/models/**/*.rb -Rails/HasManyOrHasOneDependent: - Exclude: - - 'app/models/concerns/account/counters.rb' - - 'app/models/conversation.rb' - - 'app/models/custom_emoji.rb' - - 'app/models/custom_emoji_category.rb' - - 'app/models/domain_block.rb' - - 'app/models/invite.rb' - - 'app/models/status.rb' - - 'app/models/user.rb' - - 'app/models/web/push_subscription.rb' - # Configuration parameters: Include. # Include: app/controllers/**/*.rb, app/mailers/**/*.rb Rails/LexicallyScopedActionFilter: diff --git a/app/models/concerns/account/counters.rb b/app/models/concerns/account/counters.rb index fb69be9b7..448839812 100644 --- a/app/models/concerns/account/counters.rb +++ b/app/models/concerns/account/counters.rb @@ -6,7 +6,7 @@ module Account::Counters ALLOWED_COUNTER_KEYS = %i(statuses_count following_count followers_count).freeze included do - has_one :account_stat, inverse_of: :account + has_one :account_stat, inverse_of: :account, dependent: nil after_save :save_account_stat end diff --git a/app/models/conversation.rb b/app/models/conversation.rb index 5de259962..a7fe14884 100644 --- a/app/models/conversation.rb +++ b/app/models/conversation.rb @@ -13,7 +13,7 @@ class Conversation < ApplicationRecord validates :uri, uniqueness: true, if: :uri? - has_many :statuses + has_many :statuses, dependent: nil def local? uri.nil? diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index 717de2772..97b1c63bf 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -37,7 +37,7 @@ class CustomEmoji < ApplicationRecord belongs_to :category, class_name: 'CustomEmojiCategory', optional: true - has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode, inverse_of: false + has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode, inverse_of: false, dependent: nil has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' } }, validate_media_type: false diff --git a/app/models/custom_emoji_category.rb b/app/models/custom_emoji_category.rb index 3c87f2b2e..f48074651 100644 --- a/app/models/custom_emoji_category.rb +++ b/app/models/custom_emoji_category.rb @@ -11,7 +11,7 @@ # class CustomEmojiCategory < ApplicationRecord - has_many :emojis, class_name: 'CustomEmoji', foreign_key: 'category_id', inverse_of: :category + has_many :emojis, class_name: 'CustomEmoji', foreign_key: 'category_id', inverse_of: :category, dependent: nil validates :name, presence: true, uniqueness: true end diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb index a7af2d62e..ff23f8fcc 100644 --- a/app/models/domain_block.rb +++ b/app/models/domain_block.rb @@ -25,7 +25,7 @@ class DomainBlock < ApplicationRecord validates :domain, presence: true, uniqueness: true, domain: true - has_many :accounts, foreign_key: :domain, primary_key: :domain, inverse_of: false + has_many :accounts, foreign_key: :domain, primary_key: :domain, inverse_of: false, dependent: nil delegate :count, to: :accounts, prefix: true scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } diff --git a/app/models/invite.rb b/app/models/invite.rb index 8e816cef0..c0cbc5845 100644 --- a/app/models/invite.rb +++ b/app/models/invite.rb @@ -20,7 +20,7 @@ class Invite < ApplicationRecord include Expireable belongs_to :user, inverse_of: :invites - has_many :users, inverse_of: :invite + has_many :users, inverse_of: :invite, dependent: nil scope :available, -> { where(expires_at: nil).or(where('expires_at >= ?', Time.now.utc)) } diff --git a/app/models/status.rb b/app/models/status.rb index 7b1ca69c7..eb7159dc6 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -66,12 +66,14 @@ class Status < ApplicationRecord has_many :bookmarks, inverse_of: :status, dependent: :destroy has_many :reblogs, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblog, dependent: :destroy has_many :reblogged_by_accounts, through: :reblogs, class_name: 'Account', source: :account - has_many :replies, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :thread + has_many :replies, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :thread, dependent: nil has_many :mentions, dependent: :destroy, inverse_of: :status has_many :mentioned_accounts, through: :mentions, source: :account, class_name: 'Account' - has_many :active_mentions, -> { active }, class_name: 'Mention', inverse_of: :status has_many :media_attachments, dependent: :nullify + # The `dependent` option is enabled by the initial `mentions` association declaration + has_many :active_mentions, -> { active }, class_name: 'Mention', inverse_of: :status # rubocop:disable Rails/HasManyOrHasOneDependent + # Those associations are used for the private search index has_many :local_mentioned, -> { merge(Account.local) }, through: :active_mentions, source: :account has_many :local_favorited, -> { merge(Account.local) }, through: :favourites, source: :account @@ -80,11 +82,13 @@ class Status < ApplicationRecord has_and_belongs_to_many :tags - has_one :preview_cards_status, inverse_of: :status # Because of a composite primary key, the dependent option cannot be used + # Because of a composite primary key, the `dependent` option cannot be used on this association + has_one :preview_cards_status, inverse_of: :status # rubocop:disable Rails/HasManyOrHasOneDependent + has_one :notification, as: :activity, dependent: :destroy - has_one :status_stat, inverse_of: :status + has_one :status_stat, inverse_of: :status, dependent: nil has_one :poll, inverse_of: :status, dependent: :destroy - has_one :trend, class_name: 'StatusTrend', inverse_of: :status + has_one :trend, class_name: 'StatusTrend', inverse_of: :status, dependent: nil validates :uri, uniqueness: true, presence: true, unless: :local? validates :text, presence: true, unless: -> { with_media? || reblog? } diff --git a/app/models/user.rb b/app/models/user.rb index 550f8bfd3..a1574c02a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -84,12 +84,12 @@ class User < ApplicationRecord belongs_to :role, class_name: 'UserRole', optional: true accepts_nested_attributes_for :account - has_many :applications, class_name: 'Doorkeeper::Application', as: :owner - has_many :backups, inverse_of: :user - has_many :invites, inverse_of: :user + has_many :applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: nil + has_many :backups, inverse_of: :user, dependent: nil + has_many :invites, inverse_of: :user, dependent: nil has_many :markers, inverse_of: :user, dependent: :destroy has_many :webauthn_credentials, dependent: :destroy - has_many :ips, class_name: 'UserIp', inverse_of: :user + has_many :ips, class_name: 'UserIp', inverse_of: :user, dependent: nil has_one :invite_request, class_name: 'UserInviteRequest', inverse_of: :user, dependent: :destroy accepts_nested_attributes_for :invite_request, reject_if: ->(attributes) { attributes['text'].blank? && !Setting.require_invite_text } diff --git a/app/models/web/push_subscription.rb b/app/models/web/push_subscription.rb index 0ffbe068e..a3a2ec3f0 100644 --- a/app/models/web/push_subscription.rb +++ b/app/models/web/push_subscription.rb @@ -19,7 +19,7 @@ class Web::PushSubscription < ApplicationRecord belongs_to :user, optional: true belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', optional: true - has_one :session_activation, foreign_key: 'web_push_subscription_id', inverse_of: :web_push_subscription + has_one :session_activation, foreign_key: 'web_push_subscription_id', inverse_of: :web_push_subscription, dependent: nil validates :endpoint, presence: true validates :key_p256dh, presence: true From a98fccf84e9deed1ea1aa52b5adbc0c1f0bdfaab Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 10:52:52 -0500 Subject: [PATCH 178/255] Fix `Style/SelfAssignment` cop (#28171) --- lib/mastodon/snowflake.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mastodon/snowflake.rb b/lib/mastodon/snowflake.rb index 0a596b294..ec4f6140c 100644 --- a/lib/mastodon/snowflake.rb +++ b/lib/mastodon/snowflake.rb @@ -99,7 +99,7 @@ module Mastodon::Snowflake def id_at(timestamp, with_random: true) id = timestamp.to_i * 1000 id += rand(1000) if with_random - id = id << 16 + id <<= 16 id += rand(2**16) if with_random id end From d83d01eb1e2f2ae56cd3f3a40e254fcfec51360c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 10:52:56 -0500 Subject: [PATCH 179/255] Fix `Lint/RedundantSafeNavigation` cop (#28172) --- app/controllers/api/v1/accounts_controller.rb | 2 +- app/models/trends/history.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index 653529316..be251b425 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -49,7 +49,7 @@ class Api::V1::AccountsController < Api::BaseController end def mute - MuteService.new.call(current_user.account, @account, notifications: truthy_param?(:notifications), duration: (params[:duration]&.to_i || 0)) + MuteService.new.call(current_user.account, @account, notifications: truthy_param?(:notifications), duration: params[:duration].to_i) render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships end diff --git a/app/models/trends/history.rb b/app/models/trends/history.rb index db3689933..21331f00d 100644 --- a/app/models/trends/history.rb +++ b/app/models/trends/history.rb @@ -37,7 +37,7 @@ class Trends::History end def uses - with_redis { |redis| redis.get(key_for(:uses))&.to_i || 0 } + with_redis { |redis| redis.get(key_for(:uses)).to_i } end def add(account_id) From aa8563d43df93647db50e52eddccba63500e0c88 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 10:53:15 -0500 Subject: [PATCH 180/255] Fix `Style/SuperWithArgsParentheses` cop (#28174) --- spec/support/signed_request_helpers.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/support/signed_request_helpers.rb b/spec/support/signed_request_helpers.rb index 33d7dba6b..eba4095e4 100644 --- a/spec/support/signed_request_helpers.rb +++ b/spec/support/signed_request_helpers.rb @@ -2,7 +2,7 @@ module SignedRequestHelpers def get(path, headers: nil, sign_with: nil, **args) - return super path, headers: headers, **args if sign_with.nil? + return super(path, headers: headers, **args) if sign_with.nil? headers ||= {} headers['Date'] = Time.now.utc.httpdate @@ -16,6 +16,6 @@ module SignedRequestHelpers headers['Signature'] = "keyId=\"#{key_id}\",algorithm=\"rsa-sha256\",headers=\"#{signed_headers.keys.join(' ').downcase}\",signature=\"#{signature}\"" - super path, headers: headers, **args + super(path, headers: headers, **args) end end From 5631f139c1f6f923923a82f8c55d5ab0820a2788 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 10:53:35 -0500 Subject: [PATCH 181/255] Fix `Lint/SymbolConversion` cop (#28175) --- app/models/concerns/remotable.rb | 2 +- app/models/user_settings/setting.rb | 2 +- config/deploy.rb | 2 +- spec/models/concerns/remotable_spec.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/concerns/remotable.rb b/app/models/concerns/remotable.rb index cb8f46e68..bd8b6f4eb 100644 --- a/app/models/concerns/remotable.rb +++ b/app/models/concerns/remotable.rb @@ -5,7 +5,7 @@ module Remotable class_methods do def remotable_attachment(attachment_name, limit, suppress_errors: true, download_on_assign: true, attribute_name: nil) - attribute_name ||= "#{attachment_name}_remote_url".to_sym + attribute_name ||= :"#{attachment_name}_remote_url" define_method("download_#{attachment_name}!") do |url = nil| url ||= self[attribute_name] diff --git a/app/models/user_settings/setting.rb b/app/models/user_settings/setting.rb index 9c1701744..1ab6cbeab 100644 --- a/app/models/user_settings/setting.rb +++ b/app/models/user_settings/setting.rb @@ -62,7 +62,7 @@ class UserSettings::Setting def key if namespace - "#{namespace}.#{name}".to_sym + :"#{namespace}.#{name}" else name end diff --git a/config/deploy.rb b/config/deploy.rb index b19567a72..75bfcc26f 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -20,7 +20,7 @@ namespace :systemd do SYSTEMD_SERVICES.each do |service| SERVICE_ACTIONS.each do |action| desc "Perform a #{action} on #{service} service" - task "#{service}:#{action}".to_sym do + task :"#{service}:#{action}" do on roles(:app) do # runs e.g. "sudo restart mastodon-sidekiq.service" sudo :systemctl, action, "#{fetch(:application)}-#{service}.service" diff --git a/spec/models/concerns/remotable_spec.rb b/spec/models/concerns/remotable_spec.rb index db690da3c..9f6aeb7fb 100644 --- a/spec/models/concerns/remotable_spec.rb +++ b/spec/models/concerns/remotable_spec.rb @@ -31,7 +31,7 @@ RSpec.describe Remotable do end end - let(:attribute_name) { "#{hoge}_remote_url".to_sym } + let(:attribute_name) { :"#{hoge}_remote_url" } let(:code) { 200 } let(:file) { 'filename="foo.txt"' } let(:foo) { foo_class.new } From 3bc437b99a19bba26c0c637b18ce6c7410d5a606 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 11:00:44 -0500 Subject: [PATCH 182/255] Fix `Style/RedundantParentheses` cop (#28176) --- app/controllers/api/base_controller.rb | 2 +- app/lib/feed_manager.rb | 4 ++-- lib/mastodon/cli/media.rb | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index c81ba32b0..b3c60fcaf 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -64,7 +64,7 @@ class Api::BaseController < ApplicationController end def doorkeeper_unauthorized_render_options(error: nil) - { json: { error: (error.try(:description) || 'Not authorized') } } + { json: { error: error.try(:description) || 'Not authorized' } } end def doorkeeper_forbidden_render_options(*) diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 4e645a11f..53767486f 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -420,8 +420,8 @@ class FeedManager check_for_blocks = status.active_mentions.pluck(:account_id) check_for_blocks.push(status.in_reply_to_account) if status.reply? && !status.in_reply_to_account_id.nil? - should_filter = blocks_or_mutes?(receiver_id, check_for_blocks, :mentions) # Filter if it's from someone I blocked, in reply to someone I blocked, or mentioning someone I blocked (or muted) - should_filter ||= (status.account.silenced? && !Follow.where(account_id: receiver_id, target_account_id: status.account_id).exists?) # of if the account is silenced and I'm not following them + should_filter = blocks_or_mutes?(receiver_id, check_for_blocks, :mentions) # Filter if it's from someone I blocked, in reply to someone I blocked, or mentioning someone I blocked (or muted) + should_filter ||= status.account.silenced? && !Follow.where(account_id: receiver_id, target_account_id: status.account_id).exists? # of if the account is silenced and I'm not following them should_filter end diff --git a/lib/mastodon/cli/media.rb b/lib/mastodon/cli/media.rb index c3275b799..a796bb729 100644 --- a/lib/mastodon/cli/media.rb +++ b/lib/mastodon/cli/media.rb @@ -48,8 +48,8 @@ module Mastodon::CLI next if account.avatar.blank? && account.header.blank? next if options[:remove_headers] && account.header.blank? - size = (account.header_file_size || 0) - size += (account.avatar_file_size || 0) if options[:prune_profiles] + size = account.header_file_size || 0 + size += account.avatar_file_size || 0 if options[:prune_profiles] unless dry_run? account.header.destroy From 469ee2ae36d0c4b355fd5486c294133be75288a0 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 1 Dec 2023 11:07:19 -0500 Subject: [PATCH 183/255] Fix `Style/HashEachMethods` cop (#28173) --- db/seeds/03_roles.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/seeds/03_roles.rb b/db/seeds/03_roles.rb index 8b359582b..95a989a95 100644 --- a/db/seeds/03_roles.rb +++ b/db/seeds/03_roles.rb @@ -6,6 +6,6 @@ UserRole.everyone # Create default roles defined in config file default_roles = YAML.load_file(Rails.root.join('config', 'roles.yml')) -default_roles.each do |_, config| +default_roles.each_value do |config| UserRole.create_with(position: config['position'], permissions_as_keys: config['permissions'], highlighted: true).find_or_create_by(name: config['name']) end From 456597dae5251af841e46ab0608e0d44a7de1197 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 17:22:15 +0100 Subject: [PATCH 184/255] Update dependency doorkeeper to v5.6.8 (#28177) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 40f85c7d4..4c78e6b0a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -245,7 +245,7 @@ GEM docile (1.4.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - doorkeeper (5.6.7) + doorkeeper (5.6.8) railties (>= 5) dotenv (2.8.1) dotenv-rails (2.8.1) @@ -617,7 +617,7 @@ GEM redlock (1.3.2) redis (>= 3.0.0, < 6.0) regexp_parser (2.8.2) - reline (0.4.0) + reline (0.4.1) io-console (~> 0.5) request_store (1.5.1) rack (>= 1.4) From 0ca7a50e96f8ff596de7432462a5e92a98de5e38 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 09:50:28 +0100 Subject: [PATCH 185/255] Update devDependencies (non-major) (#28200) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 142 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 102 insertions(+), 40 deletions(-) diff --git a/yarn.lock b/yarn.lock index ad792d26c..3ec023533 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2893,8 +2893,8 @@ __metadata: linkType: hard "@testing-library/jest-dom@npm:^6.0.0": - version: 6.1.4 - resolution: "@testing-library/jest-dom@npm:6.1.4" + version: 6.1.5 + resolution: "@testing-library/jest-dom@npm:6.1.5" dependencies: "@adobe/css-tools": "npm:^4.3.1" "@babel/runtime": "npm:^7.9.2" @@ -2918,7 +2918,7 @@ __metadata: optional: true vitest: optional: true - checksum: 2e23f120613fd8ae6d5169bbc94f1a2e4c82b07182057dc94db8ec54ebf32555833442e6c43a187e59715d83704ffb5df49ba88a71f6f32d2683f3d95ba721c7 + checksum: f3643a56fcd970b5c7e8fd10faf3c4817d8ab0e74fb1198d726643bdc5ac675ceaac3b0068c5b4fbad254470e8f98ed50028741de875a29ceaa2f854570979c9 languageName: node linkType: hard @@ -4168,12 +4168,12 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^5.0.0": - version: 5.0.0 - resolution: "ansi-escapes@npm:5.0.0" +"ansi-escapes@npm:^6.2.0": + version: 6.2.0 + resolution: "ansi-escapes@npm:6.2.0" dependencies: - type-fest: "npm:^1.0.2" - checksum: f705cc7fbabb981ddf51562cd950792807bccd7260cc3d9478a619dda62bff6634c87ca100f2545ac7aade9b72652c4edad8c7f0d31a0b949b5fa58f33eaf0d0 + type-fest: "npm:^3.0.0" + checksum: 3eec75deedd8b10192c5f98e4cd9715cc3ff268d33fc463c24b7d22446668bfcd4ad1803993ea89c0f51f88b5a3399572bacb7c8cb1a067fc86e189c5f3b0c7e languageName: node linkType: hard @@ -4239,7 +4239,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0": +"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0, ansi-styles@npm:^6.2.1": version: 6.2.1 resolution: "ansi-styles@npm:6.2.1" checksum: 5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c @@ -5584,13 +5584,13 @@ __metadata: languageName: node linkType: hard -"cli-truncate@npm:^3.1.0": - version: 3.1.0 - resolution: "cli-truncate@npm:3.1.0" +"cli-truncate@npm:^4.0.0": + version: 4.0.0 + resolution: "cli-truncate@npm:4.0.0" dependencies: slice-ansi: "npm:^5.0.0" - string-width: "npm:^5.0.0" - checksum: a19088878409ec0e5dc2659a5166929629d93cfba6d68afc9cde2282fd4c751af5b555bf197047e31c87c574396348d011b7aa806fec29c4139ea4f7f00b324c + string-width: "npm:^7.0.0" + checksum: d7f0b73e3d9b88cb496e6c086df7410b541b56a43d18ade6a573c9c18bd001b1c3fba1ad578f741a4218fdc794d042385f8ac02c25e1c295a2d8b9f3cb86eb4c languageName: node linkType: hard @@ -6997,7 +6997,7 @@ __metadata: languageName: node linkType: hard -"emoji-regex@npm:10.3.0, emoji-regex@npm:^10.2.1": +"emoji-regex@npm:10.3.0, emoji-regex@npm:^10.2.1, emoji-regex@npm:^10.3.0": version: 10.3.0 resolution: "emoji-regex@npm:10.3.0" checksum: b4838e8dcdceb44cf47f59abe352c25ff4fe7857acaf5fb51097c427f6f75b44d052eb907a7a3b86f86bc4eae3a93f5c2b7460abe79c407307e6212d65c91163 @@ -8387,6 +8387,13 @@ __metadata: languageName: node linkType: hard +"get-east-asian-width@npm:^1.0.0": + version: 1.2.0 + resolution: "get-east-asian-width@npm:1.2.0" + checksum: 914b1e217cf38436c24b4c60b4c45289e39a45bf9e65ef9fd343c2815a1a02b8a0215aeec8bf9c07c516089004b6e3826332481f40a09529fcadbf6e579f286b + languageName: node + linkType: hard + "get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2": version: 1.2.2 resolution: "get-intrinsic@npm:1.2.2" @@ -9610,6 +9617,15 @@ __metadata: languageName: node linkType: hard +"is-fullwidth-code-point@npm:^5.0.0": + version: 5.0.0 + resolution: "is-fullwidth-code-point@npm:5.0.0" + dependencies: + get-east-asian-width: "npm:^1.0.0" + checksum: cd591b27d43d76b05fa65ed03eddce57a16e1eca0b7797ff7255de97019bcaf0219acfc0c4f7af13319e13541f2a53c0ace476f442b13267b9a6a7568f2b65c8 + languageName: node + linkType: hard + "is-generator-fn@npm:^2.0.0": version: 2.1.0 resolution: "is-generator-fn@npm:2.1.0" @@ -10892,7 +10908,14 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:2.1.0, lilconfig@npm:^2.1.0": +"lilconfig@npm:3.0.0": + version: 3.0.0 + resolution: "lilconfig@npm:3.0.0" + checksum: 7f5ee7a658dc016cacf146815e8d88b06f06f4402823b8b0934e305a57a197f55ccc9c5cd4fb5ea1b2b821c8ccaf2d54abd59602a4931af06eabda332388d3e6 + languageName: node + linkType: hard + +"lilconfig@npm:^2.1.0": version: 2.1.0 resolution: "lilconfig@npm:2.1.0" checksum: 64645641aa8d274c99338e130554abd6a0190533c0d9eb2ce7ebfaf2e05c7d9961f3ffe2bfa39efd3b60c521ba3dd24fa236fe2775fc38501bf82bf49d4678b8 @@ -10907,36 +10930,36 @@ __metadata: linkType: hard "lint-staged@npm:^15.0.0": - version: 15.1.0 - resolution: "lint-staged@npm:15.1.0" + version: 15.2.0 + resolution: "lint-staged@npm:15.2.0" dependencies: chalk: "npm:5.3.0" commander: "npm:11.1.0" debug: "npm:4.3.4" execa: "npm:8.0.1" - lilconfig: "npm:2.1.0" - listr2: "npm:7.0.2" + lilconfig: "npm:3.0.0" + listr2: "npm:8.0.0" micromatch: "npm:4.0.5" pidtree: "npm:0.6.0" string-argv: "npm:0.3.2" yaml: "npm:2.3.4" bin: lint-staged: bin/lint-staged.js - checksum: d427408be98df7558e918593cb765d5caaa67a5cdca89671fb54280a6c959f4e448db36d4f85e8e0bd9c2c1e996aa133916925cf47c9df573b47308d5e298d84 + checksum: 4a1ff25dd06dbd4346fd244c9a0ebb936532ba18c0caedeb895c2e232f3c6c5fd08f6667624716660bc29e3e0f9f0440a9175114394616e991ebd5fab4b1f092 languageName: node linkType: hard -"listr2@npm:7.0.2": - version: 7.0.2 - resolution: "listr2@npm:7.0.2" +"listr2@npm:8.0.0": + version: 8.0.0 + resolution: "listr2@npm:8.0.0" dependencies: - cli-truncate: "npm:^3.1.0" + cli-truncate: "npm:^4.0.0" colorette: "npm:^2.0.20" eventemitter3: "npm:^5.0.1" - log-update: "npm:^5.0.1" + log-update: "npm:^6.0.0" rfdc: "npm:^1.3.0" - wrap-ansi: "npm:^8.1.0" - checksum: 37b6501be84ebea66dcce07c5f86c224aff0c01c9fb43f5055cc38a063030281d58198aad0aad481f174438309831ddf5f763b890e820cd7b7b4f4a5dfa229c9 + wrap-ansi: "npm:^9.0.0" + checksum: 6e356df9127c68b69186c927c993645223557e941a76b0bb210e35786aedc53f577df437251db804606ff37ac509c5d945289a84b3daee7fadf2e3dcb889ecc9 languageName: node linkType: hard @@ -11104,16 +11127,16 @@ __metadata: languageName: node linkType: hard -"log-update@npm:^5.0.1": - version: 5.0.1 - resolution: "log-update@npm:5.0.1" +"log-update@npm:^6.0.0": + version: 6.0.0 + resolution: "log-update@npm:6.0.0" dependencies: - ansi-escapes: "npm:^5.0.0" + ansi-escapes: "npm:^6.2.0" cli-cursor: "npm:^4.0.0" - slice-ansi: "npm:^5.0.0" - strip-ansi: "npm:^7.0.1" - wrap-ansi: "npm:^8.0.1" - checksum: 1050ea2027e80f32e132aace909987cb00c2719368c78b82ffca681a5b3f4020eeb5f4b4e310c47c35c6c36aff258c1d1bc51485ac44d6fdac9eb0a4275c539f + slice-ansi: "npm:^7.0.0" + strip-ansi: "npm:^7.1.0" + wrap-ansi: "npm:^9.0.0" + checksum: e0b3c3401ef49ce3eb17e2f83d644765e4f7988498fc1344eaa4f31ab30e510dcc469a7fb64dc01bd1c8d9237d917598fa677a9818705fb3774c10f6e9d4b27c languageName: node linkType: hard @@ -15050,6 +15073,16 @@ __metadata: languageName: node linkType: hard +"slice-ansi@npm:^7.0.0": + version: 7.1.0 + resolution: "slice-ansi@npm:7.1.0" + dependencies: + ansi-styles: "npm:^6.2.1" + is-fullwidth-code-point: "npm:^5.0.0" + checksum: 631c971d4abf56cf880f034d43fcc44ff883624867bf11ecbd538c47343911d734a4656d7bc02362b40b89d765652a7f935595441e519b59e2ad3f4d5d6fe7ca + languageName: node + linkType: hard + "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" @@ -15493,7 +15526,7 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^5.0.0, string-width@npm:^5.0.1, string-width@npm:^5.1.2": +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": version: 5.1.2 resolution: "string-width@npm:5.1.2" dependencies: @@ -15504,6 +15537,17 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^7.0.0": + version: 7.0.0 + resolution: "string-width@npm:7.0.0" + dependencies: + emoji-regex: "npm:^10.3.0" + get-east-asian-width: "npm:^1.0.0" + strip-ansi: "npm:^7.1.0" + checksum: 8ffaeeccf4a56ccce5b6235d0b99ee3a581e3e3e5d453708efe7aa8e264fa3a858b4fe2244310cb71c6a20d8c05921cedc8b2ccd88cbaad9f5c92051ff68edc6 + languageName: node + linkType: hard + "string.prototype.matchall@npm:^4.0.6, string.prototype.matchall@npm:^4.0.8": version: 4.0.8 resolution: "string.prototype.matchall@npm:4.0.8" @@ -15618,7 +15662,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^7.0.1": +"strip-ansi@npm:^7.0.1, strip-ansi@npm:^7.1.0": version: 7.1.0 resolution: "strip-ansi@npm:7.1.0" dependencies: @@ -16379,13 +16423,20 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^1.0.1, type-fest@npm:^1.0.2, type-fest@npm:^1.2.1, type-fest@npm:^1.2.2": +"type-fest@npm:^1.0.1, type-fest@npm:^1.2.1, type-fest@npm:^1.2.2": version: 1.4.0 resolution: "type-fest@npm:1.4.0" checksum: a3c0f4ee28ff6ddf800d769eafafcdeab32efa38763c1a1b8daeae681920f6e345d7920bf277245235561d8117dab765cb5f829c76b713b4c9de0998a5397141 languageName: node linkType: hard +"type-fest@npm:^3.0.0": + version: 3.13.1 + resolution: "type-fest@npm:3.13.1" + checksum: 547d22186f73a8c04590b70dcf63baff390078c75ea8acd366bbd510fd0646e348bd1970e47ecf795b7cff0b41d26e9c475c1fedd6ef5c45c82075fbf916b629 + languageName: node + linkType: hard + "type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" @@ -17613,7 +17664,7 @@ __metadata: languageName: node linkType: hard -"wrap-ansi@npm:^8.0.1, wrap-ansi@npm:^8.1.0": +"wrap-ansi@npm:^8.1.0": version: 8.1.0 resolution: "wrap-ansi@npm:8.1.0" dependencies: @@ -17624,6 +17675,17 @@ __metadata: languageName: node linkType: hard +"wrap-ansi@npm:^9.0.0": + version: 9.0.0 + resolution: "wrap-ansi@npm:9.0.0" + dependencies: + ansi-styles: "npm:^6.2.1" + string-width: "npm:^7.0.0" + strip-ansi: "npm:^7.1.0" + checksum: a139b818da9573677548dd463bd626a5a5286271211eb6e4e82f34a4f643191d74e6d4a9bb0a3c26ec90e6f904f679e0569674ac099ea12378a8b98e20706066 + languageName: node + linkType: hard + "wrappy@npm:1": version: 1.0.2 resolution: "wrappy@npm:1.0.2" From b4fef6c26fe63aeda60a6359a17a7f357b2c923e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 09:50:43 +0100 Subject: [PATCH 186/255] Update DefinitelyTyped types (non-major) (#28199) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3ec023533..288d75925 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3495,13 +3495,13 @@ __metadata: linkType: hard "@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7": - version: 18.2.38 - resolution: "@types/react@npm:18.2.38" + version: 18.2.41 + resolution: "@types/react@npm:18.2.41" dependencies: "@types/prop-types": "npm:*" "@types/scheduler": "npm:*" csstype: "npm:^3.0.2" - checksum: 56edd4756081b677e38ee23ad6d340658c5e2468785cb20968318cec357e1ea7ccf3ecd9534981741192dd1b894200acfaf0f1551b4795c6077668f6afc19345 + checksum: 5cc72491ce8be95e7bbedd8bf039ca971772ecd22d989feb045af7e73247c7e6cff25a2f1c2200be461fb2f6b5aacef739e1ba9fd83c744209dfd3ce8aa75afe languageName: node linkType: hard @@ -3657,11 +3657,11 @@ __metadata: linkType: hard "@types/ws@npm:^8.5.9": - version: 8.5.9 - resolution: "@types/ws@npm:8.5.9" + version: 8.5.10 + resolution: "@types/ws@npm:8.5.10" dependencies: "@types/node": "npm:*" - checksum: 678bdd6461c4653f2975c537fb673cb1918c331558e2d2422b69761c9ced67200bb07c664e2593f3864077a891cb7c13ef2a40d303b4aacb06173d095d8aa3ce + checksum: e9af279b984c4a04ab53295a40aa95c3e9685f04888df5c6920860d1dd073fcc57c7bd33578a04b285b2c655a0b52258d34bee0a20569dca8defb8393e1e5d29 languageName: node linkType: hard From 3ec263bf155c87dd5c513f181682e051e9f3e105 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 09:51:08 +0100 Subject: [PATCH 187/255] Update dependency irb to v1.10.0 (#28198) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4c78e6b0a..6820c12f9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -377,7 +377,7 @@ GEM terminal-table (>= 1.5.1) idn-ruby (0.1.5) io-console (0.6.0) - irb (1.9.1) + irb (1.10.0) rdoc reline (>= 0.3.8) jmespath (1.6.2) @@ -747,7 +747,7 @@ GEM statsd-ruby (1.5.0) stoplight (3.0.2) redlock (~> 1.0) - stringio (3.0.9) + stringio (3.1.0) strong_migrations (1.6.4) activerecord (>= 5.2) swd (1.3.0) From d848d8d87cbef49f5f4635b3378b582464bae98a Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 4 Dec 2023 03:52:21 -0500 Subject: [PATCH 188/255] Add helper methods for domains allow and export blocks files (#28196) --- .../admin/export_domain_allows_controller_spec.rb | 10 ++++++++-- .../admin/export_domain_blocks_controller_spec.rb | 8 +++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/spec/controllers/admin/export_domain_allows_controller_spec.rb b/spec/controllers/admin/export_domain_allows_controller_spec.rb index e1e5ecc1f..0a2e34262 100644 --- a/spec/controllers/admin/export_domain_allows_controller_spec.rb +++ b/spec/controllers/admin/export_domain_allows_controller_spec.rb @@ -24,7 +24,7 @@ RSpec.describe Admin::ExportDomainAllowsController do get :export, params: { format: :csv } expect(response).to have_http_status(200) - expect(response.body).to eq(File.read(File.join(file_fixture_path, 'domain_allows.csv'))) + expect(response.body).to eq(domain_allows_csv_file) end end @@ -40,7 +40,7 @@ RSpec.describe Admin::ExportDomainAllowsController do # Domains should now be added get :export, params: { format: :csv } expect(response).to have_http_status(200) - expect(response.body).to eq(File.read(File.join(file_fixture_path, 'domain_allows.csv'))) + expect(response.body).to eq(domain_allows_csv_file) end it 'displays error on no file selected' do @@ -49,4 +49,10 @@ RSpec.describe Admin::ExportDomainAllowsController do expect(flash[:error]).to eq(I18n.t('admin.export_domain_allows.no_file')) end end + + private + + def domain_allows_csv_file + File.read(File.join(file_fixture_path, 'domain_allows.csv')) + end end diff --git a/spec/controllers/admin/export_domain_blocks_controller_spec.rb b/spec/controllers/admin/export_domain_blocks_controller_spec.rb index 5a282c957..bfcccfa06 100644 --- a/spec/controllers/admin/export_domain_blocks_controller_spec.rb +++ b/spec/controllers/admin/export_domain_blocks_controller_spec.rb @@ -26,7 +26,13 @@ RSpec.describe Admin::ExportDomainBlocksController do get :export, params: { format: :csv } expect(response).to have_http_status(200) - expect(response.body).to eq(File.read(File.join(file_fixture_path, 'domain_blocks.csv'))) + expect(response.body).to eq(domain_blocks_csv_file) + end + + private + + def domain_blocks_csv_file + File.read(File.join(file_fixture_path, 'domain_blocks.csv')) end end From 154fb95e44da94d8473ecdc081cf8b9648f41a52 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 09:52:53 +0100 Subject: [PATCH 189/255] Update dependency postcss to v8.4.32 (#28185) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 288d75925..4226fcc0f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11784,12 +11784,12 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.6": - version: 3.3.6 - resolution: "nanoid@npm:3.3.6" +"nanoid@npm:^3.3.7": + version: 3.3.7 + resolution: "nanoid@npm:3.3.7" bin: nanoid: bin/nanoid.cjs - checksum: 606b355960d0fcbe3d27924c4c52ef7d47d3b57208808ece73279420d91469b01ec1dce10fae512b6d4a8c5a5432b352b228336a8b2202a6ea68e67fa348e2ee + checksum: e3fb661aa083454f40500473bb69eedb85dc160e763150b9a2c567c7e9ff560ce028a9f833123b618a6ea742e311138b591910e795614a629029e86e180660f3 languageName: node linkType: hard @@ -13218,13 +13218,13 @@ __metadata: linkType: hard "postcss@npm:^8.2.15, postcss@npm:^8.4.24, postcss@npm:^8.4.28": - version: 8.4.31 - resolution: "postcss@npm:8.4.31" + version: 8.4.32 + resolution: "postcss@npm:8.4.32" dependencies: - nanoid: "npm:^3.3.6" + nanoid: "npm:^3.3.7" picocolors: "npm:^1.0.0" source-map-js: "npm:^1.0.2" - checksum: 748b82e6e5fc34034dcf2ae88ea3d11fd09f69b6c50ecdd3b4a875cfc7cdca435c958b211e2cb52355422ab6fccb7d8f2f2923161d7a1b281029e4a913d59acf + checksum: 39308a9195fa34d4dbdd7b58a896cff0c7809f84f7a4ac1b95b68ca86c9138a395addff33075668ed3983d41b90aac05754c445237a9365eb1c3a5602ebd03ad languageName: node linkType: hard From 19ad51253d255c26ba71b0754c8b21197fcd0113 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 4 Dec 2023 04:02:40 -0500 Subject: [PATCH 190/255] Prevent triple-subject run in admin/domain_blocks spec (#28195) --- .../admin/domain_blocks_controller_spec.rb | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/spec/controllers/admin/domain_blocks_controller_spec.rb b/spec/controllers/admin/domain_blocks_controller_spec.rb index 13826be36..22960f531 100644 --- a/spec/controllers/admin/domain_blocks_controller_spec.rb +++ b/spec/controllers/admin/domain_blocks_controller_spec.rb @@ -192,16 +192,11 @@ RSpec.describe Admin::DomainBlocksController do let(:original_severity) { 'suspend' } let(:new_severity) { 'silence' } - it 'changes the block severity' do - expect { subject }.to change { domain_block.reload.severity }.from('suspend').to('silence') - end - - it 'undoes individual suspensions' do - expect { subject }.to change { remote_account.reload.suspended? }.from(true).to(false) - end - - it 'performs individual silences' do - expect { subject }.to change { remote_account.reload.silenced? }.from(false).to(true) + it 'changes the block severity, suspensions, and silences' do + expect { subject } + .to change_severity('suspend', 'silence') + .and change_suspended(true, false) + .and change_silenced(false, true) end end @@ -209,17 +204,26 @@ RSpec.describe Admin::DomainBlocksController do let(:original_severity) { 'silence' } let(:new_severity) { 'suspend' } - it 'changes the block severity' do - expect { subject }.to change { domain_block.reload.severity }.from('silence').to('suspend') + it 'changes the block severity, silences, and suspensions' do + expect { subject } + .to change_severity('silence', 'suspend') + .and change_silenced(true, false) + .and change_suspended(false, true) end + end - it 'undoes individual silences' do - expect { subject }.to change { remote_account.reload.silenced? }.from(true).to(false) - end + private - it 'performs individual suspends' do - expect { subject }.to change { remote_account.reload.suspended? }.from(false).to(true) - end + def change_severity(from, to) + change { domain_block.reload.severity }.from(from).to(to) + end + + def change_silenced(from, to) + change { remote_account.reload.silenced? }.from(from).to(to) + end + + def change_suspended(from, to) + change { remote_account.reload.suspended? }.from(from).to(to) end end From 1bf2230fd1a25a1f8c012e4ff70c08a0a48d88d3 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 4 Dec 2023 04:08:47 -0500 Subject: [PATCH 191/255] Add spec coverage for `CLI::Upgrade#storage_schema` command (#28180) --- spec/lib/mastodon/cli/upgrade_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/spec/lib/mastodon/cli/upgrade_spec.rb b/spec/lib/mastodon/cli/upgrade_spec.rb index 817044f7e..0d6494eee 100644 --- a/spec/lib/mastodon/cli/upgrade_spec.rb +++ b/spec/lib/mastodon/cli/upgrade_spec.rb @@ -4,5 +4,24 @@ require 'rails_helper' require 'mastodon/cli/upgrade' describe Mastodon::CLI::Upgrade do + let(:cli) { described_class.new } + it_behaves_like 'CLI Command' + + describe '#storage_schema' do + context 'with records that dont need upgrading' do + let(:options) { {} } + + before do + Fabricate(:account) + Fabricate(:media_attachment) + end + + it 'does not upgrade storage for the attachments' do + expect { cli.invoke(:storage_schema, [], options) }.to output( + a_string_including('Upgraded storage schema of 0 records') + ).to_stdout + end + end + end end From 9603198982fce7e064a4ec60ac36420173a91cd5 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 4 Dec 2023 04:09:05 -0500 Subject: [PATCH 192/255] Add spec coverage for `CLI::Domains#purge` command (#28179) --- spec/lib/mastodon/cli/domains_spec.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/spec/lib/mastodon/cli/domains_spec.rb b/spec/lib/mastodon/cli/domains_spec.rb index 765b63e2a..add754159 100644 --- a/spec/lib/mastodon/cli/domains_spec.rb +++ b/spec/lib/mastodon/cli/domains_spec.rb @@ -4,5 +4,22 @@ require 'rails_helper' require 'mastodon/cli/domains' describe Mastodon::CLI::Domains do + let(:cli) { described_class.new } + it_behaves_like 'CLI Command' + + describe '#purge' do + context 'with accounts from the domain' do + let(:options) { {} } + let(:domain) { 'host.example' } + let!(:account) { Fabricate(:account, domain: domain) } + + it 'removes the account' do + expect { cli.invoke(:purge, [domain], options) }.to output( + a_string_including('Removed 1 accounts') + ).to_stdout + expect { account.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end end From a2bcfeb887a0ae1d437bb727333d769a8248b578 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Mon, 4 Dec 2023 10:09:43 +0100 Subject: [PATCH 193/255] Fix `Style/HashEachMethods` cop in HAML files (#28178) --- app/views/admin/reports/index.html.haml | 2 +- app/views/settings/applications/_fields.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/reports/index.html.haml b/app/views/admin/reports/index.html.haml index e94847d67..e2a9868aa 100644 --- a/app/views/admin/reports/index.html.haml +++ b/app/views/admin/reports/index.html.haml @@ -27,7 +27,7 @@ %button.button= t('admin.accounts.search') = link_to t('admin.accounts.reset'), admin_reports_path, class: 'button negative' -- @reports.group_by(&:target_account_id).each do |_target_account_id, reports| +- @reports.group_by(&:target_account_id).each_value do |reports| - target_account = reports.first.target_account .report-card .report-card__profile diff --git a/app/views/settings/applications/_fields.html.haml b/app/views/settings/applications/_fields.html.haml index 4f5077d83..29e2bcb5a 100644 --- a/app/views/settings/applications/_fields.html.haml +++ b/app/views/settings/applications/_fields.html.haml @@ -14,5 +14,5 @@ %label= t('activerecord.attributes.doorkeeper/application.scopes') %span.hint= t('simple_form.hints.defaults.scopes') - - Doorkeeper.configuration.scopes.group_by { |s| s.split(':').first }.each do |_key, value| + - Doorkeeper.configuration.scopes.group_by { |s| s.split(':').first }.each_value do |value| = f.input :scopes, label: false, hint: false, collection: value.sort, wrapper: :with_block_label, include_blank: false, label_method: ->(scope) { safe_join([content_tag(:samp, scope, class: class_for_scope(scope)), content_tag(:span, t("doorkeeper.scopes.#{scope}"), class: 'hint')]) }, selected: f.object.scopes.all, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' From 829457212ee2ae933db273b8dce402d2d8e659cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 10:38:49 +0100 Subject: [PATCH 194/255] Update dependency rubocop to v1.58.0 (#28170) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6820c12f9..037fe145d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -381,7 +381,7 @@ GEM rdoc reline (>= 0.3.8) jmespath (1.6.2) - json (2.6.3) + json (2.7.0) json-canonicalization (0.3.2) json-jwt (1.15.3) activesupport (>= 4.2) @@ -656,7 +656,7 @@ GEM rspec-mocks (~> 3.0) sidekiq (>= 5, < 8) rspec-support (3.12.1) - rubocop (1.57.2) + rubocop (1.58.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -664,7 +664,7 @@ GEM rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.28.1, < 2.0) + rubocop-ast (>= 1.30.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.30.0) From b3b009e6aa29d9051aa61113da344b3ab26d98e4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 4 Dec 2023 04:44:54 -0500 Subject: [PATCH 195/255] Add spec coverage for `CLI::EmailDomainBlocks` commands (#28181) --- lib/mastodon/cli/email_domain_blocks.rb | 4 +- .../mastodon/cli/email_domain_blocks_spec.rb | 93 +++++++++++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/lib/mastodon/cli/email_domain_blocks.rb b/lib/mastodon/cli/email_domain_blocks.rb index 88a84ecb4..022b1dcbb 100644 --- a/lib/mastodon/cli/email_domain_blocks.rb +++ b/lib/mastodon/cli/email_domain_blocks.rb @@ -7,10 +7,10 @@ module Mastodon::CLI class EmailDomainBlocks < Base desc 'list', 'List blocked e-mail domains' def list - EmailDomainBlock.where(parent_id: nil).order(id: 'DESC').find_each do |entry| + EmailDomainBlock.where(parent_id: nil).find_each do |entry| say(entry.domain.to_s, :white) - EmailDomainBlock.where(parent_id: entry.id).order(id: 'DESC').find_each do |child| + EmailDomainBlock.where(parent_id: entry.id).find_each do |child| say(" #{child.domain}", :cyan) end end diff --git a/spec/lib/mastodon/cli/email_domain_blocks_spec.rb b/spec/lib/mastodon/cli/email_domain_blocks_spec.rb index 060943b18..f5cb6c332 100644 --- a/spec/lib/mastodon/cli/email_domain_blocks_spec.rb +++ b/spec/lib/mastodon/cli/email_domain_blocks_spec.rb @@ -4,5 +4,98 @@ require 'rails_helper' require 'mastodon/cli/email_domain_blocks' describe Mastodon::CLI::EmailDomainBlocks do + let(:cli) { described_class.new } + it_behaves_like 'CLI Command' + + describe '#list' do + context 'with email domain block records' do + let!(:parent_block) { Fabricate(:email_domain_block) } + let!(:child_block) { Fabricate(:email_domain_block, parent: parent_block) } + let(:options) { {} } + + it 'lists the blocks' do + expect { cli.invoke(:list, [], options) }.to output( + a_string_including(parent_block.domain) + .and(a_string_including(child_block.domain)) + ).to_stdout + end + end + end + + describe '#add' do + context 'without any options' do + let(:options) { {} } + + it 'warns about usage and exits' do + expect { cli.invoke(:add, [], options) }.to output( + a_string_including('No domain(s) given') + ).to_stdout.and raise_error(SystemExit) + end + end + + context 'when blocks exist' do + let(:options) { {} } + let(:domain) { 'host.example' } + + before { Fabricate(:email_domain_block, domain: domain) } + + it 'does not add a new block' do + expect { cli.invoke(:add, [domain], options) }.to output( + a_string_including('is already blocked') + ).to_stdout + .and(not_change(EmailDomainBlock, :count)) + end + end + + context 'when no blocks exist' do + let(:options) { {} } + let(:domain) { 'host.example' } + + it 'adds a new block' do + expect { cli.invoke(:add, [domain], options) }.to output( + a_string_including('Added 1') + ).to_stdout + .and(change(EmailDomainBlock, :count).by(1)) + end + end + end + + describe '#remove' do + context 'without any options' do + let(:options) { {} } + + it 'warns about usage and exits' do + expect { cli.invoke(:remove, [], options) }.to output( + a_string_including('No domain(s) given') + ).to_stdout.and raise_error(SystemExit) + end + end + + context 'when blocks exist' do + let(:options) { {} } + let(:domain) { 'host.example' } + + before { Fabricate(:email_domain_block, domain: domain) } + + it 'removes the block' do + expect { cli.invoke(:remove, [domain], options) }.to output( + a_string_including('Removed 1') + ).to_stdout + .and(change(EmailDomainBlock, :count).by(-1)) + end + end + + context 'when no blocks exist' do + let(:options) { {} } + let(:domain) { 'host.example' } + + it 'does not remove a block' do + expect { cli.invoke(:remove, [domain], options) }.to output( + a_string_including('is not yet blocked') + ).to_stdout + .and(not_change(EmailDomainBlock, :count)) + end + end + end end From cca19f5fbb568bf7f145fe98d6d2497632c8987c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 4 Dec 2023 07:56:28 -0500 Subject: [PATCH 196/255] Use the `Admin::ActionLog` fabricator in admin/action_logs spec (#28194) --- .../admin/accounts_controller_spec.rb | 32 ++++++++++++------- .../admin/action_logs_controller_spec.rb | 31 +++++++++++++++--- .../api/v1/admin/account_actions_spec.rb | 17 +++++++--- spec/requests/api/v1/admin/accounts_spec.rb | 32 ++++++++++++------- 4 files changed, 78 insertions(+), 34 deletions(-) diff --git a/spec/controllers/admin/accounts_controller_spec.rb b/spec/controllers/admin/accounts_controller_spec.rb index 307e81950..1882ea838 100644 --- a/spec/controllers/admin/accounts_controller_spec.rb +++ b/spec/controllers/admin/accounts_controller_spec.rb @@ -161,12 +161,13 @@ RSpec.describe Admin::AccountsController do it 'logs action' do expect(subject).to have_http_status 302 - log_item = Admin::ActionLog.last - - expect(log_item).to_not be_nil - expect(log_item.action).to eq :approve - expect(log_item.account_id).to eq current_user.account_id - expect(log_item.target_id).to eq account.user.id + expect(latest_admin_action_log) + .to be_present + .and have_attributes( + action: eq(:approve), + account_id: eq(current_user.account_id), + target_id: eq(account.user.id) + ) end end @@ -201,12 +202,13 @@ RSpec.describe Admin::AccountsController do it 'logs action' do expect(subject).to have_http_status 302 - log_item = Admin::ActionLog.last - - expect(log_item).to_not be_nil - expect(log_item.action).to eq :reject - expect(log_item.account_id).to eq current_user.account_id - expect(log_item.target_id).to eq account.user.id + expect(latest_admin_action_log) + .to be_present + .and have_attributes( + action: eq(:reject), + account_id: eq(current_user.account_id), + target_id: eq(account.user.id) + ) end end @@ -427,4 +429,10 @@ RSpec.describe Admin::AccountsController do end end end + + private + + def latest_admin_action_log + Admin::ActionLog.last + end end diff --git a/spec/controllers/admin/action_logs_controller_spec.rb b/spec/controllers/admin/action_logs_controller_spec.rb index b7854469d..be4222df0 100644 --- a/spec/controllers/admin/action_logs_controller_spec.rb +++ b/spec/controllers/admin/action_logs_controller_spec.rb @@ -9,11 +9,9 @@ describe Admin::ActionLogsController do let!(:account) { Fabricate(:account) } before do - _orphaned_logs = %w( - Account User UserRole Report DomainBlock DomainAllow - EmailDomainBlock UnavailableDomain Status AccountWarning - Announcement IpBlock Instance CustomEmoji CanonicalEmailBlock Appeal - ).map { |type| Admin::ActionLog.new(account: account, action: 'destroy', target_type: type, target_id: 1312).save! } + orphaned_log_types.map do |type| + Fabricate(:action_log, account: account, action: 'destroy', target_type: type, target_id: 1312) + end end describe 'GET #index' do @@ -24,4 +22,27 @@ describe Admin::ActionLogsController do expect(response).to have_http_status(200) end end + + private + + def orphaned_log_types + %w( + Account + AccountWarning + Announcement + Appeal + CanonicalEmailBlock + CustomEmoji + DomainAllow + DomainBlock + EmailDomainBlock + Instance + IpBlock + Report + Status + UnavailableDomain + User + UserRole + ) + end end diff --git a/spec/requests/api/v1/admin/account_actions_spec.rb b/spec/requests/api/v1/admin/account_actions_spec.rb index c14e08c21..4167911a1 100644 --- a/spec/requests/api/v1/admin/account_actions_spec.rb +++ b/spec/requests/api/v1/admin/account_actions_spec.rb @@ -21,12 +21,19 @@ RSpec.describe 'Account actions' do it 'logs action' do subject - log_item = Admin::ActionLog.last + expect(latest_admin_action_log) + .to be_present + .and have_attributes( + action: eq(action_type), + account_id: eq(user.account_id), + target_id: eq(target_type == :user ? target_account.user.id : target_account.id) + ) + end - expect(log_item).to be_present - expect(log_item.action).to eq(action_type) - expect(log_item.account_id).to eq(user.account_id) - expect(log_item.target_id).to eq(target_type == :user ? target_account.user.id : target_account.id) + private + + def latest_admin_action_log + Admin::ActionLog.last end end diff --git a/spec/requests/api/v1/admin/accounts_spec.rb b/spec/requests/api/v1/admin/accounts_spec.rb index 8e158f623..1615581f0 100644 --- a/spec/requests/api/v1/admin/accounts_spec.rb +++ b/spec/requests/api/v1/admin/accounts_spec.rb @@ -151,12 +151,13 @@ RSpec.describe 'Accounts' do it 'logs action', :aggregate_failures do subject - log_item = Admin::ActionLog.last - - expect(log_item).to be_present - expect(log_item.action).to eq :approve - expect(log_item.account_id).to eq user.account_id - expect(log_item.target_id).to eq account.user.id + expect(latest_admin_action_log) + .to be_present + .and have_attributes( + action: eq(:approve), + account_id: eq(user.account_id), + target_id: eq(account.user.id) + ) end end @@ -202,12 +203,13 @@ RSpec.describe 'Accounts' do it 'logs action', :aggregate_failures do subject - log_item = Admin::ActionLog.last - - expect(log_item).to be_present - expect(log_item.action).to eq :reject - expect(log_item.account_id).to eq user.account_id - expect(log_item.target_id).to eq account.user.id + expect(latest_admin_action_log) + .to be_present + .and have_attributes( + action: eq(:reject), + account_id: eq(user.account_id), + target_id: eq(account.user.id) + ) end end @@ -398,4 +400,10 @@ RSpec.describe 'Accounts' do end end end + + private + + def latest_admin_action_log + Admin::ActionLog.last + end end From 71e5a16ebaf67d5e55d7f4e31436c36e6801ce5a Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 4 Dec 2023 10:28:19 -0500 Subject: [PATCH 197/255] Remove triple subject call in `api/v1/lists` spec (#28210) --- spec/requests/api/v1/lists_spec.rb | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/spec/requests/api/v1/lists_spec.rb b/spec/requests/api/v1/lists_spec.rb index 22dde43a1..4635e936f 100644 --- a/spec/requests/api/v1/lists_spec.rb +++ b/spec/requests/api/v1/lists_spec.rb @@ -135,8 +135,11 @@ RSpec.describe 'Lists' do it_behaves_like 'forbidden for wrong scope', 'read read:lists' - it 'returns the updated list', :aggregate_failures do - subject + it 'returns the updated list and updates values', :aggregate_failures do + expect { subject } + .to change_list_title + .and change_list_replies_policy + .and change_list_exclusive expect(response).to have_http_status(200) list.reload @@ -149,16 +152,16 @@ RSpec.describe 'Lists' do }) end - it 'updates the list title' do - expect { subject }.to change { list.reload.title }.from('my list').to('list') + def change_list_title + change { list.reload.title }.from('my list').to('list') end - it 'updates the list replies_policy' do - expect { subject }.to change { list.reload.replies_policy }.from('list').to('followed') + def change_list_replies_policy + change { list.reload.replies_policy }.from('list').to('followed') end - it 'updates the list exclusive' do - expect { subject }.to change { list.reload.exclusive }.from(false).to(true) + def change_list_exclusive + change { list.reload.exclusive }.from(false).to(true) end context 'when the list does not exist' do From 89a8e6e6227eb901b5811d8417d81dc8ab1427a9 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 4 Dec 2023 10:41:43 -0500 Subject: [PATCH 198/255] Remove 2x double subject call in `models/form/account_batch` spec (#28209) --- spec/models/form/account_batch_spec.rb | 40 +++++++++++++++++++------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/spec/models/form/account_batch_spec.rb b/spec/models/form/account_batch_spec.rb index fd8e90901..26fb1b953 100644 --- a/spec/models/form/account_batch_spec.rb +++ b/spec/models/form/account_batch_spec.rb @@ -37,12 +37,10 @@ RSpec.describe Form::AccountBatch do let(:select_all_matching) { '0' } let(:account_ids) { [target_account.id, target_account2.id] } - it 'suspends the expected users' do - expect { subject }.to change { [target_account.reload.suspended?, target_account2.reload.suspended?] }.from([false, false]).to([true, true]) - end - - it 'closes open reports targeting the suspended users' do - expect { subject }.to change { Report.unresolved.where(target_account: [target_account, target_account2]).count }.from(2).to(0) + it 'suspends the expected users and closes open reports' do + expect { subject } + .to change_account_suspensions + .and change_open_reports_for_accounts end end @@ -50,13 +48,33 @@ RSpec.describe Form::AccountBatch do let(:select_all_matching) { '1' } let(:query) { Account.where(id: [target_account.id, target_account2.id]) } - it 'suspends the expected users' do - expect { subject }.to change { [target_account.reload.suspended?, target_account2.reload.suspended?] }.from([false, false]).to([true, true]) + it 'suspends the expected users and closes open reports' do + expect { subject } + .to change_account_suspensions + .and change_open_reports_for_accounts end + end - it 'closes open reports targeting the suspended users' do - expect { subject }.to change { Report.unresolved.where(target_account: [target_account, target_account2]).count }.from(2).to(0) - end + private + + def change_account_suspensions + change { relevant_account_suspension_statuses } + .from([false, false]) + .to([true, true]) + end + + def change_open_reports_for_accounts + change(relevant_account_unresolved_reports, :count) + .from(2) + .to(0) + end + + def relevant_account_unresolved_reports + Report.unresolved.where(target_account: [target_account, target_account2]) + end + + def relevant_account_suspension_statuses + [target_account.reload, target_account2.reload].map(&:suspended?) end end end From f944a767c46e3d887e070d67958f4a9866c3d1f1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 13:57:16 +0100 Subject: [PATCH 199/255] Update dependency json-ld to v3.3.1 (#28229) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 037fe145d..602df6a22 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -382,15 +382,15 @@ GEM reline (>= 0.3.8) jmespath (1.6.2) json (2.7.0) - json-canonicalization (0.3.2) + json-canonicalization (1.0.0) json-jwt (1.15.3) activesupport (>= 4.2) aes_key_wrap bindata httpclient - json-ld (3.3.0) + json-ld (3.3.1) htmlentities (~> 4.3) - json-canonicalization (~> 0.3, >= 0.3.2) + json-canonicalization (~> 1.0) link_header (~> 0.0, >= 0.0.8) multi_json (~> 1.15) rack (>= 2.2, < 4) From 2d2e23c68dde6ac6fa14fe8fbeb0efac02ad9803 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:59:31 +0000 Subject: [PATCH 200/255] Update dependency brakeman to v6.1.0 (#28231) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 602df6a22..9308a41c8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -175,7 +175,7 @@ GEM blurhash (0.1.7) bootsnap (1.17.0) msgpack (~> 1.2) - brakeman (6.0.1) + brakeman (6.1.0) browser (5.3.1) brpoplpush-redis_script (0.1.3) concurrent-ruby (~> 1.0, >= 1.0.5) From d0a5ebf914f7ad74a69beb15d9c011e44e84c0dc Mon Sep 17 00:00:00 2001 From: Jonathan de Jong <jonathandejong02@gmail.com> Date: Tue, 5 Dec 2023 14:59:15 +0100 Subject: [PATCH 201/255] Fix error when encountering malformed Tag objects from Kbin (#28235) --- app/services/activitypub/process_status_update_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index 2db0e80e7..fb2b33114 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -170,9 +170,9 @@ class ActivityPub::ProcessStatusUpdateService < BaseService as_array(@json['tag']).each do |tag| if equals_or_includes?(tag['type'], 'Hashtag') - @raw_tags << tag['name'] + @raw_tags << tag['name'] if tag['name'].present? elsif equals_or_includes?(tag['type'], 'Mention') - @raw_mentions << tag['href'] + @raw_mentions << tag['href'] if tag['href'].present? elsif equals_or_includes?(tag['type'], 'Emoji') @raw_emojis << tag end From 4238ec844d61774a02daa4a677a69099ff494388 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 17:07:53 +0100 Subject: [PATCH 202/255] New Crowdin Translations (automated) (#28120) Co-authored-by: GitHub Actions <noreply@github.com> Co-authored-by: Claire <claire.github-309c@sitedethib.com> --- app/javascript/mastodon/locales/an.json | 1 + app/javascript/mastodon/locales/ca.json | 1 + app/javascript/mastodon/locales/es-MX.json | 2 +- app/javascript/mastodon/locales/fa.json | 7 +- app/javascript/mastodon/locales/fil.json | 1 + app/javascript/mastodon/locales/ko.json | 4 +- app/javascript/mastodon/locales/lt.json | 74 ++++++++++++++ app/javascript/mastodon/locales/ne.json | 1 + app/javascript/mastodon/locales/ry.json | 1 + app/javascript/mastodon/locales/sc.json | 36 +++++++ app/javascript/mastodon/locales/sk.json | 10 ++ app/javascript/mastodon/locales/sq.json | 1 + app/javascript/mastodon/locales/th.json | 14 +-- app/javascript/mastodon/locales/tlh.json | 1 + app/javascript/mastodon/locales/zh-TW.json | 2 +- config/i18n-tasks.yml | 1 + config/locales/activerecord.fil.yml | 1 + config/locales/activerecord.ne.yml | 1 + config/locales/activerecord.ry.yml | 1 + config/locales/activerecord.tlh.yml | 1 + config/locales/devise.fil.yml | 1 + config/locales/devise.ne.yml | 1 + config/locales/devise.ry.yml | 1 + config/locales/devise.tlh.yml | 1 + config/locales/doorkeeper.fil.yml | 1 + config/locales/doorkeeper.ne.yml | 1 + config/locales/doorkeeper.ry.yml | 1 + config/locales/doorkeeper.sc.yml | 15 +++ config/locales/doorkeeper.tlh.yml | 1 + config/locales/fil.yml | 1 + config/locales/fr-QC.yml | 1 + config/locales/fr.yml | 1 + config/locales/lt.yml | 26 ++++- config/locales/ne.yml | 1 + config/locales/ry.yml | 1 + config/locales/sc.yml | 113 +++++++++++++++++++++ config/locales/simple_form.fil.yml | 1 + config/locales/simple_form.lt.yml | 35 ++++++- config/locales/simple_form.ne.yml | 1 + config/locales/simple_form.ry.yml | 1 + config/locales/simple_form.sc.yml | 17 ++++ config/locales/simple_form.tlh.yml | 1 + config/locales/tlh.yml | 1 + 43 files changed, 366 insertions(+), 19 deletions(-) create mode 100644 app/javascript/mastodon/locales/fil.json create mode 100644 app/javascript/mastodon/locales/ne.json create mode 100644 app/javascript/mastodon/locales/ry.json create mode 100644 app/javascript/mastodon/locales/tlh.json create mode 100644 config/locales/activerecord.fil.yml create mode 100644 config/locales/activerecord.ne.yml create mode 100644 config/locales/activerecord.ry.yml create mode 100644 config/locales/activerecord.tlh.yml create mode 100644 config/locales/devise.fil.yml create mode 100644 config/locales/devise.ne.yml create mode 100644 config/locales/devise.ry.yml create mode 100644 config/locales/devise.tlh.yml create mode 100644 config/locales/doorkeeper.fil.yml create mode 100644 config/locales/doorkeeper.ne.yml create mode 100644 config/locales/doorkeeper.ry.yml create mode 100644 config/locales/doorkeeper.tlh.yml create mode 100644 config/locales/fil.yml create mode 100644 config/locales/ne.yml create mode 100644 config/locales/ry.yml create mode 100644 config/locales/simple_form.fil.yml create mode 100644 config/locales/simple_form.ne.yml create mode 100644 config/locales/simple_form.ry.yml create mode 100644 config/locales/simple_form.tlh.yml create mode 100644 config/locales/tlh.yml diff --git a/app/javascript/mastodon/locales/an.json b/app/javascript/mastodon/locales/an.json index a652272fa..b2134551b 100644 --- a/app/javascript/mastodon/locales/an.json +++ b/app/javascript/mastodon/locales/an.json @@ -499,6 +499,7 @@ "report_notification.open": "Ubrir informe", "search.placeholder": "Buscar", "search.search_or_paste": "Buscar u apegar URL", + "search_popout.full_text_search_logged_out_message": "Nomás disponible iniciando la sesión.", "search_results.all": "Totz", "search_results.hashtags": "Etiquetas", "search_results.nothing_found": "No se podió trobar cosa pa estes termins de busqueda", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 87121b7c5..5ae49325f 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -482,6 +482,7 @@ "onboarding.follows.lead": "La teva línia de temps inici només està a les teves mans. Com més gent segueixis, més activa i interessant serà. Aquests perfils poden ser un bon punt d'inici—sempre pots acabar deixant de seguir-los!:", "onboarding.follows.title": "Personalitza la pantalla d'inci", "onboarding.profile.discoverable": "Fes el meu perfil descobrible", + "onboarding.profile.discoverable_hint": "En acceptar d'ésser descobert a Mastodon els teus missatges poden aparèixer dins les tendències i els resultats de cerques, i el teu perfil es pot suggerir a qui tingui interessos semblants als teus.", "onboarding.profile.display_name": "Nom que es mostrarà", "onboarding.profile.display_name_hint": "El teu nom complet o el teu malnom…", "onboarding.profile.lead": "Sempre ho pots completar més endavant a la configuració, on hi ha encara més opcions disponibles.", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index f7cd1b330..0d26afef2 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -606,7 +606,7 @@ "search.quick_action.status_search": "Publicaciones que coinciden con {x}", "search.search_or_paste": "Buscar o pegar URL", "search_popout.full_text_search_disabled_message": "No disponible en {domain}.", - "search_popout.full_text_search_logged_out_message": "Solo disponible si inicias sesión.", + "search_popout.full_text_search_logged_out_message": "Sólo disponible al iniciar sesión.", "search_popout.language_code": "Código de idioma ISO", "search_popout.options": "Opciones de búsqueda", "search_popout.quick_actions": "Acciones rápidas", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 6951d5cb0..8e8930bfe 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -1,7 +1,7 @@ { "about.blocks": "کارسازهای نظارت شده", "about.contact": "تماس:", - "about.disclaimer": "ماستودون نرمافزار آزاد و یک شرکت غیر انتفاعی آلمانی با مسئولیت محدود است.", + "about.disclaimer": "ماستودون نرمافزار آزاد و نشان تجاری یک شرکت غیر انتفاعی با مسئولیت محدود آلمانی است.", "about.domain_blocks.no_reason_available": "دلیلی موجود نیست", "about.domain_blocks.preamble": "ماستودون عموماً میگذارد محتوا را از از هر کارساز دیگری در دنیای شبکههای اجتماعی غیرمتمرکز دیده و با آنان برهمکنش داشته باشید. اینها استثناهایی هستند که روی این کارساز خاص وضع شدهاند.", "about.domain_blocks.silenced.explanation": "عموماً نمایهها و محتوا از این کارساز را نمیبینید، مگر این که به طور خاص دنبالشان گشته یا با پی گیری، داوطلب دیدنشان شوید.", @@ -21,6 +21,7 @@ "account.blocked": "مسدود", "account.browse_more_on_origin_server": "مرور بیشتر روی نمایهٔ اصلی", "account.cancel_follow_request": "رد کردن درخواست پیگیری", + "account.copy": "رونوشت از پیوند به نمایه", "account.direct": "اشارهٔ خصوصی به @{name}", "account.disable_notifications": "آگاه کردن من هنگام فرستههای @{name} را متوقّف کن", "account.domain_blocked": "دامنه مسدود شد", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "علامتگذاری به عنوان خوانده شده", "conversation.open": "دیدن گفتگو", "conversation.with": "با {names}", + "copy_icon_button.copied": "در بریدهدان رونوشت شد", "copypaste.copied": "رونوشت شد", "copypaste.copy_to_clipboard": "رونوشت به تختهگیره", "directory.federated": "از کارسازهای شناختهشده", @@ -486,6 +488,8 @@ "onboarding.profile.note_hint": "میتوانید افراد دیگر را @نامبردن یا #برچسب بزنید…", "onboarding.profile.save_and_continue": "ذخیره کن و ادامه بده", "onboarding.profile.title": "تنظیم نمایه", + "onboarding.profile.upload_avatar": "بازگذاری تصویر نمایه", + "onboarding.profile.upload_header": "بارگذاری تصویر سردر نمایه", "onboarding.share.lead": "بگذارید افراد بدانند چگونه میتوانند در ماستادون بیابندتان!", "onboarding.share.message": "من {username} روی #ماستودون هستم! مرا در {url} پیبگیرید", "onboarding.share.next_steps": "گامهای ممکن بعدی:", @@ -600,6 +604,7 @@ "search.quick_action.status_search": "فرستههای جور با {x}", "search.search_or_paste": "جستوجو یا جایگذاری نشانی", "search_popout.full_text_search_disabled_message": "روی {domain} موجود نیست.", + "search_popout.full_text_search_logged_out_message": "تنها زمانی که وارد شدهاید دردسترس است.", "search_popout.language_code": "کد زبان ایزو", "search_popout.options": "گزینههای جستوجو", "search_popout.quick_actions": "کنشهای سریع", diff --git a/app/javascript/mastodon/locales/fil.json b/app/javascript/mastodon/locales/fil.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/app/javascript/mastodon/locales/fil.json @@ -0,0 +1 @@ +{} diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 46caf32b0..5b76cd67c 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -302,8 +302,8 @@ "hashtag.counter_by_accounts": "{count, plural, other {{counter} 명의 참여자}}", "hashtag.counter_by_uses": "{count, plural, other {{counter} 개의 게시물}}", "hashtag.counter_by_uses_today": "오늘 {count, plural, other {{counter} 개의 게시물}}", - "hashtag.follow": "해시태그 팔로우", - "hashtag.unfollow": "해시태그 팔로우 해제", + "hashtag.follow": "팔로우", + "hashtag.unfollow": "팔로우 해제", "hashtags.and_other": "…그리고 {count, plural,other {#개 더}}", "home.actions.go_to_explore": "무엇이 유행인지 보기", "home.actions.go_to_suggestions": "팔로우할 사람 찾기", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index a976d5907..e588b8538 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -180,29 +180,71 @@ "confirmations.logout.message": "Ar tikrai nori atsijungti?", "confirmations.mute.confirm": "Nutildyti", "confirmations.mute.explanation": "Tai paslėps jų įrašus ir įrašus, kuriuose jie menėmi, tačiau jie vis tiek galės matyti tavo įrašus ir sekti.", + "confirmations.mute.message": "Ar tikrai norite nutildyti {name}?", + "confirmations.redraft.confirm": "Ištrinti ir perrašyti", "confirmations.reply.confirm": "Atsakyti", "confirmations.reply.message": "Atsakant dabar, bus perrašyta metu kuriama žinutė. Ar tikrai nori tęsti?", "confirmations.unfollow.confirm": "Nebesekti", + "confirmations.unfollow.message": "Ar tikrai norite atsisakyti sekimo {name}?", + "conversation.delete": "Ištrinti pokalbį", "conversation.mark_as_read": "Žymėti kaip skaitytą", "conversation.open": "Peržiūrėti pokalbį", "conversation.with": "Su {names}", "copy_icon_button.copied": "Nukopijuota į iškarpinę", "copypaste.copied": "Nukopijuota", "copypaste.copy_to_clipboard": "Kopijuoti į iškarpinę", + "directory.local": "Iš {domain} tik", + "directory.new_arrivals": "Naujos prekės", + "directory.recently_active": "Neseniai aktyvus", "disabled_account_banner.account_settings": "Paskyros nustatymai", + "disabled_account_banner.text": "Jūsų paskyra {disabledAccount} šiuo metu yra išjungta.", + "dismissable_banner.dismiss": "Atmesti", "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", + "dismissable_banner.explore_statuses": "Tai įrašai iš viso socialinio tinklo, kurie šiandien sulaukia vis daugiau dėmesio. Naujesni įrašai, turintys daugiau boosts ir mėgstamiausių įrašų, yra vertinami aukščiau.", "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", "embed.instructions": "Embed this status on your website by copying the code below.", "embed.preview": "Štai kaip tai atrodys:", + "emoji_button.activity": "Veikla", + "emoji_button.clear": "Išvalyti", + "emoji_button.custom": "Pasirinktinis", + "emoji_button.flags": "Vėliavos", + "emoji_button.food": "Maistas ir Gėrimai", + "emoji_button.label": "Įterpti veidelius", + "emoji_button.nature": "Gamta", + "emoji_button.not_found": "Nerasta jokių tinkamų jaustukų", "emoji_button.objects": "Objektai", + "emoji_button.people": "Žmonės", + "emoji_button.recent": "Dažniausiai naudojama", "emoji_button.search": "Paieška...", + "emoji_button.search_results": "Paieškos rezultatai", + "emoji_button.symbols": "Simboliai", + "emoji_button.travel": "Kelionės ir Vietos", "empty_column.account_hides_collections": "Šis naudotojas (-a) pasirinko nepadaryti šią informaciją prieinamą", + "empty_column.account_suspended": "Paskyra sustabdyta", "empty_column.account_timeline": "No toots here!", + "empty_column.account_unavailable": "Profilis neprieinamas", + "empty_column.blocks": "Dar neužblokavote nė vieno naudotojo.", "empty_column.bookmarked_statuses": "You don't have any bookmarked toots yet. When you bookmark one, it will show up here.", + "empty_column.community": "Vietinė laiko juosta yra tuščia. Parašykite ką nors viešai, kad pradėtumėte veikti!", + "empty_column.direct": "Dar neturite jokių privačių paminėjimų. Kai išsiųsite arba gausite tokį pranešimą, jis bus rodomas čia.", "empty_column.domain_blocks": "There are no hidden domains yet.", + "empty_column.favourited_statuses": "Dar neturite mėgstamiausių įrašų. Kai vieną iš jų pamėgsite, jis bus rodomas čia.", + "empty_column.follow_requests": "Dar neturite jokių sekimo užklausų. Kai gausite tokį prašymą, jis bus rodomas čia.", + "empty_column.followed_tags": "Dar nesekėte jokių grotažymių. Kai tai padarysite, jie bus rodomi čia.", "empty_column.hashtag": "Nėra nieko šiame saitažodyje kol kas.", "empty_column.home": "Your home timeline is empty! Follow more people to fill it up. {suggestions}", "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", + "empty_column.lists": "Dar neturite jokių sąrašų. Kai jį sukursite, jis bus rodomas čia.", + "empty_column.mutes": "Dar nesate nutildę nė vieno naudotojo.", + "empty_column.notifications": "Dar neturite jokių pranešimų. Kai kiti žmonės su jumis bendraus, matysite tai čia.", + "empty_column.public": "Čia nieko nėra! Parašykite ką nors viešai arba rankiniu būdu sekite naudotojus iš kitų serverių, kad jį užpildytumėte", + "error.unexpected_crash.explanation": "Dėl mūsų kodo klaidos arba naršyklės suderinamumo problemos šis puslapis negalėjo būti rodomas teisingai.", + "error.unexpected_crash.explanation_addons": "Šį puslapį nepavyko teisingai parodyti. Šią klaidą greičiausiai sukėlė naršyklės priedas arba automatinio vertimo įrankiai.", + "error.unexpected_crash.next_steps": "Pabandykite atnaujinti puslapį. Jei tai nepadeda, galbūt vis dar galėsite naudotis \"Mastodon\" naudodami kitą naršyklę arba vietinę programėlę.", + "error.unexpected_crash.next_steps_addons": "Pabandykite juos išjungti ir atnaujinti puslapį. Jei tai nepadeda, galbūt vis dar galėsite naudotis \"Mastodon\" naudodami kitą naršyklę arba vietinę programėlę.", + "errors.unexpected_crash.report_issue": "Pranešti apie triktį", + "explore.search_results": "Paieškos rezultatai", + "explore.suggested_follows": "Žmonės", "explore.title": "Naršyti", "explore.trending_links": "Naujienos", "explore.trending_statuses": "Įrašai", @@ -304,7 +346,13 @@ "moved_to_account_banner.text": "Tavo paskyra {disabledAccount} šiuo metu yra išjungta, nes persikėlei į {movedToAccount}.", "mute_modal.duration": "Trukmė", "mute_modal.hide_notifications": "Slėpti šio naudotojo pranešimus?", + "mute_modal.indefinite": "Neribotas", + "navigation_bar.about": "Apie", + "navigation_bar.advanced_interface": "Atidarykite išplėstinę žiniatinklio sąsają", + "navigation_bar.blocks": "Užblokuoti naudotojai", + "navigation_bar.bookmarks": "Žymės", "navigation_bar.compose": "Compose new toot", + "navigation_bar.direct": "Privatūs paminėjimai", "navigation_bar.discover": "Atrasti", "navigation_bar.domain_blocks": "Hidden domains", "navigation_bar.edit_profile": "Redaguoti profilį", @@ -372,6 +420,7 @@ "notifications.permission_required": "Darbalaukio pranešimai nepasiekiami, nes nesuteiktas reikiamas leidimas.", "notifications_permission_banner.enable": "Įjungti darbalaukio pranešimus", "notifications_permission_banner.how_to_control": "Jei norite gauti pranešimus, kai \"Mastodon\" nėra atidarytas, įjunkite darbalaukio pranešimus. Įjungę darbalaukio pranešimus, galite tiksliai valdyti, kokių tipų sąveikos generuoja darbalaukio pranešimus, naudodamiesi pirmiau esančiu mygtuku {icon}.", + "notifications_permission_banner.title": "Niekada nieko nepraleiskite", "onboarding.action.back": "Gražinkite mane atgal", "onboarding.actions.back": "Gražinkite mane atgal", "onboarding.actions.go_to_explore": "See what's trending", @@ -394,8 +443,10 @@ "onboarding.share.lead": "Praneškite žmonėms, kaip jus rasti \"Mastodon\"!", "onboarding.share.message": "Aš {username} #Mastodon! Ateik sekti manęs adresu {url}", "onboarding.share.next_steps": "Galimi kiti žingsniai:", + "onboarding.share.title": "Bendrinkite savo profilį", "onboarding.start.lead": "Dabar esi Mastodon dalis – unikalios decentralizuotos socialinės žiniasklaidos platformos, kurioje tu, o ne algoritmas, pats nustatai savo patirtį. Pradėkime tavo kelionę šioje naujoje socialinėje erdvėje:", "onboarding.start.skip": "Want to skip right ahead?", + "onboarding.start.title": "Jums pavyko!", "onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.", "onboarding.steps.follow_people.title": "Follow {count, plural, one {one person} other {# people}}", "onboarding.steps.publish_status.body": "Say hello to the world.", @@ -404,23 +455,46 @@ "onboarding.steps.setup_profile.title": "Customize your profile", "onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!", "onboarding.steps.share_profile.title": "Share your profile", + "picture_in_picture.restore": "Padėkite jį atgal", + "poll.closed": "Uždaryti", + "poll.refresh": "Atnaujinti", + "poll.reveal": "Peržiūrėti rezultatus", "poll.vote": "Balsuoti", "poll.voted": "Tu balsavai už šį atsakymą", "poll.votes": "{votes, plural, one {# balsas} few {# balsai} many {# balso} other {# balsų}}", + "poll_button.add_poll": "Pridėti apklausą", + "poll_button.remove_poll": "Šalinti apklausą", "privacy.change": "Adjust status privacy", "privacy.direct.long": "Post to mentioned users only", "privacy.direct.short": "Direct", "privacy.private.long": "Post to followers only", "privacy.private.short": "Followers-only", + "privacy.public.long": "Visiems matomas", + "privacy.public.short": "Viešas", "privacy.unlisted.long": "Matomas visiems, bet atsisakyta atradimo funkcijų", "privacy.unlisted.short": "Neįtrauktas į sąrašą", "privacy_policy.last_updated": "Paskutinį kartą atnaujinta {date}", + "privacy_policy.title": "Privatumo politika", "recommended": "Rekomenduojama", + "refresh": "Atnaujinti", + "regeneration_indicator.label": "Kraunasi…", + "relative_time.full.just_now": "ką tik", "relative_time.hours": "{number} val.", "relative_time.just_now": "dabar", "relative_time.minutes": "{number} min.", "relative_time.seconds": "{number} sek.", "relative_time.today": "šiandien", + "reply_indicator.cancel": "Atšaukti", + "report.block": "Blokuoti", + "report.categories.legal": "Legalus", + "report.categories.other": "Kita", + "report.categories.spam": "Šlamštas", + "report.categories.violation": "Turinys pažeidžia vieną ar daugiau serverio taisyklių", + "report.category.subtitle": "Pasirinkite tinkamiausią variantą", + "report.category.title_account": "profilis", + "report.category.title_status": "įrašas", + "report.close": "Atlikta", + "report.comment.title": "Ar yra dar kas nors, ką, jūsų manymu, turėtume žinoti?", "report.mute_explanation": "Jų įrašų nematysi. Jie vis tiek gali tave sekti ir matyti įrašus, bet nežinos, kad jie nutildyti.", "report.next": "Tęsti", "report.placeholder": "Papildomi komentarai", diff --git a/app/javascript/mastodon/locales/ne.json b/app/javascript/mastodon/locales/ne.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/app/javascript/mastodon/locales/ne.json @@ -0,0 +1 @@ +{} diff --git a/app/javascript/mastodon/locales/ry.json b/app/javascript/mastodon/locales/ry.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/app/javascript/mastodon/locales/ry.json @@ -0,0 +1 @@ +{} diff --git a/app/javascript/mastodon/locales/sc.json b/app/javascript/mastodon/locales/sc.json index 59c834b95..7f29525e7 100644 --- a/app/javascript/mastodon/locales/sc.json +++ b/app/javascript/mastodon/locales/sc.json @@ -14,6 +14,7 @@ "account.badges.group": "Grupu", "account.block": "Bloca @{name}", "account.block_domain": "Bloca su domìniu {domain}", + "account.block_short": "Bloca", "account.blocked": "Blocadu", "account.browse_more_on_origin_server": "Esplora de prus in su profilu originale", "account.cancel_follow_request": "Withdraw follow request", @@ -31,17 +32,20 @@ "account.follows.empty": "Custa persone non sighit ancora a nemos.", "account.follows_you": "Ti sighit", "account.hide_reblogs": "Cua is cumpartziduras de @{name}", + "account.in_memoriam": "In memoriam.", "account.joined_short": "At aderidu", "account.link_verified_on": "Sa propiedade de custu ligòngiu est istada controllada su {date}", "account.locked_info": "S'istadu de riservadesa de custu contu est istadu cunfiguradu comente blocadu. Sa persone chi tenet sa propiedade revisionat a manu chie dda podet sighire.", "account.media": "Cuntenutu multimediale", "account.mention": "Mèntova a @{name}", "account.mute": "Pone a @{name} a sa muda", + "account.mute_short": "A sa muda", "account.muted": "A sa muda", "account.posts": "Publicatziones", "account.posts_with_replies": "Publicatziones e rispostas", "account.report": "Signala @{name}", "account.requested": "Abetende s'aprovatzione. Incarca pro annullare sa rechesta de sighidura", + "account.requested_follow": "{name} at dimandadu de ti sighire", "account.share": "Cumpartzi su profilu de @{name}", "account.show_reblogs": "Ammustra is cumpartziduras de @{name}", "account.statuses_counter": "{count, plural, one {{counter} publicatzione} other {{counter} publicatziones}}", @@ -106,6 +110,7 @@ "compose_form.publish": "Pùblica", "compose_form.publish_form": "Publish", "compose_form.publish_loud": "{publish}!", + "compose_form.save_changes": "Sarva is modìficas", "compose_form.sensitive.hide": "{count, plural, one {Marca elementu multimediale comente a sensìbile} other {Marca elementos multimediales comente sensìbiles}}", "compose_form.sensitive.marked": "{count, plural, one {Elementu multimediale marcadu comente a sensìbile} other {Elementos multimediales marcados comente a sensìbiles}}", "compose_form.sensitive.unmarked": "{count, plural, one {Elementu multimediale non marcadu comente a sensìbile} other {Elementos multimediales non marcados comente a sensìbiles}}", @@ -122,6 +127,7 @@ "confirmations.delete_list.message": "Seguru chi boles cantzellare custa lista in manera permanente?", "confirmations.domain_block.confirm": "Bloca totu su domìniu", "confirmations.domain_block.message": "Boles de seguru, ma a beru a beru, blocare {domain}? In sa parte manna de is casos, pagos blocos o silentziamentos de persones sunt sufitzientes e preferìbiles. No as a bìdere cuntenutos dae custu domìniu in peruna lìnia de tempus pùblica o in is notìficas tuas. Sa gente chi ti sighit dae cussu domìniu at a èssere bogada.", + "confirmations.edit.confirm": "Modìfica", "confirmations.logout.confirm": "Essi·nche", "confirmations.logout.message": "Seguru chi boles essire?", "confirmations.mute.confirm": "A sa muda", @@ -140,6 +146,7 @@ "directory.local": "Isceti dae {domain}", "directory.new_arrivals": "Arribos noos", "directory.recently_active": "Cun atividade dae pagu", + "disabled_account_banner.account_settings": "Cunfiguratziones de su contu", "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", "embed.instructions": "Inserta custa publicatzione in su situ web tuo copiende su còdighe de suta.", @@ -180,13 +187,19 @@ "errors.unexpected_crash.copy_stacktrace": "Còpia stacktrace in punta de billete", "errors.unexpected_crash.report_issue": "Sinnala unu problema", "explore.search_results": "Resurtados de sa chirca", + "explore.suggested_follows": "Gente", + "explore.trending_statuses": "Publicatziones", + "explore.trending_tags": "Etichetas", "filter_modal.select_filter.expired": "iscadidu", + "firehose.all": "Totus", "follow_request.authorize": "Autoriza", "follow_request.reject": "Refuda", "follow_requests.unlocked_explanation": "Fintzas si su contu tuo no est blocadu, su personale de {domain} at pensadu chi forsis bolias revisionare a manu is rechestas de custos contos.", "footer.about": "Informatziones", "footer.invite": "Invita gente", + "footer.keyboard_shortcuts": "Incurtzaduras de tecladu", "footer.privacy_policy": "Polìtica de riservadesa", + "footer.status": "Istadu", "generic.saved": "Sarvadu", "getting_started.heading": "Comente cumintzare", "hashtag.column_header.tag_mode.all": "e {additional}", @@ -263,6 +276,7 @@ "lists.search": "Chirca intre sa gente chi ses sighende", "lists.subheading": "Is listas tuas", "load_pending": "{count, plural, one {# elementu nou} other {# elementos noos}}", + "loading_indicator.label": "Carrighende…", "media_gallery.toggle_visible": "Cua {number, plural, one {immàgine} other {immàgines}}", "mute_modal.duration": "Durada", "mute_modal.hide_notifications": "Boles cuare is notìficas de custa persone?", @@ -288,6 +302,7 @@ "navigation_bar.search": "Chirca", "navigation_bar.security": "Seguresa", "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", + "notification.favourite": "{name} at marcadu comente a preferidu s'istadu tuo", "notification.follow": "{name} ti sighit", "notification.follow_request": "{name} at dimandadu de ti sighire", "notification.mention": "{name} t'at mentovadu", @@ -328,6 +343,8 @@ "onboarding.actions.go_to_home": "Go to your home feed", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.display_name": "Nòmine visìbile", + "onboarding.profile.note": "Biografia", "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", "onboarding.start.skip": "Want to skip right ahead?", "onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.", @@ -344,6 +361,7 @@ "poll.total_votes": "{count, plural, one {# votu} other {# votos}}", "poll.vote": "Vota", "poll.voted": "As votadu custa risposta", + "poll.votes": "{votes, plural, one {# votu} other {# votos}}", "poll_button.add_poll": "Agiunghe unu sondàgiu", "poll_button.remove_poll": "Cantzella su sondàgiu", "privacy.change": "Modìfica s'istadu de riservadesa", @@ -353,25 +371,41 @@ "privacy.private.short": "Followers-only", "privacy.public.short": "Pùblicu", "privacy.unlisted.short": "Esclùidu de sa lista", + "recommended": "Cussigiadu", "refresh": "Atualiza", "regeneration_indicator.label": "Carrighende…", "regeneration_indicator.sublabel": "Preparende sa lìnia de tempus printzipale tua.", "relative_time.days": "{number} dies a oe", + "relative_time.full.just_now": "immoe etotu", "relative_time.hours": "{number} oras a immoe", "relative_time.just_now": "immoe", "relative_time.minutes": "{number} minutos a immoe", "relative_time.seconds": "{number} segundos a immoe", "relative_time.today": "oe", "reply_indicator.cancel": "Annulla", + "report.block": "Bloca", + "report.categories.other": "Àteru", + "report.category.title_account": "profilu", + "report.category.title_status": "publicatzione", + "report.close": "Fatu", "report.forward": "Torra a imbiare a {target}", "report.forward_hint": "Custu contu est de un'àteru serbidore. Ddi boles imbiare puru una còpia anònima de custu informe?", + "report.mute": "A sa muda", + "report.next": "Imbeniente", "report.placeholder": "Cummentos additzionales", "report.submit": "Imbia", "report.target": "Informende de {target}", "report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached", + "report_notification.categories.other": "Àteru", "search.placeholder": "Chirca", + "search_popout.user": "utente", + "search_results.accounts": "Profilos", + "search_results.all": "Totus", "search_results.hashtags": "Etichetas", "search_results.statuses": "Publicatziones", + "server_banner.administered_by": "Amministradu dae:", + "server_banner.learn_more": "Àteras informatziones", + "server_banner.server_stats": "Istatìsticas de su serbidore:", "sign_in_banner.sign_in": "Sign in", "status.admin_account": "Aberi s'interfache de moderatzione pro @{name}", "status.admin_status": "Aberi custa publicatzione in s'interfache de moderatzione", @@ -382,6 +416,7 @@ "status.copy": "Còpia su ligòngiu a sa publicatzione tua", "status.delete": "Cantzella", "status.detailed_status": "Visualizatzione de detàlliu de arresonada", + "status.edit": "Modìfica", "status.edited_x_times": "Edited {count, plural, one {# time} other {# times}}", "status.embed": "Afissa", "status.filtered": "Filtradu", @@ -413,6 +448,7 @@ "status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}", "status.unmute_conversation": "Torra a ativare s'arresonada", "status.unpin": "Boga dae pitzu de su profilu", + "subscribed_languages.save": "Sarva is modìficas", "tabs_bar.home": "Printzipale", "tabs_bar.notifications": "Notìficas", "time_remaining.days": "{number, plural, one {abarrat # die} other {abarrant # dies}}", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 9115695d8..c4ce6f8cf 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -391,6 +391,7 @@ "lists.search": "Vyhľadávaj medzi užívateľmi, ktorých sleduješ", "lists.subheading": "Tvoje zoznamy", "load_pending": "{count, plural, one {# nová položka} other {# nových položiek}}", + "loading_indicator.label": "Načítam…", "media_gallery.toggle_visible": "Zapni/Vypni viditeľnosť", "moved_to_account_banner.text": "Vaše konto {disabledAccount} je momentálne zablokované, pretože ste sa presunuli na {movedToAccount}.", "mute_modal.duration": "Trvanie", @@ -480,6 +481,14 @@ "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", "onboarding.profile.discoverable": "Urob môj profil objaviteľný", + "onboarding.profile.display_name": "Zobrazované meno", + "onboarding.profile.display_name_hint": "Tvoje plné meno, alebo tvoje zábavné meno…", + "onboarding.profile.lead": "Toto môžeš vždy dokončiť neskôr v nastaveniach, kde je dostupných ešte viac volieb na prispôsobenie.", + "onboarding.profile.note": "O tebe", + "onboarding.profile.note_hint": "Môžeš @spomenúť iných ľudí, alebo #haštagy…", + "onboarding.profile.save_and_continue": "Ulož a pokračuj", + "onboarding.profile.upload_avatar": "Nahraj profilový obrázok", + "onboarding.profile.upload_header": "Nahraj profilové záhlavie", "onboarding.share.lead": "Daj ľudom vedieť, ako ťa môžu na Mastodone nájsť!", "onboarding.share.message": "Na Mastodone som {username}. Príď ma nasledovať na {url}", "onboarding.share.next_steps": "Ďalšie možné kroky:", @@ -594,6 +603,7 @@ "search.quick_action.status_search": "Príspevky zodpovedajúce {x}", "search.search_or_paste": "Hľadaj, alebo vlož URL adresu", "search_popout.full_text_search_disabled_message": "Nie je k dispozícii v doméne {domain}.", + "search_popout.full_text_search_logged_out_message": "Dostupné iba keď si prihlásený/á.", "search_popout.language_code": "ISO kód jazyka", "search_popout.options": "Možnosti vyhľadávania", "search_popout.quick_actions": "Rýchle akcie", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 86042a91e..710224e1c 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -606,6 +606,7 @@ "search.quick_action.status_search": "Postime me përputhje me {x}", "search.search_or_paste": "Kërkoni, ose hidhni një URL", "search_popout.full_text_search_disabled_message": "Jo i passhëm në {domain}.", + "search_popout.full_text_search_logged_out_message": "E përdorshme vetëm kur keni bërë hyrjen në llogari.", "search_popout.language_code": "Kod ISO gjuhe", "search_popout.options": "Mundësi kërkimi", "search_popout.quick_actions": "Veprime të shpejta", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index c020dc362..0be9bf6d7 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -60,7 +60,7 @@ "account.report": "รายงาน @{name}", "account.requested": "กำลังรอการอนุมัติ คลิกเพื่อยกเลิกคำขอติดตาม", "account.requested_follow": "{name} ได้ขอติดตามคุณ", - "account.share": "แบ่งปันโปรไฟล์ของ @{name}", + "account.share": "แชร์โปรไฟล์ของ @{name}", "account.show_reblogs": "แสดงการดันจาก @{name}", "account.statuses_counter": "{count, plural, other {{counter} โพสต์}}", "account.unblock": "เลิกปิดกั้น @{name}", @@ -319,7 +319,7 @@ "home.show_announcements": "แสดงประกาศ", "interaction_modal.description.favourite": "ด้วยบัญชีใน Mastodon คุณสามารถชื่นชอบโพสต์นี้เพื่อแจ้งให้ผู้สร้างทราบว่าคุณชื่นชมโพสต์และบันทึกโพสต์ไว้สำหรับภายหลัง", "interaction_modal.description.follow": "ด้วยบัญชีใน Mastodon คุณสามารถติดตาม {name} เพื่อรับโพสต์ของเขาในฟีดหน้าแรกของคุณ", - "interaction_modal.description.reblog": "ด้วยบัญชีใน Mastodon คุณสามารถดันโพสต์นี้เพื่อแบ่งปันโพสต์กับผู้ติดตามของคุณเอง", + "interaction_modal.description.reblog": "ด้วยบัญชีใน Mastodon คุณสามารถดันโพสต์นี้เพื่อแชร์โพสต์กับผู้ติดตามของคุณเอง", "interaction_modal.description.reply": "ด้วยบัญชีใน Mastodon คุณสามารถตอบกลับโพสต์นี้", "interaction_modal.login.action": "นำฉันกลับบ้าน", "interaction_modal.login.prompt": "โดเมนของเซิร์ฟเวอร์บ้านของคุณ เช่น mastodon.social", @@ -495,7 +495,7 @@ "onboarding.share.lead": "แจ้งให้ผู้คนทราบวิธีที่เขาสามารถค้นหาคุณใน Mastodon!", "onboarding.share.message": "ฉันคือ {username} ใน #Mastodon! มาติดตามฉันที่ {url}", "onboarding.share.next_steps": "ขั้นตอนถัดไปที่เป็นไปได้:", - "onboarding.share.title": "แบ่งปันโปรไฟล์ของคุณ", + "onboarding.share.title": "แชร์โปรไฟล์ของคุณ", "onboarding.start.lead": "ตอนนี้คุณเป็นส่วนหนึ่งของ Mastodon แพลตฟอร์มสื่อสังคมที่มีเอกลักษณ์เฉพาะตัว กระจายศูนย์ ที่ซึ่งคุณ—ไม่ใช่อัลกอริทึม—เรียบเรียงประสบการณ์ของคุณเอง มาช่วยให้คุณเริ่มต้นใช้งานพรมแดนทางสังคมใหม่นี้กันเลย:", "onboarding.start.skip": "ไม่ต้องการความช่วยเหลือในการเริ่มต้นใช้งาน?", "onboarding.start.title": "คุณทำสำเร็จแล้ว!", @@ -506,7 +506,7 @@ "onboarding.steps.setup_profile.body": "เพิ่มการโต้ตอบของคุณโดยการมีโปรไฟล์ที่ครอบคลุม", "onboarding.steps.setup_profile.title": "ปรับแต่งโปรไฟล์ของคุณ", "onboarding.steps.share_profile.body": "แจ้งให้เพื่อน ๆ ของคุณทราบวิธีค้นหาคุณใน Mastodon", - "onboarding.steps.share_profile.title": "แบ่งปันโปรไฟล์ Mastodon ของคุณ", + "onboarding.steps.share_profile.title": "แชร์โปรไฟล์ Mastodon ของคุณ", "onboarding.tips.2fa": "<strong>คุณทราบหรือไม่?</strong> คุณสามารถรักษาความปลอดภัยบัญชีของคุณได้โดยตั้งค่าการรับรองความถูกต้องด้วยสองปัจจัยในการตั้งค่าบัญชีของคุณ การรับรองความถูกต้องด้วยสองปัจจัยทำงานร่วมกับแอป TOTP ใด ๆ ที่คุณเลือก ไม่จำเป็นต้องมีหมายเลขโทรศัพท์!", "onboarding.tips.accounts_from_other_servers": "<strong>คุณทราบหรือไม่?</strong> เนื่องจาก Mastodon เป็นแบบกระจายศูนย์ โปรไฟล์บางส่วนที่คุณเจอจะได้รับการโฮสต์ในเซิร์ฟเวอร์อื่น ๆ ที่ไม่ใช่ของคุณ และคุณยังสามารถโต้ตอบกับเขาได้อย่างไร้รอยต่อ! เซิร์ฟเวอร์ของเขาอยู่ในครึ่งหลังของชื่อผู้ใช้ของเขา!", "onboarding.tips.migration": "<strong>คุณทราบหรือไม่?</strong> หากคุณรู้สึกว่า {domain} ไม่ใช่ตัวเลือกเซิร์ฟเวอร์ที่ยอดเยี่ยมสำหรับคุณในอนาคต คุณสามารถย้ายไปยังเซิร์ฟเวอร์ Mastodon อื่นได้โดยไม่สูญเสียผู้ติดตามของคุณ คุณยังสามารถโฮสต์เซิร์ฟเวอร์ของคุณเอง!", @@ -558,7 +558,7 @@ "report.categories.spam": "สแปม", "report.categories.violation": "เนื้อหาละเมิดกฎของเซิร์ฟเวอร์จำนวนหนึ่งหรือมากกว่า", "report.category.subtitle": "เลือกที่ตรงกันที่สุด", - "report.category.title": "บอกเราถึงสิ่งที่กำลังเกิดขึ้นกับ {type} นี้", + "report.category.title": "บอกเราถึงสิ่งที่กำลังเกิดขึ้นกับ{type}นี้", "report.category.title_account": "โปรไฟล์", "report.category.title_status": "โพสต์", "report.close": "เสร็จสิ้น", @@ -629,7 +629,7 @@ "sign_in_banner.create_account": "สร้างบัญชี", "sign_in_banner.sign_in": "เข้าสู่ระบบ", "sign_in_banner.sso_redirect": "เข้าสู่ระบบหรือลงทะเบียน", - "sign_in_banner.text": "เข้าสู่ระบบเพื่อติดตามโปรไฟล์หรือแฮชแท็ก ชื่นชอบ แบ่งปัน และตอบกลับโพสต์ คุณยังสามารถโต้ตอบจากบัญชีของคุณในเซิร์ฟเวอร์อื่น", + "sign_in_banner.text": "เข้าสู่ระบบเพื่อติดตามโปรไฟล์หรือแฮชแท็ก ชื่นชอบ แชร์ และตอบกลับโพสต์ คุณยังสามารถโต้ตอบจากบัญชีของคุณในเซิร์ฟเวอร์อื่น", "status.admin_account": "เปิดส่วนติดต่อการควบคุมสำหรับ @{name}", "status.admin_domain": "เปิดส่วนติดต่อการควบคุมสำหรับ {domain}", "status.admin_status": "เปิดโพสต์นี้ในส่วนติดต่อการควบคุม", @@ -675,7 +675,7 @@ "status.replyAll": "ตอบกลับกระทู้", "status.report": "รายงาน @{name}", "status.sensitive_warning": "เนื้อหาที่ละเอียดอ่อน", - "status.share": "แบ่งปัน", + "status.share": "แชร์", "status.show_filter_reason": "แสดงต่อไป", "status.show_less": "แสดงน้อยลง", "status.show_less_all": "แสดงน้อยลงทั้งหมด", diff --git a/app/javascript/mastodon/locales/tlh.json b/app/javascript/mastodon/locales/tlh.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/app/javascript/mastodon/locales/tlh.json @@ -0,0 +1 @@ +{} diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 7ba66ae8c..e6dd008bf 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -376,7 +376,7 @@ "lightbox.previous": "上一步", "limited_account_hint.action": "一律顯示個人檔案", "limited_account_hint.title": "此個人檔案已被 {domain} 的管理員隱藏。", - "link_preview.author": "由 {name} 提供", + "link_preview.author": "來自 {name}", "lists.account.add": "新增至列表", "lists.account.remove": "自列表中移除", "lists.delete": "刪除列表", diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index e2ea4153c..8463d4297 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -70,6 +70,7 @@ ignore_unused: - 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html' - 'mail_subscriptions.unsubscribe.emails.*' - 'preferences.other' # some locales are missing other keys, therefore leading i18n-tasks to detect `preferences` as plural and not finding use + - 'edit_profile.other' # some locales are missing other keys, therefore leading i18n-tasks to detect `preferences` as plural and not finding use ignore_inconsistent_interpolations: - '*.one' diff --git a/config/locales/activerecord.fil.yml b/config/locales/activerecord.fil.yml new file mode 100644 index 000000000..4084bf2f9 --- /dev/null +++ b/config/locales/activerecord.fil.yml @@ -0,0 +1 @@ +fil: diff --git a/config/locales/activerecord.ne.yml b/config/locales/activerecord.ne.yml new file mode 100644 index 000000000..db03c5186 --- /dev/null +++ b/config/locales/activerecord.ne.yml @@ -0,0 +1 @@ +ne: diff --git a/config/locales/activerecord.ry.yml b/config/locales/activerecord.ry.yml new file mode 100644 index 000000000..6fe57b65c --- /dev/null +++ b/config/locales/activerecord.ry.yml @@ -0,0 +1 @@ +ry: diff --git a/config/locales/activerecord.tlh.yml b/config/locales/activerecord.tlh.yml new file mode 100644 index 000000000..884714fb7 --- /dev/null +++ b/config/locales/activerecord.tlh.yml @@ -0,0 +1 @@ +tlh: diff --git a/config/locales/devise.fil.yml b/config/locales/devise.fil.yml new file mode 100644 index 000000000..4084bf2f9 --- /dev/null +++ b/config/locales/devise.fil.yml @@ -0,0 +1 @@ +fil: diff --git a/config/locales/devise.ne.yml b/config/locales/devise.ne.yml new file mode 100644 index 000000000..db03c5186 --- /dev/null +++ b/config/locales/devise.ne.yml @@ -0,0 +1 @@ +ne: diff --git a/config/locales/devise.ry.yml b/config/locales/devise.ry.yml new file mode 100644 index 000000000..6fe57b65c --- /dev/null +++ b/config/locales/devise.ry.yml @@ -0,0 +1 @@ +ry: diff --git a/config/locales/devise.tlh.yml b/config/locales/devise.tlh.yml new file mode 100644 index 000000000..884714fb7 --- /dev/null +++ b/config/locales/devise.tlh.yml @@ -0,0 +1 @@ +tlh: diff --git a/config/locales/doorkeeper.fil.yml b/config/locales/doorkeeper.fil.yml new file mode 100644 index 000000000..4084bf2f9 --- /dev/null +++ b/config/locales/doorkeeper.fil.yml @@ -0,0 +1 @@ +fil: diff --git a/config/locales/doorkeeper.ne.yml b/config/locales/doorkeeper.ne.yml new file mode 100644 index 000000000..db03c5186 --- /dev/null +++ b/config/locales/doorkeeper.ne.yml @@ -0,0 +1 @@ +ne: diff --git a/config/locales/doorkeeper.ry.yml b/config/locales/doorkeeper.ry.yml new file mode 100644 index 000000000..6fe57b65c --- /dev/null +++ b/config/locales/doorkeeper.ry.yml @@ -0,0 +1 @@ +ry: diff --git a/config/locales/doorkeeper.sc.yml b/config/locales/doorkeeper.sc.yml index 1f1d38f3a..297d6bd8f 100644 --- a/config/locales/doorkeeper.sc.yml +++ b/config/locales/doorkeeper.sc.yml @@ -69,6 +69,7 @@ sc: confirmations: revoke: Seguru? index: + scopes: Permissos title: Is aplicatziones autorizadas tuas errors: messages: @@ -104,6 +105,20 @@ sc: authorized_applications: destroy: notice: Aplicatzione revocada. + grouped_scopes: + title: + accounts: Contos + bookmarks: Sinnalibros + conversations: Arresonadas + filters: Filtros + follows: Sighende + lists: Listas + media: Allegados multimediales + notifications: Notìficas + push: Notìficas push + reports: Informes + search: Chirca + statuses: Publicatziones layouts: admin: nav: diff --git a/config/locales/doorkeeper.tlh.yml b/config/locales/doorkeeper.tlh.yml new file mode 100644 index 000000000..884714fb7 --- /dev/null +++ b/config/locales/doorkeeper.tlh.yml @@ -0,0 +1 @@ +tlh: diff --git a/config/locales/fil.yml b/config/locales/fil.yml new file mode 100644 index 000000000..4084bf2f9 --- /dev/null +++ b/config/locales/fil.yml @@ -0,0 +1 @@ +fil: diff --git a/config/locales/fr-QC.yml b/config/locales/fr-QC.yml index 3aba8713f..00a59463c 100644 --- a/config/locales/fr-QC.yml +++ b/config/locales/fr-QC.yml @@ -611,6 +611,7 @@ fr-QC: created_at: Signalé delete_and_resolve: Supprimer les messages forwarded: Transféré + forwarded_replies_explanation: Ce rapport provient d'un utilisateur sur une autre instance et concerne du contenu non-local. Il vous a été transmis car le contenu signalé est en réponse à l'un de vos utilisateurs. forwarded_to: Transféré à %{domain} mark_as_resolved: Marquer comme résolu mark_as_sensitive: Marquer comme sensible diff --git a/config/locales/fr.yml b/config/locales/fr.yml index a69a5b535..0a6601bbc 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -611,6 +611,7 @@ fr: created_at: Signalé delete_and_resolve: Supprimer les messages forwarded: Transféré + forwarded_replies_explanation: Ce rapport provient d'un utilisateur sur une autre instance et concerne du contenu non-local. Il vous a été transmis car le contenu signalé est en réponse à l'un de vos utilisateurs. forwarded_to: Transféré à %{domain} mark_as_resolved: Marquer comme résolu mark_as_sensitive: Marquer comme sensible diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 111127749..b1d8772b6 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -37,10 +37,12 @@ lt: accounts: add_email_domain_block: Blokuoti el. pašto domeną approve: Patvirtinti + approved_msg: Sėkmingai patvirtinta %{username} registracijos paraiška are_you_sure: Ar esi įsitikinęs (-usi)? avatar: Avataras by_domain: Domenas change_email: + changed_msg: El. paštas sėkmingai pakeistas! current_email: Dabartinis el paštas label: Pakeisti el pašto adresą new_email: Naujas el pašto adresas @@ -466,6 +468,8 @@ lt: prev: Ankstesnis preferences: other: Kita + privacy: + hint_html: "<strong>Tikrink, kaip nori, kad tavo profilis ir įrašai būtų randami.</strong> Įjungus įvairias Mastodon funkcijas, jos gali padėti pasiekti platesnę auditoriją. Akimirką peržiūrėk šiuos nustatymus, kad įsitikintum, jog jie atitinka tavo naudojimo būdą." remote_follow: missing_resource: Jūsų paskyros nukreipimo URL nerasta scheduled_statuses: @@ -515,6 +519,11 @@ lt: public_long: Visi gali matyti unlisted: Neįtrauktas į sąrašus unlisted_long: Matyti gali visi, tačiau nėra įtraukti į viešąsias laiko skales + statuses_cleanup: + enabled_hint: Automatiškai ištrina įrašus, kai jie pasiekia nustatytą amžiaus ribą, nebent jie atitinka vieną iš toliau nurodytų išimčių + keep_polls_hint: Neištrina jokių tavo apklausų + keep_self_bookmark: Laikyti įrašus, kuriuos pažymėjai + keep_self_bookmark_hint: Neištrina tavo pačių įrašų, jei esi juos pažymėjęs (-usi) stream_entries: sensitive_content: Jautrus turinys themes: @@ -551,22 +560,31 @@ lt: explanation: Štai keletas patarimų, kaip pradėti final_action: Pradėti kelti įrašus final_step: 'Pradėk skelbti! Net jei ir neturi sekėjų, tavo viešus įrašus gali matyti kiti, pavyzdžiui, vietinėje laiko skalėje arba saitažodžiuose. Galbūt norėsi prisistatyti saitažodyje #introductions.' - full_handle: Jūsų pilnas slapyvardis - full_handle_hint: Štai ką jūs sakytumėte savo draugams, kad jie galėtų jums siųsti žinutes arba just sekti iš kitų serverių. + full_handle: Tavo pilnas slapyvardis + full_handle_hint: Štai ką pasakytum savo draugams, kad jie galėtų parašyti arba sekti tave iš kito serverio. subject: Sveiki atvykę į Mastodon title: Sveiki atvykę, %{name}! users: - follow_limit_reached: Negalite sekti daugiau nei %{limit} žmonių + follow_limit_reached: Negali sekti daugiau nei %{limit} žmonių + go_to_sso_account_settings: Eik į savo tapatybės teikėjo paskyros nustatymus invalid_otp_token: Netinkamas dviejų veiksnių kodas otp_lost_help_html: Jei praradai prieigą prie abiejų, gali susisiek su %{email} - seamless_external_login: Jūs esate prisijungę per išorini įrenginį, todėl slaptąžodis ir el pašto nustatymai neprieinami. + seamless_external_login: Esi prisijungęs (-usi) per išorinę paslaugą, todėl slaptažodžio ir el. pašto nustatymai nepasiekiami. signed_in_as: 'Prisijungta kaip:' verification: + extra_instructions_html: <strong>Patarimas:</strong> nuoroda tavo svetainėje gali būti nematoma. Svarbi dalis – tai, kas <code>rel="me"</code> neleidžia apsimesti interneto svetainėse, kuriose yra naudotojų sukurto turinio. Vietoj to gali naudoti net <code>nuorodą</code> puslapio antraštėje esančią žymę <code>a</code>, tačiau HTML turi būti pasiekiamas nevykdant JavaScript. hint_html: "<strong>Savo tapatybės patvirtinimas Mastodon skirtas visiems.</strong> Remiantis atviraisiais žiniatinklio standartais, dabar ir visam laikui nemokamas. Viskas, ko tau reikia, yra asmeninė svetainė, pagal kurią žmonės tave atpažįsta. Kai iš savo profilio pateiksi nuorodą į šią svetainę, patikrinsime, ar svetainėje yra nuoroda į tavo profilį, ir parodysime vizualinį indikatorių." + instructions_html: Nukopijuok ir įklijuok toliau pateiktą kodą į savo svetainės HTML. Tada į vieną iš papildomų profilio laukų skirtuke „Redaguoti profilį“ įrašyk savo svetainės adresą ir išsaugok pakeitimus. verification: Patvirtinimas verified_links: Tavo patikrintos nuorodos webauthn_credentials: create: error: Kilo problema pridedant saugumo raktą. Bandyk dar kartą. + success: Tavo saugumo raktas buvo sėkmingai pridėtas. + delete_confirmation: Ar tikrai nori ištrinti šį saugumo raktą? + description_html: Jei įjungsi <strong>saugumo rakto tapatybės nustatymą</strong>, prisijungiant reikės naudoti vieną iš savo saugumo raktų. + destroy: + error: Kilo problema ištrinant saugumo raktą. Bandyk dar kartą. + success: Tavo saugumo raktas buvo sėkmingai ištrintas. nickname_hint: Įvesk naujojo saugumo rakto slapyvardį not_enabled: Dar neįjungei WebAuthn diff --git a/config/locales/ne.yml b/config/locales/ne.yml new file mode 100644 index 000000000..db03c5186 --- /dev/null +++ b/config/locales/ne.yml @@ -0,0 +1 @@ +ne: diff --git a/config/locales/ry.yml b/config/locales/ry.yml new file mode 100644 index 000000000..6fe57b65c --- /dev/null +++ b/config/locales/ry.yml @@ -0,0 +1 @@ +ry: diff --git a/config/locales/sc.yml b/config/locales/sc.yml index fa7603f2b..d92b64783 100644 --- a/config/locales/sc.yml +++ b/config/locales/sc.yml @@ -5,6 +5,7 @@ sc: contact_missing: No cunfiguradu contact_unavailable: No a disponimentu hosted_on: Mastodon allogiadu in %{domain} + title: Informatziones accounts: follow: Sighi followers: @@ -45,6 +46,7 @@ sc: confirm: Cunfirma confirmed: Cunfirmadu confirming: Cunfirmende + custom: Personalizadu delete: Cantzella datos deleted: Cantzelladu demote: Degrada @@ -81,7 +83,9 @@ sc: moderation: active: Ativu all: Totus + disabled: Disativadu pending: De imbiare + silenced: Limitadu suspended: Suspèndidu title: Moderatzione moderation_notes: Notas de moderatzione @@ -112,6 +116,7 @@ sc: search: Chirca search_same_email_domain: Àteras persones cun su pròpiu domìniu de posta search_same_ip: Àteras persones cun sa pròpiu IP + security: Seguresa sensitive: Sensìbile sensitized: marcadu comente a sensìbile shared_inbox_url: URL de intrada cumpartzida @@ -122,6 +127,7 @@ sc: silenced: Limitadas statuses: Tuts subscribe: Sutascrie·ti + suspend: Suspensione suspended: Suspèndidu suspension_irreversible: Is datos de custu contu sunt istados cantzellados in manera irreversìbile. Podes bogare sa suspensione a su contu pro chi si potzat impreare, ma no at a recuperare datu perunu de is chi teniat in antis. suspension_reversible_hint_html: Su contu est istadu suspèndidu, e is datos ant a èssere cantzelladu de su totu su %{date}. Finas a tando, su contu si podet ripristinare sena efetu malu perunu. Si boles cantzellare totu is datos de su contu immediatamente ddu podes fàghere inoghe in bassu. @@ -274,6 +280,7 @@ sc: updated_msg: Emoji atualizadu upload: Càrriga dashboard: + media_storage: Immagasinamentu software: Programmas space: Impreu de ispàtziu title: Pannellu @@ -281,21 +288,28 @@ sc: add_new: Permite sa federatzione cun domìniu created_msg: Sa federatzione cun su domìniu est istada permìtida destroyed_msg: Sa federatzione cun su domìniu no est istada permìtida + import: Importatzione undo: Non permitas sa federatzione cun su domìniu domain_blocks: add_new: Agiunghe blocu de domìniu nou + confirm_suspension: + cancel: Annulla + confirm: Suspensione created_msg: Protzessende su blocu de domìniu destroyed_msg: Su blocu de domìniu est istadu iscontzadu domain: Domìniu edit: Modìfica su blocu de su domìniu existing_domain_block_html: As giai impostu lìmites prus astrintos a %{name}, ddu dias dèpere <a href="%{unblock_url}">isblocare</a> prima. + import: Importatzione new: create: Crea unu blocu hint: Su blocu de domìniu no at a impedire sa creatzione de contos noos in sa base de datos, ma ant a èssere aplicados in manera retroativa mètodos de moderatzione ispetzìficos subra custos contos. severity: noop: Perunu + silence: A sa muda suspend: Suspensione title: Blocu de domìniu nou + not_permitted: Non tenes su permissu de fàghere custa atzione obfuscate: Cua su nòmine de domìniu obfuscate_hint: Cua una parte de su nòmine de domìniu in sa lista si sa visualizatzione de sa lista de domìnios limitados est ativa private_comment: Cummentu privadu @@ -326,9 +340,24 @@ sc: title: Cussìgios de sighidura unsuppress: Recùpera su cussìgiu de sighidura instances: + back_to_all: Totus + back_to_limited: Limitadu + back_to_warning: Atentzione by_domain: Domìniu + content_policies: + policies: + reject_reports: Refuda informes + silence: A sa muda + suspend: Suspensione + dashboard: + instance_reports_measure: informes a subra de àtere + delivery: + all: Totus delivery_available: Sa cunsigna est a disponimentu empty: Perunu domìniu agatadu. + known_accounts: + one: "%{count} contu connòschidu" + other: "%{count} contos connòschidos" moderation: all: Totus limited: Limitadas @@ -390,18 +419,23 @@ sc: notes: one: "%{count} nota" other: "%{count} notas" + action_log: Registru de controllu action_taken_by: Mesuras adotadas dae are_you_sure: Seguru? assign_to_self: Assigna a mie assigned: Moderatzione assignada by_target_domain: Domìniu de su contu signaladu + cancel: Annulla comment: none: Perunu + confirm: Cunfirma created_at: Sinnaladu forwarded: Torradu a imbiare forwarded_to: Torradu a imbiare a %{domain} mark_as_resolved: Marca comente a isòrvidu + mark_as_sensitive: Signala comente a sensìbile mark_as_unresolved: Marcare comente a non isòrvidu + no_one_assigned: Nemos notes: create: Agiunghe una nota create_and_resolve: Isorve cun una nota @@ -419,6 +453,15 @@ sc: unassign: Boga s'assignatzione unresolved: No isòrvidu updated_at: Atualizadu + view_profile: Visualiza profilu + roles: + categories: + administration: Amministratzione + invites: Invitos + moderation: Moderatzione + delete: Cantzella + privileges: + administrator: Amministratzione rules: add_new: Agiunghe règula delete: Cantzella @@ -427,10 +470,26 @@ sc: empty: Peruna règula de serbidore definida ancora. title: Règulas de su serbidore settings: + about: + manage_rules: Gesti is règulas de su serbidore + title: Informatziones + appearance: + title: Aspetu + default_noindex: + desc_html: Ìmplicat a totu is utentes chi no apant modificadu custa cunfiguratzione + title: Esclude in manera predefinida is utentes dae s'inditzamentu de is motores de chirca + discovery: + follow_recommendations: Cussìgios de sighidura + profile_directory: Diretòriu de profilos + public_timelines: Lìnias de tempos pùblicas + title: Iscoberta + trends: Tendèntzias domain_blocks: all: Pro totus disabled: Pro nemos users: Pro utentes locales in lìnia + registrations: + title: Registros registrations_mode: modes: approved: Aprovatzione rechesta pro si registrare @@ -439,7 +498,10 @@ sc: site_uploads: delete: Cantzella s'archìviu carrigadu destroyed_msg: Càrriga de su situ cantzellada. + software_updates: + documentation_link: Àteras informatziones statuses: + application: Aplicatzione back_to_account: Torra a sa pàgina de su contu deleted: Cantzelladu media: @@ -447,6 +509,10 @@ sc: no_status_selected: Perunu istadu est istadu mudadu dae chi non nd'as seletzionadu title: Istados de su contu with_media: Cun elementos multimediales + strikes: + actions: + none: "%{name} at imbiadu un'avisu a %{target}" + suspend: "%{name} at suspèndidu su contu de %{target}" system_checks: database_schema_check: message_html: Ddoe at tràmudas de base de datos in suspesu. Pone·ddas in esecutzione pro ti assegurare chi s'aplicatzione funtzionet comente si tocat @@ -459,12 +525,24 @@ sc: review: Revisiona s'istadu updated_msg: Cunfiguratzione de etichetas atualizada title: Amministratzione + trends: + pending_review: De revisionare + tags: + title: Etichetas de tendèntzia + title: Tendèntzias warning_presets: add_new: Agiunghe noa delete: Cantzella edit_preset: Modìfica s'avisu predefinidu empty: No as cunfiguradu ancora perunu avisu predefinidu. title: Gesti is cunfiguratziones predefinidas de is avisos + webhooks: + delete: Cantzella + disable: Disativa + disabled: Disativadu + enable: Ativa + enabled: Ativu + status: Istadu admin_mailer: new_pending_account: body: Is detàllios de su contu nou sunt a suta. Podes aprovare o refudare custa rechesta. @@ -473,6 +551,9 @@ sc: body: "%{reporter} at sinnaladu %{target}" body_remote: Una persone de su domìniu %{domain} at sinnaladu %{target} subject: Informe nou pro %{instance} (#%{id}) + new_trends: + new_trending_tags: + title: Etichetas de tendèntzia aliases: add_new: Crea unu nomìngiu created_msg: Nomìngiu creadu. Immoe podes cumintzare a tramudare dae su contu betzu. @@ -495,17 +576,21 @@ sc: notification_preferences: Muda is preferèntzias de posta salutation: "%{name}," settings: 'Muda is preferèntzias de posta: %{link}' + unsubscribe: Annulla sa sutiscritzione view: 'Visualizatzione:' view_profile: Visualiza profilu view_status: Ammustra s'istadu applications: created: Aplicatzione creada destroyed: Aplicatzione cantzellada + logout: Essi regenerate_token: Torra a generare s'identificadore de atzessu token_regenerated: Identificadore de atzessu generadu warning: Dae cara a custos datos. Non ddos cumpartzas mai cun nemos! your_token: S'identificadore tuo de atzessu auth: + confirmations: + login_link: intra delete_account: Cantzella su contu delete_account_html: Si boles cantzellare su contu, ddu podes <a href="%{path}">fàghere inoghe</a>. T'amus a dimandare una cunfirmatzione. description: @@ -528,11 +613,14 @@ sc: register: Registru registration_closed: "%{instance} no atzetat àteras persones" reset_password: Reseta sa crae + rules: + back: A coa security: Seguresa set_new_password: Cunfigura una crae noa status: account_status: Istadu de su contu confirming: Isetende chi sa posta eletrònica siat cumpletada. + functional: Su contu tuo est operativu. pending: Sa dimanda tua est in protzessu de revisione dae su personale nostru. Podet serbire unu pagu de tempus. As a retzire unu messàgiu eletrònicu si sa dimanda est aprovada. redirecting_to: Su contu tuo est inativu pro ite in die de oe est torrende a indiritzare a %{acct}. too_fast: Formulàriu imbiadu tropu a lestru, torra a proare. @@ -581,8 +669,14 @@ sc: more_details_html: Pro àteros detàllios, bide sa <a href="%{terms_path}">normativa de riservadesa</a>. username_available: Su nòmine de utente tuo at a torrare a èssere a disponimentu username_unavailable: Su nòmine de utente tuo no at a abarrare a disponimentu + disputes: + strikes: + title_actions: + none: Atentzione domain_validator: invalid_domain: no est unu nòmine de domìniu vàlidu + edit_profile: + other: Àteru errors: '400': Sa dimanda chi as imbiadu non fiat vàlida o non fiat curreta. '403': Non tenes permissu pro bìdere custa pàgina. @@ -638,11 +732,15 @@ sc: title: Agiunghe unu filtru nou generic: all: Totus + cancel: Annulla changes_saved_msg: Modìficas sarvadas. + confirm: Cunfirma copy: Còpia delete: Cantzella + none: Perunu order_by: Òrdina pro save_changes: Sarva is modìficas + today: oe validation_errors: one: Calicuna cosa ancora no est andende. Bide sa faddina in bàsciu other: Calicuna cosa ancora no est andende. Bide is %{count} faddinas in bàsciu @@ -655,12 +753,15 @@ sc: overwrite: Subrascrie overwrite_long: Sostitui is registros atuales cun cussos noos preface: Podes importare datos chi as esportadu dae unu àteru serbidore, che a sa lista de sa gente chi ses sighende o blochende. + status: Istadu success: Datos carrigados; ant a èssere protzessados luego + type: Casta de importatzione types: blocking: Lista de blocos bookmarks: Sinnalibros domain_blocking: Lista domìnios blocados following: Lista de sighiduras + lists: Listas muting: Lista gente a sa muda upload: Càrriga invites: @@ -685,6 +786,13 @@ sc: expires_at: Iscadit uses: Impreos title: Invita gente + login_activities: + authentication_methods: + password: crae + webauthn: craes de seguresa + mail_subscriptions: + unsubscribe: + title: Annulla sa sutiscritzione media_attachments: validations: images_and_video: Non si podet allegare unu vìdeu in una publicatzione chi cuntenet giai immàgines @@ -797,6 +905,8 @@ sc: other: Àteru posting_defaults: Valores predefinidos de publicatzione public_timelines: Lìnias de tempos pùblicas + privacy: + search: Chirca reactions: errors: limit_reached: Lìmite de reatziones diferentes cròmpidu @@ -850,6 +960,7 @@ sc: platforms: adobe_air: Adobe Air android: Android + chrome_os: ChromeOS firefox_os: Firefox OS ios: iOS linux: Linux @@ -934,6 +1045,7 @@ sc: '2629746': 1 mese '31556952': 1 annu '5259492': 2 meses + '604800': 1 chida '63113904': 2 annos '7889238': 3 meses stream_entries: @@ -969,6 +1081,7 @@ sc: subject: S'archìviu tuo est prontu pro èssere iscarrigadu title: Collida dae s'archìviu warning: + reason: 'Resone:' subject: disable: Su contu tuo %{acct} est istadu cungeladu none: Avisu pro %{acct} diff --git a/config/locales/simple_form.fil.yml b/config/locales/simple_form.fil.yml new file mode 100644 index 000000000..4084bf2f9 --- /dev/null +++ b/config/locales/simple_form.fil.yml @@ -0,0 +1 @@ +fil: diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index 39caaf6ba..d53b7105e 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -27,14 +27,33 @@ lt: none: Naudok šią parinktį norėdamas (-a) išsiųsti įspėjimą naudotojui, nesukeldamas (-a) jokio kito veiksmo. sensitive: Priversk visus šio naudotojo medijos priedus pažymėti kaip jautrius. silence: Neleisk naudotojui skelbti viešai matomų įrašų, paslėpk jų įrašus ir pranešimus nuo žmonių, kurie neseka jo. Uždaro visus su šia paskyra susijusius ataskaitas. + suspend: Neleisk jokios sąveikos iš šios paskyros arba į ją ir ištrink jos turinį. Sugrąžinama per 30 dienų. Uždaro visas su šia paskyra susijusias ataskaitas. + warning_preset_id: Pasirinktinai. Gali pridėti pasirinktinį tekstą iš anksto nustatyto rinkinio pabaigoje + announcement: + all_day: Jei pažymėta, bus rodomos tik laikotarpio datos + ends_at: Pasirinktinai. Skelbimas šiuo laiku bus automatiškai panaikintas + scheduled_at: Palik tuščią, kad skelbimas būtų paskelbtas iš karto + starts_at: Pasirinktinai. Jei skelbimas susietas su tam tikru laiko tarpu + text: Gali naudoti įrašo sintaksę. Būk dėmesingas (-a), kiek vietos naudotojo ekrane užims skelbimas + appeal: + text: Gali pateikti apeliaciją dėl streiko tik vieną kartą defaults: + autofollow: Žmonės, kurie užsiregistruos per kvietimą, automatiškai seks tave avatar: PNG, GIF arba JPG. Ne daugiau kaip %{size}. Bus sumažintas iki %{dimensions} tšk. - header: PNG, GIF arba JPG. Ne daugiau kaip %{size}. Bus sumažintas iki %{dimensions}tšk. + bot: Signalizuoti kitiems, kad paskyroje daugiausia atliekami automatiniai veiksmai ir kad ji gali būti nestebima + context: Vienas arba keli kontekstai, kuriems turėtų būti taikomas filtras + current_password: Saugumo sumetimais įvesk dabartinės paskyros slaptažodį + current_username: Kad patvirtintum, įvesk dabartinės paskyros naudotojo vardą + digest: Siunčiama tik po ilgo neaktyvumo laikotarpio ir tik tuo atveju, jei negavai jokių asmeninių žinučių + email: Tau bus išsiųstas patvirtinimo el. laiškas + header: PNG, GIF arba JPG. Ne daugiau kaip %{size}. Bus sumažintas iki %{dimensions} tšk. inbox_url: Nukopijuok URL adresą iš pradinio puslapio perdavėjo, kurį nori naudoti irreversible: Filtruoti įrašai išnyks negrįžtamai, net jei vėliau filtras bus pašalintas locale: Naudotojo sąsajos kalba, el. laiškai ir stumiamieji pranešimai password: Naudok bent 8 simbolius - phrase: Bus suderinta, neatsižvelgiant į teksto korpusą arba įrašo turinio įspėjimą + phrase: Bus suderinta, neatsižvelgiant į teksto lygį arba įrašo turinio įspėjimą + scopes: Prie kurių API programai bus leidžiama pasiekti. Pasirinkus aukščiausio lygio sritį, atskirų sričių pasirinkti nereikia. + setting_aggregate_reblogs: Nerodyti naujų pakėlimų įrašams, kurie neseniai buvo pakelti (taikoma tik naujai gautiems pakėlimams) setting_always_send_emails: Paprastai pranešimai el. paštu nebus siunčiami, kai aktyviai naudoji Mastodon setting_default_sensitive: Jautrioji medija pagal numatytuosius nustatymus yra paslėpta ir gali būti atskleista paspaudus setting_display_media_default: Slėpti mediją, pažymėtą kaip jautrią @@ -42,16 +61,26 @@ lt: setting_display_media_show_all: Visada rodyti mediją setting_use_blurhash: Gradientai pagrįsti paslėptų vaizdų spalvomis, tačiau užgožia bet kokias detales setting_use_pending_items: Slėpti laiko skalės naujienas po paspaudimo, vietoj automatinio kanalo slinkimo + username: Gali naudoti raides, skaičius ir pabraukimus + whole_word: Kai raktažodis ar frazė yra tik raidinis ir skaitmeninis, jis bus taikomas tik tada, jei atitiks visą žodį featured_tag: name: 'Štai keletas pastaruoju metu dažniausiai saitažodžių, kurių tu naudojai:' + filters: + action: Pasirink, kokį veiksmą atlikti, kai įrašas atitinka filtrą + actions: + hide: Visiškai paslėpti filtruotą turinį ir elgtis taip, tarsi jo neegzistuotų + warn: Slėpti filtruojamą turinį po įspėjimu, paminint filtro pavadinimą form_admin_settings: + activity_api_enabled: Vietinių paskelbtų įrašų, aktyvių naudotojų ir naujų registracijų skaičiai kas savaitę + backups_retention_period: Laikyti sukurtus naudotojų archyvus nurodytą dienų skaičių. peers_api_enabled: Domenų pavadinimų sąrašas, su kuriais šis serveris susidūrė fediverse. Čia nėra duomenų apie tai, ar tu bendrauji su tam tikru serveriu, tik apie tai, kad tavo serveris apie jį žino. Tai naudojama tarnybose, kurios renka federacijos statistiką bendrąja prasme. site_contact_email: Kaip žmonės gali su tavimi susisiekti teisiniais ar pagalbos užklausimais. site_contact_username: Kaip žmonės gali tave pasiekti Mastodon. site_extended_description: Bet kokia papildoma informacija, kuri gali būti naudinga lankytojams ir naudotojams. Gali būti struktūrizuota naudojant Markdown sintaksę. trends: Trendai rodo, kurios įrašai, saitažodžiai ir naujienų istorijos tavo serveryje sulaukia didžiausio susidomėjimo. sessions: - webauthn: Jei tai USB raktas, būtinai jį įkišk ir, jei reikia, paliesk. + otp: 'Įvesk telefono programėlėje sugeneruotą dviejų tapatybės kodą arba naudok vieną iš atkūrimo kodų:' + webauthn: Jei tai USB raktas, būtinai jį įkišk ir, jei reikia, paspausk. settings: indexable: Tavo profilio puslapis gali būti rodomas paieškos rezultatuose Google, Bing ir kituose. labels: diff --git a/config/locales/simple_form.ne.yml b/config/locales/simple_form.ne.yml new file mode 100644 index 000000000..db03c5186 --- /dev/null +++ b/config/locales/simple_form.ne.yml @@ -0,0 +1 @@ +ne: diff --git a/config/locales/simple_form.ry.yml b/config/locales/simple_form.ry.yml new file mode 100644 index 000000000..6fe57b65c --- /dev/null +++ b/config/locales/simple_form.ry.yml @@ -0,0 +1 @@ +ry: diff --git a/config/locales/simple_form.sc.yml b/config/locales/simple_form.sc.yml index 2c4725996..5f5d63307 100644 --- a/config/locales/simple_form.sc.yml +++ b/config/locales/simple_form.sc.yml @@ -53,6 +53,8 @@ sc: domain: Custu domìniu at a pòdere recuperare datos dae custu serbidore e is datos in intrada dae cue ant a èssere protzessados e archiviados email_domain_block: with_dns_records: S'at a fàghere unu tentativu de risòlvere is registros DNS de su domìniu e fintzas is risultados ant a èssere blocados + form_admin_settings: + activity_api_enabled: Nùmeru de tuts publicados in locale, utentes ativos e registros noos in perìodos chidajolos form_challenge: current_password: Ses intrende in un'àrea segura imports: @@ -155,6 +157,7 @@ sc: setting_use_pending_items: Modalidade lenta severity: Severidade sign_in_token_attempt: Còdighe de seguresa + title: Tìtulu type: Casta de importatzione username: Nòmine utente username_or_email: Nòmine utente o indiritzu de posta eletrònica @@ -163,6 +166,16 @@ sc: with_dns_records: Include registros MX e indiritzos IP de su domìniu featured_tag: name: Eticheta + form_admin_settings: + activity_api_enabled: Pùblica istatìsticas agregadas subra s'atividade de s'utente + custom_css: CSS personalizadu + peers_api_enabled: Pùblica sa lista de serbidores iscobertos in s'API + profile_directory: Ativa diretòriu de profilos + show_domain_blocks: Ammustra blocos de domìniu + site_contact_username: Nòmine de utente de su cuntatu + site_short_description: Descritzione de su serbidore + site_title: Nòmine de su serbidore + thumbnail: Miniadura de su serbidore interactions: must_be_follower: Bloca is notìficas dae chie non ti sighit must_be_following: Bloca is notìficas dae gente chi non sighis @@ -186,6 +199,7 @@ sc: mention: Una persone t'at mentovadu pending_account: Unu contu nou tenet bisòngiu de una revisione reblog: Una persone at cumpartzidu s'istadu tuo + report: Imbiu de un'informe nou rule: text: Règula tag: @@ -193,6 +207,9 @@ sc: name: Eticheta trendable: Permite a custa eticheta de apàrrere in is tendèntzias usable: Permite a is tuts de impreare custa eticheta + user_role: + name: Nòmine + permissions_as_keys: Permissos 'no': Nono recommended: Cussigiadu required: diff --git a/config/locales/simple_form.tlh.yml b/config/locales/simple_form.tlh.yml new file mode 100644 index 000000000..884714fb7 --- /dev/null +++ b/config/locales/simple_form.tlh.yml @@ -0,0 +1 @@ +tlh: diff --git a/config/locales/tlh.yml b/config/locales/tlh.yml new file mode 100644 index 000000000..884714fb7 --- /dev/null +++ b/config/locales/tlh.yml @@ -0,0 +1 @@ +tlh: From 996c13a24d941e02458fa21d30e8334d04bdb2b5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:33:11 +0100 Subject: [PATCH 203/255] Update dependency core-js to v3.34.0 (#28241) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4226fcc0f..9e1622680 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5960,9 +5960,9 @@ __metadata: linkType: hard "core-js@npm:^3.30.2": - version: 3.33.3 - resolution: "core-js@npm:3.33.3" - checksum: 08abdc9470c8228b9d09f61e62ab312738681202c4c34e9638889125b304b235f34c4fe22e9d41c20906ac0fcc807dca57c5ff7d6b90021bf64e8fe23461d9ab + version: 3.34.0 + resolution: "core-js@npm:3.34.0" + checksum: 408a77898abe03bf3e5dec2a451c36f4745081cca9022f8bdf9b817d57bb6d3a534d555f47a4b95e1daa5e21dbc79122eac2402e25720d425f5925127e55dcd8 languageName: node linkType: hard From 3b710b96cf4a7ff743313f20b054c6220da3dd6b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:33:27 +0100 Subject: [PATCH 204/255] Update dependency irb to v1.10.1 (#28240) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9308a41c8..4a409a0ad 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -377,7 +377,7 @@ GEM terminal-table (>= 1.5.1) idn-ruby (0.1.5) io-console (0.6.0) - irb (1.10.0) + irb (1.10.1) rdoc reline (>= 0.3.8) jmespath (1.6.2) @@ -608,7 +608,7 @@ GEM link_header (~> 0.0, >= 0.0.8) rdf-normalize (0.6.1) rdf (~> 3.2) - rdoc (6.6.0) + rdoc (6.6.1) psych (>= 4.0.0) redcarpet (3.6.0) redis (4.8.1) From faffd81976092fc5a95fb359ec5844c2af76101d Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 6 Dec 2023 03:44:07 -0500 Subject: [PATCH 205/255] Remove double subject call in `services/unsuspend_account_service` spec (#28215) --- .../unsuspend_account_service_spec.rb | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/spec/services/unsuspend_account_service_spec.rb b/spec/services/unsuspend_account_service_spec.rb index c555b661e..2f737c621 100644 --- a/spec/services/unsuspend_account_service_spec.rb +++ b/spec/services/unsuspend_account_service_spec.rb @@ -45,14 +45,19 @@ RSpec.describe UnsuspendAccountService, type: :service do remote_follower.follow!(account) end - it "merges back into local followers' feeds" do + it 'merges back into feeds of local followers and sends update' do subject + + expect_feeds_merged + expect_updates_sent + end + + def expect_feeds_merged expect(FeedManager.instance).to have_received(:merge_into_home).with(account, local_follower) expect(FeedManager.instance).to have_received(:merge_into_list).with(account, list) end - it 'sends an update actor to followers and reporters' do - subject + def expect_updates_sent expect(a_request(:post, remote_follower.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once expect(a_request(:post, remote_reporter.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once end @@ -73,19 +78,20 @@ RSpec.describe UnsuspendAccountService, type: :service do allow(resolve_account_service).to receive(:call).with(account).and_return(account) end - it 're-fetches the account' do - subject + it 're-fetches the account, merges feeds, and preserves suspended' do + expect { subject } + .to_not change_suspended_flag + expect_feeds_merged expect(resolve_account_service).to have_received(:call).with(account) end - it "merges back into local followers' feeds" do - subject + def expect_feeds_merged expect(FeedManager.instance).to have_received(:merge_into_home).with(account, local_follower) expect(FeedManager.instance).to have_received(:merge_into_list).with(account, list) end - it 'does not change the “suspended” flag' do - expect { subject }.to_not change(account, :suspended?) + def change_suspended_flag + change(account, :suspended?) end end @@ -97,19 +103,20 @@ RSpec.describe UnsuspendAccountService, type: :service do end end - it 're-fetches the account' do - subject + it 're-fetches the account, does not merge feeds, marks suspended' do + expect { subject } + .to change_suspended_to_true expect(resolve_account_service).to have_received(:call).with(account) + expect_feeds_not_merged end - it "does not merge back into local followers' feeds" do - subject + def expect_feeds_not_merged expect(FeedManager.instance).to_not have_received(:merge_into_home).with(account, local_follower) expect(FeedManager.instance).to_not have_received(:merge_into_list).with(account, list) end - it 'marks account as suspended' do - expect { subject }.to change(account, :suspended?).from(false).to(true) + def change_suspended_to_true + change(account, :suspended?).from(false).to(true) end end @@ -118,13 +125,14 @@ RSpec.describe UnsuspendAccountService, type: :service do allow(resolve_account_service).to receive(:call).with(account).and_return(nil) end - it 're-fetches the account' do + it 're-fetches the account and does not merge feeds' do subject + expect(resolve_account_service).to have_received(:call).with(account) + expect_feeds_not_merged end - it "does not merge back into local followers' feeds" do - subject + def expect_feeds_not_merged expect(FeedManager.instance).to_not have_received(:merge_into_home).with(account, local_follower) expect(FeedManager.instance).to_not have_received(:merge_into_list).with(account, list) end From 5517df61de1e867afa531268755ee893ffca3c99 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 6 Dec 2023 03:44:51 -0500 Subject: [PATCH 206/255] Remove double subject call in `services/activitypub/process_account_service` spec (#28214) --- .../process_account_service_spec.rb | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/spec/services/activitypub/process_account_service_spec.rb b/spec/services/activitypub/process_account_service_spec.rb index c02a0800a..09eb5ddee 100644 --- a/spec/services/activitypub/process_account_service_spec.rb +++ b/spec/services/activitypub/process_account_service_spec.rb @@ -129,12 +129,10 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do stub_const 'ActivityPub::ProcessAccountService::SUBDOMAINS_RATELIMIT', 5 end - it 'creates at least some accounts' do - expect { subject }.to change { Account.remote.count }.by_at_least(2) - end - - it 'creates no more account than the limit allows' do - expect { subject }.to change { Account.remote.count }.by_at_most(5) + it 'creates accounts without exceeding rate limit' do + expect { subject } + .to create_some_remote_accounts + .and create_fewer_than_rate_limit_accounts end end @@ -195,12 +193,20 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do end end - it 'creates at least some accounts' do - expect { subject.call('user1', 'foo.test', payload) }.to change { Account.remote.count }.by_at_least(2) - end - - it 'creates no more account than the limit allows' do - expect { subject.call('user1', 'foo.test', payload) }.to change { Account.remote.count }.by_at_most(5) + it 'creates accounts without exceeding rate limit' do + expect { subject.call('user1', 'foo.test', payload) } + .to create_some_remote_accounts + .and create_fewer_than_rate_limit_accounts end end + + private + + def create_some_remote_accounts + change(Account.remote, :count).by_at_least(2) + end + + def create_fewer_than_rate_limit_accounts + change(Account.remote, :count).by_at_most(5) + end end From be6bb1a10d6f1f23151198c6487f44145a0692ee Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 6 Dec 2023 03:45:19 -0500 Subject: [PATCH 207/255] Remove double subject call in `services/suspend_account_service` spec (#28213) --- spec/services/suspend_account_service_spec.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/services/suspend_account_service_spec.rb b/spec/services/suspend_account_service_spec.rb index edb705008..c258995b7 100644 --- a/spec/services/suspend_account_service_spec.rb +++ b/spec/services/suspend_account_service_spec.rb @@ -18,14 +18,15 @@ RSpec.describe SuspendAccountService, type: :service do account.suspend! end - it "unmerges from local followers' feeds" do - subject + it 'unmerges from feeds of local followers and preserves suspended flag' do + expect { subject } + .to_not change_suspended_flag expect(FeedManager.instance).to have_received(:unmerge_from_home).with(account, local_follower) expect(FeedManager.instance).to have_received(:unmerge_from_list).with(account, list) end - it 'does not change the “suspended” flag' do - expect { subject }.to_not change(account, :suspended?) + def change_suspended_flag + change(account, :suspended?) end end From ed7b5c091b62d63e695d2f1ff946e021fb37fa18 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 6 Dec 2023 03:51:09 -0500 Subject: [PATCH 208/255] Remove double subject call in `services/delete_account_service` spec (#28212) --- spec/services/delete_account_service_spec.rb | 25 +++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/spec/services/delete_account_service_spec.rb b/spec/services/delete_account_service_spec.rb index 68ab491e4..8a19d3cf7 100644 --- a/spec/services/delete_account_service_spec.rb +++ b/spec/services/delete_account_service_spec.rb @@ -27,8 +27,15 @@ RSpec.describe DeleteAccountService, type: :service do let!(:account_note) { Fabricate(:account_note, account: account) } - it 'deletes associated owned records' do - expect { subject }.to change { + it 'deletes associated owned and target records and target notifications' do + expect { subject } + .to delete_associated_owned_records + .and delete_associated_target_records + .and delete_associated_target_notifications + end + + def delete_associated_owned_records + change do [ account.statuses, account.media_attachments, @@ -39,23 +46,23 @@ RSpec.describe DeleteAccountService, type: :service do account.polls, account.account_notes, ].map(&:count) - }.from([2, 1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0, 0]) + end.from([2, 1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0, 0]) end - it 'deletes associated target records' do - expect { subject }.to change { + def delete_associated_target_records + change do [ AccountPin.where(target_account: account), ].map(&:count) - }.from([1]).to([0]) + end.from([1]).to([0]) end - it 'deletes associated target notifications' do - expect { subject }.to change { + def delete_associated_target_notifications + change do %w( poll favourite status mention follow ).map { |type| Notification.where(type: type).count } - }.from([1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0]) + end.from([1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0]) end end From 0e8ba19113182f74a0adde0ac75a35694833316c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 6 Dec 2023 03:52:30 -0500 Subject: [PATCH 209/255] Add spec coverage for `CLI::Emoji` class (#28182) --- spec/fixtures/files/elite-assets.tar.gz | Bin 0 -> 17590 bytes spec/lib/mastodon/cli/emoji_spec.rb | 54 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 spec/fixtures/files/elite-assets.tar.gz diff --git a/spec/fixtures/files/elite-assets.tar.gz b/spec/fixtures/files/elite-assets.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..7b4f4425705c62fe4b538fa52148937e51a69552 GIT binary patch literal 17590 zcmV(nK=QvIiwFRdRBB}a1MIp5RGrPTD7bO=;0aE!;O_43Zo%Ds;~s)r(2ctVcMCy- zyKf-424`c#f6jUL-Z^vMc{6X_H*03i)L!-V*WJ}6-Bs27_1a9v&i1D6HjW++#-^@j z)=bWhR)GI%U}0h5;@}|rtK{b5{9DPw_V@bVfP;&bjFp3vosENogPoI;jD?l!?FS%Z z`7hVxKLHOncT?9lRUB+h9qpXF-0W=rbGkP&OUr-3=kKPF{ag9}7J$P;06+r(il$~{ z%Iah~WdDG_+5kvz$o7V>Z}?V+V*NkIQdC1j?eA}Y8v%Yp)qf&^`A0h@06=8s<iKR= z>}+qrWN+%`?%`%(Zf@#sL8+qt588`2L;(PB|DDd+)ydPs(bUn*;;;V4H{|-?^}BeO zx|%w^d9?*#Q{MJ(MDo#le1Fpj0DxRo(ss~F3Ar${u<@|-b8&K+a(p)D=I7^?<PewQ z<Yr+MXA$RQ<lvIxW)zj+kYr@#mE>aKVBr)KW8wIpo8<rJf{LlPjD@MWg)8&_x;*ed zihpia?thAZZf>@>`1k%V)8Jpg|HtE>jhD>9-NwN}kd>Q-m4l0eorRT&larT)_ia^> zSy@@h6lBFj)x>3FwIrFmP2JsHnf|jd6I7It<xuo>V^h-5vsRLpvs3bQ<5t$xWKm_& zWmWPObyxKjlTcD;VNtTvWmnLYl2nq^bXU}{mr}A7Wl@yS5?6gIk$HH@)ZZj2=>987 z{}VBb%*p+)%=q_gA}FdVD$3xg>?*I|=A>rJfz0vW)#yJA`VT1unTz*dN&2V!Cdkg> z?xOc5QdCq-!Nx+DOZ0Dm%=zDy`p*phIlCeMUta(J^}GN7DE>KES=rhCDgHURIXM3R z{r~?Ch*nXOMnfk0%W=?TWhDOEw}bvdMEJMo4<XaBw*uBmR8bTF_#Th)WD56ICo_{# zQv?8fKfck0y*dA1^apP<`L<q1CIA56Hvj<NIlEm|;H?A6Sw`3GjrZbT2qi|F^_JA3 zbZs<r+;tQc`2ObE=1!k2n7kdF|E7<CH{aW<gN3^(nYV+zqZ^;MAjRJ(_}<?CYG$S& z`x}Y7ogjsdq6(R~ldA<8Cldz~3xyE!+rdS^)!dR#O+xA)!{2Ix6xQzU&V0<wUS3{I zUhGUxu2#&fyu7?`+dnfK8{-=VqnnSTyQw#$qZ{Slnfy0C5*BV|t~So@HcpOYf7MMt zJ9)SZQcxh1{RjBFAa@(ff0yLw_7Ah(3}pVRhnba$h56rj|Hb~VRz77{8;du|fAJS$ z6=429wEZ_-nEy$czgx=u4^xGZ1(^SB+Jul5`e}3l01<$!gs6r$)O?Ol%DS}2{;@-s zS7p;!(kJ=)uMQ(=X#E6VC4GZrSxn%uzx_5(`~6$tTS5k}m5j{CWTcE2O2U_K3T%X~ zA8Fj`lgx*saj@;9`k-dM*NHZV_mS1ba@lQm6mM+uZBAAjcfE8i_S`{kF3pu?YXkM? zt1BM6JdPKtA@j_;c%*7_N!9XN3m)ZX8){7Kaw#?PI&&VyXGXJQ82$(18PX&^Mb|I+ zk7tajYJmszseT&0MC}?BsoPGU$%IMNN=w~ulj8*+e*M`pO<#y_AN=tpg;$A%&xr=K z1$WJW#+#r*=9tKW?<eI8*lt+^tP>@;=PWv@f*HCsPx2!@J@!5>c77W-Z<*Y?f@ah# zMmtmN#gC@dpx>RCh;tV*=D9xzw%Vxbkm46ua48;rPia$n`kOtLd#+H;Le3uvyC!<I zoK!kMMu^dzy7wIO12UeqdT&TT4BRFf21fFN#o*$aYI*A^`vXu_LJc=@n^e;Y2^dAY zZQo7C=6H^Ay6KgCrb1F!yYnSgw{bf^2PkC{3eXW8u1W<g8A7l?Veg?x64Hn<>5=gc zT#I%WEA`fG$z`N*EKwfH)yh$Gs`}t>Z6Sw)wwp8auc}0&?9(}PibJ{8_8I$#n}|Zm z#2yqW`dC5U`7#5X;2&$d@L|XoNco@G`HYF~<#^r~cRBk!=@qLHHf0{c5<rm(;6tJn z5G|NlQm+E}FUP+hSOP#}xO8q3cT!h`s0?MHmce2k#|WgVff@v0s~desL@+{okP?GF z+r4Tq+i~`>&(^_o^f>XRvrwv>lY52+b@D`O|4HNO4TQTx({8a{t-MGsJR)yYcG{|5 z*K7Al*XwC@vMuh+NSiL5n&(Th94O*;BbM0DxYZeoq{=%(@=EF=1Nq0M?cIt30MH}d zgIUJYTl?<*I-i9Naq&wKv#+3kXlTZmnb}VNwf)DO?otKj8iUc|kfxWKTqAAz3Mhah zVj|#Mu}W^T=qz69C{lsp_^$Oci__0B)Mwhp&`CGk%X`h*kxz7Up~~Uf$UrK=Amt6j zzLbD@F&8(ae7(KP-XQWU#bPCMwzXyf)TfMcS#7-Dr@8)0;SQQ=7Ixlpc;m6O&*koT z6o>Aa_1IdSzjCXPwD|AWR7~vbj^v?+0Ccd}wJ9r+O#T7-gv-WES%4z;jPppjgu-?h zZhlJ1P^mJMM)&sM&fL;@LkSl(=*@9F`BLDu-TM`!0RD&UGSlM@KyRrN7rfL^YRYhP zsB#8-c!-C3{}pT=#8+dko}Ecp(4rcYHO;Q1$Unt+k?mcSq&0PcH86%K!pEO0C0||E zj4cTL6rg$kei4v8JETf*H2ysYdzndUFYum{RCGl%^cSH<N66t>N_*(j*ZNcybBl{< zL5;w6ChgH0GBgo<GRp51tK`+f50?sC1=i-x>u!@paSRKZsx0B!sgt5GbD@)*V0J2f zM;W!p=p*Yy!u;xODO;1@zqWov`s^V~dQqiT8>IV^s@T=aG?fDG54P}8z1>hHFO}|8 zeoc<5e3HYwmY@uB|Clqg^@LK|<K=2?UB<@7R&U_t^@EMM{!Df{eZUG9Fc|)whY=+9 z61aS+c}578Ixhe)Gg!=_JEtxGzJq`Y)fD(Jr#cJ0MI!xKXA_jTDdW<qn3qMj=(2h0 zv~=+^F_Cg0v>UeXz^yCFxv<Yk_J<m6uQcNQ^d;e*4r#@Xt5}jmvql*lo8sr+RR+D` zH^+;muV?2kHP=((7#<sKHm9}a=PzdESLj5I)@s5i8TOHbPaZu6k(N?3&^;Afgj8v6 z%L+XaNw0fx`pxf*`F!@uacGoMutGorF8#6IZP8_1f>dd`bVeRRKi<Itz;skeipR!| zt)^h7^&{jCPc&SyO5pj+qcE-C3pZc=vi{}Q8$p?w3!7jPZFdbrS1h_nY;iH!FPYu* zT^h8*ZnT3%Y8DX~y2~ixpZ_>lWJ3-Ll|MZBQJk)}Fnb+Lk+VgY>C8ZcWx*{Ceuf&9 zD9|G0hnv>VV`$u{PlA36=@_Kl9HPOb0b||#2277x%kB_zh%;f}+|Tw_d+E}w3<59h zIRDw5N<D-s_75LwbbgJoQq}#0Q%m&-n9b#Goj4;|hFc){#>F^_ksuy#ZGDeFdTa)I z99^79@Je<hM|#r!xl)=fOO6P@wjZaao1r*cN4#KIML=k<^YguooXE}jyu!`@eNS6+ z(0J66{qVD@idNAy$GLb+sV0d3sj=gf5u>f8XWzd@-$+CXp2Izij5)}mD2P<#uAwbE zYhL9dy5~XO>#R7`ap(A~<&hu~*%G!wfB4-O>R5dB*PHJ&7%%V`m?8OziI*2^v|F4Q zLc3A`vEzMT-uzQ=t?rH*aeK>eBLTNPWH^8CSK>g4Q#_9zLAATQ6v=ffxR-+mb+NXS zjjP(1YQL*cCpVZ%EzNlWTu@Gq=CO8?3=zu{A3wiCnDfo3#oc`1{g=mn&<pcolWj7w zPRocCk|kLIojTp`UR>m#=Nf9MulH>*lK~lQ<cLRcJmI9|3F~%Jr;%bVMJ5bbE9fuH z4y*Mv%DEEN%0O@*cUR3f*B)xXMo!V0Rq4mI;`Cgv$H40!XF2CSOAc*5S&A<JE;1bG z`;C=5tw3#U{4*n*q-+kTNu~GvN8R_!ldV>y&u%R?lm1MlXGJ<?$9NLTTmz-*yK6%v z{zr6cgU_qY)oMPq<O#L97n;quSV5j4o3ZU)p%XbgtX#JXt4`;}9RU~k^FLl)xzelE z?*dj{`(u<l^o?GX?luBncFra`ZZkj9diP@YMIwa(x_b)zE<6n*?P0@q!<_{7Ngl6D z*NSmAU5K5!7TaT29Lcjr@KKT>&k!8r$2}TJtIuyo06X_=A%94tmjc|jJb!ce<k&pG zfiC4f8EfCyX{DXh@BaGmxSgr%IGFpznko6kN$rk*uiUR`VcM;<=rl&{PIzad^VPv| zzC!ePQ_(`YnxvcC?m?gyV+qb1lRsrBb<7>bSgYk?wZ`uTkGsy(tVus%;GJCR7Y`Kr zP19I{fWxs#;IZ43olBz%$m6Nq5E$q3G1t&;|CC-s>c~yxXm;*-s>|=}^zigW!iwpx zCgSMj=l*)A@a?SH-MO2-*%65c2}TT@a4w!Wt2@e2{0!q$liyjx>!L&ZqYz=7bu=Nd zMujBqF8A=X|H0E_L(Me`h}ZexePcwYzsZ7m_AT`O>2?F!b9x2TidvbV->thsF7GU* zgK)F-k=yaYO;4F*4(YK<$IMh^k=CFqiSFG-sQ*iG>3Xx@2D!&8^V(TQ@!7l_O2Cqq z=3Q{x7?ki-*&&{#<yuRwaFOGd@>=*#<T~Vo*Q#~C#wQbrwBN!Bsoxaki50$#kOrRg zviHD!2+MP9#2lviu-b2B0ejCQ`P68mHlcXN*rGzm8k`uJyg$LW(gXaRc<IpL>G7V| zHOy4&5aB%VIlg4JT-n{j-F`^4&}2c7M(5sa-^e9(`>Wr%vj1F{#VbauX6VRK?tK`~ zy}>MBXcMW(Za`%)N2V=T=%2L=_OtTD+EyB&o2(kUaV_rF0Jr%%><hQTw=|}oY4CKg z58}JW_-z)#!a*fGxRoi@YBfnYn7sMC9=pEY(7=nNR=i}aB%d}q6c-!EU^B0|Z0mEp z-S-$5HBkU(G6KesKaz@wm?5Iz)CewnoH$duxyp#FQ#Q?O#oA-AeyZ=aT3>hat@L~B z*f_2BLqeQw4a$6{MFboZ_etFU+6Y*Q>Qv6<IYS2?#+)5^b<-)%(OGEz9N|x7bEPO} z!#)sBT|E@`XFbA88hyVGLmL+SCF7Nxj~i<GK@FNC<4-s|oIwiU6Ctoj5b!GQ<TI8z zVc;U;aDc!e-C$_v2KiF#%CuYE^!WSNAyYa%wGDvYXf^scg6H_G`?b2p$s{$4fb<SU z@XzuD3bbsOlqfx+TCknkSinb?`pbQ4yDj)e<cAPzHoIX>$z4L{9W%4Dj!FM@i#c4? ziS|6EU&V7d(~Mt_mbtH!orfspdT&0)Nby2{A^b$0;5|}8pj^6sE)4nI08%CLR!e2d zX(0lDnn++_jHP2s^igEN?2SlC%TaQ+-b;TNgrC6O4s2(Enw*fl!ShOhB>Ne(O$}33 zx2j!#RKYwq>LPQlC;Q?=dtCPo+75VwQ#0qL8p}T<7SQv&()&<9pP+LBRT%QwWuaIi zJx!V96A$BfTw6`>c#Sb7%o!(=WO4GOYrxC=LzK?v?P4nMQ}W%P=lBmi_sbW1>YrA` zN`o*W!g`&v34fM+Z9WhphZiry9fG5IA3<FXNrem8^>^wx-{+jaMPlq9hGK)y`KA#K zxvRkZ!kQW4gx-DW8OrV8RnEx2CpR#TDWT|g-`x7cQL>mzDpL&!3*YCRp|b^tNpcL9 zAuR7#E|o`%d8gon;<Ig0Kz{*E2s3|SQM=3m@)2H#Ir>u=Md0mBvAkw3V*-9WlyFrR zneq(LJ)hp|=yz2a+Xs{o=FjC@GBYF_uO-51E6+%63K@zGNJR6()yV1uOJzj1)e#u& z*TFABI*(f$on{}1M=i>M8g5N+a^V#op2L3H_#PzXQrv*7Mr&UTq4#qiUQnLA<<shK z?U1pfSoyv&q$mDLFp{W4NfFa9Gt`y3!8jogtSB;OE(-ng>j9b^U8pnS9XK>J+>(f_ z+YvO3X$=SDu3Bukt`z8eeGxu78GZ>fsvTu;QEJ=Qh%V48YlnO#07ny91j<4E#9`dX z&UIf@3e-pW!=Wr}rShkh2{A9Ff;_K7%fZv|x$-8v!1qF456b;zslj!R>UPYd@rWta ziBEb*c5GjH-hWw+$hM&GQ0;Tx$`wR7=xeC0^RZF-@kvGWWD5Hj{vRhY4Wovs;;2?2 zirefWR%C&cCP+H;nCD&s37kdBUt~iC2%1!ZQo`1Q50rri^)grN1~yWrKgjlKL(pCE z6O-!3<%-AgzN9iAc$X!)Y#xv91sFUZARG{J3{QSF7TQ1a8}eIw#t1M#y|jBs?G(); zO*_KHF@~I(-WB&ia9V7CjBBlqOvjvcxAd&8_q=Lz`szeY055}vo<xmokhBnXlaCMT zIKxN10}9&t2Taztk^^5Q@7Arlk9@UjIRl}tkdB>}cOf3JdlU(vClY9(ok8i^c6Me` zPX!D4Vc?Go$+}jQCs}A=7a~4cK-$LT;T`8MKkI{+>iP>I@>Gn2Mj*Ya794vx@DIEC z!&9xmL+m+_S!3J(@m%{g4FZ@p5i_;y_we-SSUp>FNb8&zlBnS&vOpWMjJ08(opn@m zx~)o!&D#Y!-a>e}TRn3+%q9)@$U;0TgIkvvP$^lTP;H?m)&M<ep$7>sBR#JnNEOOM zEcIacMTf?glzuAQT&Xa)@eoGUlA)9Z#1Jhr4h|-fF|c@n5rBZwH6G%7)?9XryBTYp zea=CX%a|ryGwMFGA0wkQAotnYlFRt%T>1UeATzz~{zezEUyJ=Av(U?ZqHb4^$BF{9 zez?BtdL>sYJB{)Z3r5LB6<()`!1?dK$Hnpt0ZG?3q3Y|{Af<iC+Vxz@2HdyrX$JD4 z*pnD#?%S+k9CtPK(3q%#TG%)`;!|=#ctJ`^3awYA%Iy;yP)MN=k!nVn!fiKQ9EI&= z^OVb+nW@{$2llg>avY}Bd9(h)&N62PawH(~s`H_)0RZzD5Kt$gcXU;lR4g?I*?gGr zuUxY~lC~C{QeWpdanX(Sf5p4t?BKSJ;WgsnfB3;{AS0|)RK-tTsAE>CQL5oXy*Qsk z)aAXgyK9WF1dvOKNAISd<%2@5eSgO{ugB-N0I?qBS)F!>;g`V(s)jv@PXb($$>+h& zJTzFXg<tJ+PC7TNwx8nR3~O0qAwYdwfW}$)c#T@cd6B<a?uFsDFlkkM%kC)0kj9k5 zyUPR;+Cr`mtj}5ByFq<0A^oHhDh1{?T>bznf|rDbpTKb`y2>))q<YN5O?AfvJ;j+E zp#L$;h(Uz#$n?}ovXO<K_t|ConBd^#Q(cnuz9Uc4iRhxo%a^Qnvi(Ue!l+bxX=&T* zH3mnuTAOMjgPa5VD8Kv8h$*TkksiHNFLx;4l0tbRk=hVh8E5hqY{1Z5_e`O`QHtRo zKhjs5^kX9TouQ$%$(Qp@mpkDL6O`uYNi+wxfamtC&ZjRNt9%Wb^z_Qwn?WA>IA(=s zm&@vBM;Y3`@P?7@<2GKr$4aSFIZ=*E<R8RU6bay&kbu^GxY!71uuVO*7v%3k27f+& z{|pD%d19NXo@I{hyy*Jj+rd@ZV&~IF5jI+P`LdIURdj8>5+PL6?{ah`>t&eBiD6I; z|1}h2iiL1f$e+E^zb$fR;L9M>x6Sad6T5h$)5^(s>zO8jn_U`%*Ao6U#ah46RY<Q8 zBd*_o1|Q?<WjVE~8}5Mt@duCDbV+XC(WyqVQ_qvtO?T!1{{chQ%Auv5So08j_$r}K zlPMAMRqn^%GIRXr6jK9o_HC^<Y=8If;150+gp%9#*o@IoK!IWI4b%szgGmQV=pQ`a zvj*57$MPlmqp#SVb-EcDbA+sef2eNB095tA@qUzFa)g~Yq(B#%1PFiH6B+mNybE8T z+zOr!_$Ik#Ngky9-uiM!k$eGx4VX1gEa}ckt$V)oPQaL!0BxBWpE=tr1L`MNUy7xg z-Gs7%*CI0r|G>Xs)1jXV{AV0LMX6WbH&qON+qm+*(`-^h;O$brxU~`+`g>X1hl^I~ z3tT6Xdn$X~Q}H~Z;o(H5KqZlC+}61ah&R$A^JDvAG(qa|v6nWJAsY)!!wxud0pY$; zDkAuzY8KBQ@&tt{KG6<<!kd}f|9}9pvPO;YZT0ri<@h=zyGj0|D)o=BJMCQ~$5gnR zRa208<>g%!=Xrh@86|O$A4Jupns4FKO;hZ_AbtFrzhdcZ2wmW@Z}Me_9U&qTtx~HO zv^Y#FUx;ZB$SvebLlv6+7B5hsmm*i6^|fl;vP?}+G1*XsV*bP!9RMX_waMr8upM4; zV}v2}3ypDehMWVsTK;+e*DlKT2l0w3qdOAqz#Ol2x>}=SLRF0J;7@#W<kVY7^F_18 z>O*S~hnDs$>7L`}6M~u1?cB6>TvS<DaK+K|^y%YGg}mObW*uiJp)8RYx$!FlTTTG8 z_UKFBroi*HBn9|xpGV+n*r3w3>J}eP$UPJQ2vA{IGj{j>ohVq~u>`43__jrWJAwa2 zbUade-t2&{$UR<iT`EFrdU>{XYl>HQ2Nj(|{v$|i3fAR<e1NkzABhiE?_#JS#ZF7g zMAgw+z~SaCnV|~XBjJcG<DNf&<J*M!Jo<C|AADLo#~jY`F@RHFe}uo+P{74GV5%_? zprNc^wWKa&o0{UFOi2v>^;_d1!Tpsc#$Wq2#FW(~;<pMh5z(}P9NL9|ZP6`0n$Q3y zpvYMl%;0YcInmui!vqxKf~cTK*OgIy<0l)HrgxPr7#bE~_vpWp-E<Hk=X#iFORx9Z zu610aZh%o3dveKqw(stUG@rA=ob<%$gBA)ir%-_u6dFOD#~v*m#!mxI?bDUo>qNY% zI(prh_oDi$X(J;@UZ?$ZEuL5CP!96sOJ2hpT4^f6Oy^5ZfiJ!6#;D;i_gI8J5L{`g z{`Dgl$-YQ>#s+epdHXDoPW~JM0-l|cnPWti&rDlsJSmT}E*!7CUP8&{2f@I8!;XOQ z#$hq=svFeC^14F|r}YK=_DKrrOzUlmwj4B+40!@q<CAkd<)P}1|1*r^<AlDUQ()j2 zI61AtpvQAOwS>t>I81~1xzpQ2f-T_O%-H{S9qYa-sem<;S#pR<A*ol|ZBkPLKL!m= z(=8_K2n9|@;k4=7T7hOk06G#M`py8aE)*`epzqJvm|)m5ZrcYu(ZB=fc0Y)DxwKaM zOv+`lD{Zv&l%_Q<a2vi4kwio}m}Z2$5jc7Tr}aaZ*PFh3SHFwpljOcU=<$esbGy1k z#Y?ZV>?4%2<qfce7SNODAh~S`RjzMaMyF8()kv(($I&8{nvrhoY#-&a8R@eGO^8O# zetCEifevPb6+-2PI+%Y1Hn?)qqP@yBELM|BH2?zEVu=Atm#0^#U|r;Zd;Q5(%!@NW zW2d<CRzYlfc2Zz_VRn06Wd(v+ZyVVRO>1WEhMw=!A0PiG1BpPbA6DzgVCKqQ>5O3o zBfW3hWj9@24K(w5hf_YSDS6$m7K%hm2~22!b-SOv49y=&MevXjG0rqgj2QutD$i#X zWAu9hOHuwNXrcbQ5#vW(uiI4wLsci5wTG#WwMpQKaHaeKx9@Lh8EDerp9!5*;>~U* zp*ai{)j*suX5Ieq*IzpgNuTsjrI)v@Scu8m9Ul@j%9bOApG?)IS$EIdW}%l^urXC= z0CGq_X=7o15!SznfQ>4H7YyijB|}fBIrspbw<tA9*6`huNp<;(MlWYx>*cki?)+zg zksYU??pgo4@64?`(((7Q`7&fX;AFgf0I)GK7QiF}C=f)r;So1Xx#n>Z@8VTPj0S3T zT2%T^n`{iN*r3*iQT*zeFH>o_8Oz$IaR9!3sRqzpo4ee0&Iwyv5g=U;8wY5jW+$>o zq;(|V1wAN`q{i^D<EjwR|4Ffgm7MI=#RSeoqgQ(wz+2y0>OR+#BNN4WS|g0MvJCcN zSTxkg9ny`ZMC55t<a`nESACg?wQb+#SPsL&-1o>Q2OV!S?y?E(bkL%`%?PflbWhKG z8vPyeK?C$D+jA2T5fyGdwV}3^P7xVye!Xt6QKoq3<~(Ty5dc6oocX%e7M9lA^6e#l z8AVn8?l7b6y6Ynm^%C?H8lx~Gy|fl%yfI(7refNl6TiNT)yv-4<kIT+JGwMO9tUDj zDwLfdtpew!7N<y|SalfRk&yq&?n0Grvd`@W()dg3?4UUk!0%SUP|%SQil9@4Oe!*) z+uHyN&Wx>kzN75(9!*k&@3{4fx3Qf@rF_$zXC9W*Ls5Jv>48hUY+k1&bYcCYgVn6j zGXjQj6zPZ6k$p(GkooeGI6i|8KZ>TI`^us=1&FXsGQKWTy6<E77j+Bn5;}DkEDf`t znSrC~VbXT&XuvSCoOy}3J(zEc%JsMV>VJX?j;7ydC@D5Z$JxZ^-YmH5fQj&jeJE38 z9!(@{8J(Keim=MhldT9I1}>dwKrr{T65miNr#4UmnDcVND?(~RWPa9ixfj0}Ut1J; z6Cquf6Pu{X?0<xnaKy$0aC+J`4LYA<D467$utKSu>lq2)rRr>4D6Ei8{khxg(IUAN z392z@FZ05;-NZ>i?R>vI5O=!Ao*LQ12~O@gpW?|PO+x;;<VHOR;snQ77Pqu4^4anR z&56-gzOZ2*teSkazlEer;#oygHf^~+XJSj4T#tE-Ma^c4W|697Ye9$nsP|vMwoa_T zm6p#4?=eQTt#o^5Wi%EaHTyd2zl2%m)I^x)OLdNiHf0yIgb0@UlQEhl`|bmsyf|fD zPB`+>aN)^xt{TWX^iG4$pTpOR!U2a(Pufd&ww%D+rOB>1{+Ttky1Tnjoy>#nDuUKp zBk$psuE{(LJMO3PLCUo^CKkXRX{Nyh#(9gX5N+ZZCPbPSE0=+&kH!C!Xh{v>d}-cd zwlTRP2edT}=$M!gJgI-o+5;Z|l-b5CJO85dn9lS8{wXgm55vs*!Gc?$3Wkr~PtEA3 zENh~J9w+tz9_8fHwh{q}My+Jr3qU9$!$mjf`#V(jkn)4Zy>~iu!7Q9Oc_Nbsg;4K6 zoY7O}rid$1^(L?p+%e*r5XxQi-~IJmS`Za$DXvQo<Lpe@Y?_yZeYY98+-7SX3tkN1 zs46o+hKdY|FPIWe56N!Ru%l$}P;`+TzMCnc@Nv<Ncdu`fQ0MdeEatB{!Zr=Ivd0kU zdpWarCIRVsU78{XF5@Y#NnoAKFyY_hu5}|Wx)-j98S=X8^67Zx*M~z_gV#k+Df>5e zW{yXrNMpu7r=p~&={wYwJ1_dF_#?jl>Z+7R(n^}VVI(EIjs2Q^BxV5M8Ilz-l^JkZ zW(3vfFb9ih<3YkaLiiNvH7vZnc{+t&kQt?@r}lDexY>O-A~X_JL`KEX?%Tx~PLGb} zs@8+fuRP-OsVcGw`}TT$GM|dKKhc0l78R(tf}riL{dT|gBf<i|q!W~7^nZ&8a+Ue= zP4a8EKoVbn1A}(lpmr&y=`t{)roW(<Mieth3e4QGTj<;51==nA&XXE08GR(f{uxg> z(O!-Ai(S+bM1)mnyVmEo%HyA2#JrZ;Ne?jU7fbK~w7q7+2BG~|z3eYjD#xHi2(zu0 z>iF^{g7gUrj#!M6CUywLwud=v!ZFT7BLJm@GtPCz_?EPBicSI$xD3RLrMkd*sA`=D z{Gba{L_LtPX=|YfR};=u<F3*A?UGCsCUjI*?q-~5r1c)9@hGmFb5JD=DOIRv*N-N? zx<NbU)I72H1UjS|Wv<z!GkpcX7K8r+OA}8R{0TPo$PzhS@?&T9z)dzmgoc|mEGz~& z^i=ucA{~1l-Z#7}8Xi(*<4BBC_&`x1b-dnNzPQRZv3V}WS9{e!)`BAXa@qspb3eZp zj*}SMs4-n^YQ^bHzQ;vd8IO$!9~O>{%V_TXtt&ilB}UFpr^w!m0-N%Kj-X875fk)% zpCj#V6Pd;g$^muPz=)p6s_L4pX8ID7|H~3a`t_I0E+lh!bLv71m#TDu8tavvL5kWG zht#=C{hbEf!O_ow0HoTH`aXmrfKbYfRvu^QdWRRc!-Mz=d*r<wP(V-DK3NR4r{+j8 zU-o9KY+r`wga<)r<cV0s(6+q!NshA~ue>&Vz81M2_&E^zUi9aVkdk)DRGFro1y+nA zW>iApr?wo5GsJihY*JvBYuTn*b=Zs2FNIXy59_KY$Du=Gdkxl~P=Ls>@MN$Ts?TG{ z;jSZd0c2vE%gc$Z?MP>nnB#G5(A5qWu5bh%ge)e_ipVxvX#8XV^SeU0Y!?bwYC8*O z(CMa?i|U9TSrW+ML^>)I!w^+@)Ns`99l-9or^-<Dn-${2(A8H^a+()Zt??WcrV#9D zxTy{O*;B@BX$EXXXBt-=Ds&Le;G@D$lWu?8Ku$iDsQs)-I<-o<f_SlPwoaWlut;@p z+lClvICv0+#0)>~Q80J_ECqHW#dTm0(L<KPvPYyL%fOI9zUsxlG*qCC)=Kmr_81q& z%gA%cgb$PcQ)_efS?>xkrNTlQ6t@DoSSefkz|gmE(ek8%0Sjm%X3R%w!4Cu;j?nxe z6{$sTMj+Kw<P^rLAm@_zTtj7Y!4j`$;iVpgOt9D7Rw5PR0ETVo@E!q3+%R?7R{NNA z<bp9G-<P7nS&_=((%X@H`Ab!-y^k#k@Oih|%*Lwe>K0)f0Nqj}irK`(d;(2|!OyQ% z1o!4&p_cggVq;bWx!6OK5q5q+`xlo7IT!vkJNTG#Ye5y=&CgJrbULvN5y_%A3eq~Q zAk%20GDvG15l`Vl7it0EZ3;<Ck=#SEMKxyB>5&x_TMz_)0iRRPq2El()9z2?xER_k zE;%RgUDTLy8Tw$^j-fIj3t8yaaESdtF2>;e21WBySFH=}7q#L$HHN(zzXw}2Z`rP8 zL)@&&-k;edhEepjwvL{5bcO@4PjB-6DGzHKhd;;?N3_%CS2#2%-;%&u?8Ew%^4`nm zC#AC2{qQuVSObDS>snG=*>ZXXSH@OU`?#g223!Qtr!)q@yqM|X7bEJdi8`F&r|lMR zD_SC?UwFu+gmU!OYGp-U$BWAhT7czm-3h82Z$3_KZ_f~EZ1{^G5@d)W)VK}SXT_aV zhRuMPb+pNn_F)V4F>A4X0cYi{_AU@~x%cg%i5RXEtgfYvWt<>khvkUaVKW0&cirCM zV%htYErtm=)=)=gipfs+cgPfrrO)K$a7><mA0i1I`!L%8=ZOX-)p>v$VFFyr@H$m# z%HJI<H+3WTwST9Iq!oKs%*i{j9mjKDBo8Z0ai9&e)rSp*rBoT(fIB2)`fiLA017Yd z?3Y?}(WFd6&z8bwavE+Q+g(PcB;M=98%rk=ih(`Uh6dJ6GHC+#aBXiUa`Im>I26$U z$Zn>iRjCO+yHn)88*9af-%;dz6QAL9NQYber6#41VX7@AY4F*|(HPT$^2|HnIYPdv zyq;)Z!fs_OUdobDC_GQdO|gAAx+)J6D=A!z2;N$8JW{@p6T>O=cv|sr`0T?}^<fS% zLQPXiIN*Y8bz@ahX0_ji1e9u7+{=v)SEolS&nfpg-}7wE2BLRK$jeiORxgOENC3JP z3r^cCTohTGn6GSL?g8Fr{u)+q?hE6wMo+6OwU3gNM<E-GhE9d5Q3Wt^1xaq&^ZS>7 z5~#I#!0MHXw1Oa%RgoiB2FoNLo?K;0?vtPM+>^-@EW)Zu>W_*__eBKp2@i%#@x*L- zQGg@|uLwirQ7+n6S{O@2%opoa`h3$9ghSY+#Cw&x@HUFIb8D^SGHMfak_BUtoxnJe z3FoJ~?PS6)@~VN%_7>50=0gO;`CrcTpDu<rul(RF_#mgvJ^=O)x4FWMS<^_2pu+H0 zu4!Hl0?+!0plGU17?~Jrn{VA}1ynCx(qUhi!bOO};{9Ph>cEcXhRvHy8tu8pNzX^d zDiK|_sfOU4F9s=R{zMd+6+<%cU7s^E7Q8QIiwMv{<)eDN!^s2y`On*>cOI#r%AiPz zDz!!&q-9cLU9wk-rh4-_+_ysX%F+Um0B4%<)4cGMPP>*JkUw3k=BOyV-qMp=H)Ra0 z2{*rHvT8SGp)~YboR(eTq}BV<xb08@de`4E>Lh`0pL8|uCo}+d=1O4BbJka`U8#_i zDm{$A+QZEfpkrqJgZTY><73eiHi~sQ8G4Nw4N5ffn}cAhKyB#&JoEb^oDH}AWq}J1 z<{rO0m8}cYQ?C4cb<K6#_rl(@)o0;WJ(hN-07+d@O1vinfOu=}JS012@OKy!BLn}{ zDC=E12qNADWV}*RI37X#g!Dy=f<1@9j7@=lx3TfqN%+~ymCXb4fCz&J3ifc>qn5y& zcrSbeX*A_H#=&irO{375k#3EuhWX7#*EqUg)Hr_DXJw58y~DB~UyUfDmY+#Tfs3~5 zJ=9gD<%Gxx55z?VF~XJXTF)X9Yp}pjre=Gn`|9ss^wFG>yX?XJoYe+3^+_1tU=>Ex z>z&GP@>nwx^vA+5YF#1uSGrfl-aX@^+jtMthB?8KfsDZRAu>eaS?kZCX-3z70QEI4 zdJSNjk$CPrs)gA8&kt)+O3%;Ulqld?HU%*|I~`D?EJ#@RsNie>MN({3G?Iug!PC&k z`t{|eZLX>@NWa*s#1IhP1{GK?ZU~0M41>RUAHrJ#Tfy}isRd79#&7_}BujY_f1G5Q zMY$gr<GcI4_;sA!F7D}*i(lgv!c7s$&6ZRU=_MSnmdHa*AF}d!*;%1QOe}6(FTmkw zP+JzPo(B-38)2wcq-2UdXCD3b8$FqJn?}Fl0O$Pre0mb{8LB2#x*3bITu}v<ug2_S zRMk&<rKpan>C!tX^2=ybf|<M{MvSweQ7i=G$rvri{al2nVR+=uqB!z3#ETJ>t<Xr# zi?-!56u?si3Xg2-Kmu$)=dSk1jKB3^<3Qdeskwqs#W)SOjTR!A$!ASBC}b&eBXO;D zL^kzt%$XNo-@V5}`Yp+9GFbC{!6YI569nMnrPu16{nAJn(?`6E7g^pSzDCvCyQZ>h zeD4L3=S`WnBcOqWc@=d2ZlwNPry-;8cNKCoCxQ0M$H=n}zxLf$IXj<xf+5Tn>#G|- z?3-In9~~Um_p%(Y;d>F^XRvaZ=9NobCTZx(V?L9YU~FjjS_jD%dFS<5Njn|F%zm<p z>;7GnD`+#;L;Z<56=U)IRpaheI<<To>-Ls7jo_Gjk;W&amhb*up%Dz23~U6}<L|50 zeoQI-C<9=jVxNKap6)JZj_)*=uP=HIXR8c9c@z*d{Q<8g4c_6Y*PBzZ-xbruLz@%$ zAy^KGI@-TOy=X{$$-Ie}PlWELLFx@kae1zm#&{15uE!7t%24KM<35!D<4^$f!a>T6 zD`)|i$Y>VtF`#>{O{)uEg(J~fH;d+TZ|8{E=|Nhf2{Dw6AZDOmi%B6u3?5BOZyQ1f zJaD>*xR(;i|1y|!IQ+Jup>v8uwe2KhVprVrZ0Wn1&CTcQjz7+n`a)ptT{ldCfp%Xb zJaA5PhR3)CA2$i|1c#yt`Z4zW4DTl=e@x+U_6Q6PmO@-@Yp?{p@J2`pmc!LTktUqF zIb%`x)*45O1RtPR;HVF0rm7)0xJpVrtG4mR_uC-@N5cRBYy-+L+fK{gyPp-$F{+k~ zDoPnHr&OL=6Zjh4<<Bc+G3^D#v-@sEO>SY9g7>*)clZiMvqW%>=y0|qMs8qr16Z=4 zNzNt_i#g&?0{RLvwhxME-CEIpcALyXy_)<1yCK9q-X+L7d9yMP>V0Ipe_BzmE=U2L zKcjl30Y`mkjjXWCi^5$OcTtX1_c7aU2hd=+PVzr?cu&CcZ->1o`>aL3_U@F6x6Wr^ zV(~93e@$_!cT`)y!-?Cg7XDfRW)9w|WUHuOJATnPu6n#4KLzxZ<LYVWmZV=^{v4|$ zlumPsyj|k3`4I^?7<zD1)q@LUlDu4QbK4YUqXWkR0%d{dsMIdB=B^HS-K$(pq^z#l zj=b-F^rizY{uF-}S|MzNa16)^VUI(+KXhrH@4(Su%r3j}QqKakhyt{5q_{X@B~kp3 zew*VDdJw=RoZ6M_Ms8C8y!rIZ4Q05_m$)uc)wKtPZA*gUec^#Z^L(vFt98RHjm=uI z^CtuGR}RI_MIxvQ)el!D&AsT7rm)VMq~4kDJFu%iTpa#RYKFt7HzOPP!-*jDUJM{c z-ex2x105)PL`&|*o(oM`40V4{V^Bw5&-BIjJWzz+d$aS{V-H2Aj6bj7>vG1ng%5#L z_Mw#^Sl?ggF;Rf(UGXiRqzS=rf8ufawIt@_edxK8xw3@0J;<!y0snq%?`;8W?G_=L z*!MB@Vp-;zP1%p9^7MMN-^MR_Q*E);cfPKUV}(&<`Dw+z<0luQ-xL6<+D}2rq@78+ z-G6^Ku8c*-p-h|9LVW-L(vayF<bZ1tLE>KXoh2j6PKfvB>+|Zl3^bn<QBgvb$M#VQ zU_T>V=#GoW82KicWH^aQR1v(~v}QThJ5e?Ls58R4(A=~hpWU|0g?*`?SJn7xJGQS! zEK`Es1x#xyU`d}(gAGMN$qi_QBpyz^V;o&0O#)z6x)m7mpOQ0f_JU$oAQ_jI9#{`o z<iqb70^e16mm|C3pV=8du3TTRROY7%wA<2v9JUIqXo?*Ksc>zJso2m1<n*t!!k+Gb zV00gL%~W7~i9Mexh~u^$NgE%jcaVQwL35nv>ml}Xwdj<d6aaqY9!Me^wm1<4%G*JT zLg0-bvI*uR5;F0$yi~Lv=CX=jR0DGt{OXl~XO+gJgjyQUc$G*iBUXF<Qx$zW(>8Yb zIpJSI&zqe{e`WvmKd<g*C&=B(?p1P`wKIPFmVX#03L63ZrD4ALy+igStkMZDC88Ae z-hfT@M)dbOni*gJUyX8ekx`D4ZU}ntc^206w)q+_Q~T)epDL}j8ay*pDKtBlm4w*E zf`u%$*gY5{i^TG8vnIHjWV+yiO~BGLVe*n<tBIb1matjw%Gb0s+5G0c6R0SZr4q2b zb%kg_gPIaa7#0*8c_z$ex+FTBBI2%FhC+Ho*red?yw#aHA+1*x%e>k=s4;ocn>t^a z_e6W_7o^~qVM~JwCzxSul=1PFTq8B3f#z(=g@N5&OfPBdk^HDd_x3{oQ9ypcj<6oj zScAeT%)3K4?1u19gz-ZT?v7w78`;VD&S>WSz?<yFpR^bqN$$gRVTxpQCMwg>2{PL2 zx4{S`OL@pT)b93pD<k{9=^VSX&1|UlR{49uwPK2=Yi;Zv2MI#SS#qcIC>eB36tREk zb@4)#V&mHxHvOh8QtI2=`Q4HE3JyEC9p`6GvLr@@Ma17V4Nd<1F$oogA@BuZeIJX% zr_%b_;n7xupQ9%Gr8{fR)x{{3nsmdT-X;t*d(u-vdyU-YcI>%%DvX)$?^1_kZe2sK zaoHi6=|$Nnl($9m`As)K0H#=+^|{_=yW?D>CmuZ#Fe_q#n8S!gJ(YW_m7L`&a>(Hv z=5=8GCK1%IWngeKWZs)2=szm>@G#lx$ard5Wt7mcw`b_pit#)r-Kj9Q$kxt9B$mb* z@p^y1zt+Tn-?RYmlYKF0%i4Udea#Uf=GO5bEwovR>4lYkV4?RuJA^rlN{hd<_GxWr z^ru$HPg<eDrc~TOZN~!UA_(2smOv#T&!gLcTzelYTI^-c-+euZzzaHwLFFXW)aCX( zvABzff2m*fdd<2)1Dx)}6lh+6D^u+>dU^fe0$wnTT)SF&BpEq(YvOa=xX*#{ekQLN zIxU#^?<p~#k)TEHT<#yl&kDK;GWEMAtiKv}fju{y79FN(e*2)kzwkj>-a|{tJ^ZcY z0cX$rxK<dr2Qlg~_CuDaj2tcJPLvGA7k7LIGQ|^9VPD^r0XS;pgXPig+m+BN^Ui%P z`sPzLUX+fdive}52#(!9tBpDqxSS9lVPU7dCyw<_cE<KsmT?DAh0x}gHY3xJo#9C! zS(qPA48rmxdxfV;l?U;xKEicJe1ql|_L$$0H)t^p^}+7A@fU-wQMouX-!`$T+H4)M z@Egzyti~627v4Q1)N+aFg3v75YVoz~n(<+KFVslE-(TTDs0f4KGCg{*SkuoD%6685 zmCKQYfF!eawN^vB%0*e21GpG>`dUR|?$b_jkOMKt7_nIlDI*pomWj>snmCU+lf>AM zIc5Bh_B*uOmnb&6y}HlgRt3R;x@iqnVnwJ=dS#z7?O#kLVTGhGQLcHgonm3#PZ{s- z7iZp)V}o-LNS9hdebF$qe=?OPHYHD9^>Pbc(csa(gNMn(36ZF|S5a=<4_1!I2c@uk zkSb{Pwr!Wx8oTIwow%;AH<3D)>@Ic|Gnj(s&y@TnRzgI!D=8bT)t?)G!G(IFVGTbJ zb{$pU7nuzaO5w&fN7JB(ELDydwVZSsuFe{zJDY<+X<w{dA?u3Gkr=DTuCn0SOD6&l z9SV63)L$2-`CHgSo^s}jW7<Yd`39;zhkXS<m5h0Jo7d{sJG}yQXeS1HX;@9Zi_F;v z6HN6Fwnwa>5*cIl$cJb(=IlLDz|x`A>UuAcsW7$YRr7nc(k*}ZM68`44<MS8o`~HC zm9AE6Kh_d~LIE7mJ%-pBWpO4`QGw$I)f4N-IRPJ|3_29K9X@_(8m7ANAq?9*X*4=r zXbHhYe4a)(GXf}l%mi2u+(e#HRVsc|>l0J!uL)-A`Yg0%6A^VI{j-o^sna7%2(P%@ z1eEUoNv+h03L>vvlV>U}k_mW?xZ-^W0RR0SG<nB}A4PIZ**zLvn&>b;|FMOBf@$HI zp-4WngLKWaMZdu@2Wkots7D$jF<2XKGjstJW2cwzmvel0T8t}JYm>)Mmv>|_&E6~> z<V<Yky55YTGCLqfm}UB7Ft)~T9NvwDPH1(Y!q3@jy~%87(5$fVC#T)l{ZsfJa?p+k z;Dl^{4I{ijSkF<0XkVRHoHP1<>%imE;5#rqLR)a#LY9%9lb!R7>l~OvtRhVE=^=q6 z=*M7UnI2d8o;U`O6ZXP;V_GnwwMRJ*D{fw~$Q_25tWuHuNkv^xf>=qxHW?`_9!LZi zkx&V*-4V-wcMzKFn`)p{!iA*HO3z(wyxJgtXbC?Wdhx7zcy&CcC@PkxrI6M`4_1#d z0mz}AUom@^y=n;adE8{LHoK+YoTJ`|MTKH4!9un&=sX{8UB`(48#h*a@%OP}xWHg} z0sEjcp*_k(%3Fpr7aRyOVvH0K65wux)FHHwPp~FOu~?7;n|6zN*uwRW_H{<YYQJ)H zp9doZ@VDzvv>3++@*lj?vXEF&!yTkg)~Ma4vzEkx2$*Q^Ztk}9gG5jO)=_lb*TIuU z`9*MKU6oo{@Q602q9@Alf#L@4zBjn8Tp1Tvi2bV219;ATfLQ8UUbNkncK^t=!67PP zBmE2Q!A~TjUXQCA3pGML<q_3%*6vuaK{pzvH@0e>TIY;}K#SgEa509zwQ^+drX76V zZF*?_2gn69IvGS;1YH3g9NEvR2YwW}ZC1hrEW@r7WiFEhszNY9X77Oq+xQ15vr!`- z3`UwyJ540=N@#{GNDqGCs1k0w_qUZMx)NK|O~gfZ)WiJ7Ok(_=&R=2m!?7;2;9<n| z-awoXDvt%R*Y!s|GN-^v*63XLi@s)pzO@ZB$4}`jZHJ9Rc<tIh)yibyLOtERjckKQ z?8%G2mSH3T*QCCP^+M^kLicWuaFhmJmyhg4RAhkU#hOv>DeqILKLl`fdv(g2jCx&H zT4Tm5BW#Ny3oPu`$T9cwh-2Gs{sHekO;gmyxAxxDqu_c@r=4FLSprf)9?i*%((7rb z9aYA~uQ%%L0U;&b3XKXv*DBu@v>d9&ra4J{4`$Ck^Q2nmkPr0jleoP3=71S${09}S zTwmKopu`s}XcuC*uM*u_8{AXpT&Jz;<3}jlpD<OYh6-mZkq_C}Lp9^ADEZLNn6oBt z-1oU-AOtAJwf6ZefS=AHd9T?-f~Oxuj?P(sAI%3S{(=3~NMMw`U=#wODWXE%xy5B& zK!b;h3MD;*yTBdUCTD3r4=PC%r1M}du*g#4#tdQ+ko21l2e)SC5X7YAjug_J=CKAp zz*N9HDZ*tMReb^#R;4ij7_`drt#M@k+{WHd-ZWTh&9nl4lw_gaTY_PzkSv>innVYO zApWVX(#==$mt$&N_Py9)-1IJRpAuVw%)^n11at$uE^yu05%jPyPBD8i?lAMJSDVMO zyf<bZA4?u|Kg?NMvQX6u*ARe?5qH1_t~w)P%c$VT$Ow3gPwUZ{nh8*4f)H&d*Q^%% z@ADnwa>%rGUY1e^SqKY5Oyf$!1$U%=UqdHneZY@Yw~M(W_$u^EIvcPRJg55~ydz2w z^GSd>WHwdREo;~Xn46QRS{&>=C;j~iRJxh+JCj;TlP)VJJ+4`jF-rxJWceJX@XjBF zJxbqQ@aaBs!3^tj>pQL<FVti`KIzG@pA$40G~4d(V8bVzrE-9e=JD80aDVYb1#v5% zPEwW-f3d<*{(g>rK&;jrD=-c7Bnvhxs*g_q5q5gL`~u@l|H^Zf9p&?^%>l3S_|OsM z8HOjN8UxuKwc)a$vZqnOj4d0MM!dwhh$$ta)kzLpvplaz?GraiQpCc5?$Y(f-AH#t z<TRj*ULoMJSbyr>L|Et7h4lj?$_p3Sogh7HOJ{TIGQ!u@pH|m}T^%xpS-8F4s&}P~ z;l3M_3DJ|d><Pm-%0@3M%SWgt)=eI}<!w~xx&4h#x7n-0{&(S$Sz#iDwiok7xgB{P zlw7T$HaFx&ZouelIx(~yY)gurAL_84`5Ap8+*?a{LJT0Hi;=}gc^tU}=SsuyQ4(I) zFc(9uA4Ofaw{cZW=b;$vK`4zt>XM(^FujJW)76th@&M;<fL=VFm$PDacyH;(g5p8c zw9P0Lc1fe>2MkYG>20jM4+xu%a!+-TV@vo#*ZYh<-pNvBtY-&&5R~vQi3pNUw-bhn zgnNcmxD{I|XPtAgPUhD~_-;E7EoWW+m2oZDxYrp_1`g~&jMuMnFa(XGBY#}R*KD*@ z_Mh&3OE>onn_8Gdn#!(W>4l!{?`&&jsT4kRg+iikG-sj5`%3Ym*+Wl0e2SJmf9NA! zTaDSDrNCZ~Z2qJBJ3n>+9!`4WrEr4J2Jh{VIiq35Uf>%caf^E3K>xw2X~wc8ZQNZR zCFKIZ1~WWLblPa~Y-8e0p%^Tgw`o!8EE~Eu7{C~474HR87*~iZ6-{;IG*hAboII;Q z!JkrbxPrRV^u4kfO>kG%@xd*{)(YMMCx+uHM6SKfu4Kn!;5`Wm`cZW?P)p0@!o>-a zj~8x@O@wRP)@=_10*=AF$gkwIopk9;IA`LslngRiOF5JVn^c#`k_VG|j78=SHn|H> zw=fC?sj)J9oe?qa-j4MFs^&!$fKc|FlVO-Pe>g7a2uB+*?-3FIRIrC$T0<0TbSXY& zFk2ZZ>q<T0&#q2bSxBa0LigUiIOK55MqcBi;zBR-F!_{~Hj-=f-ErIFz$vDfpNId1 zt-8_ea&Ft*a|qDYjOkT;+iO>OUJE|D0jUI5`^!O$M0$ElnGxzr^ul1j0}eVR!vMI{ zGCZaBVltH>-#|f@>_hL0LK5uTB;^NcNVv&wbY=V`<Od2)og4w6O7P;ZdoFB1?+}X} z!+j-n5G41Aia+=ZwO1seh>H??kYMw`ik|U+f?asyK-gwgNpR^d>=!)KZ&h}TX@o(x zU!!f34xHmfjx9FwJDhqKAU}{{O+KI03-0jui{fw;;8;7Xbm~@qkxUOcsI7LFYvVo; zaQjo>@xx)4-RB75;%dQ{Di&I7OnN*yp}#4Aw?pG@Z#;au!RpG&*UhVhVfU0J<pq?^ zz;(8=uM-;2C4$Rs*9EMPWy(unZhiVqoxb7SkQP?DHt;Kqc<K`cDUf5OLZ&kKiRFKr zQt`GkK6jU{+iAXf=CL&_ip%AjZmo&oV0fCO`*_vt{Ow0oPTjX@x}>q)zTo=0xBm6d zPt3f!I=sBEuP<rJ*4FcjxIcV8aD8v(VF$J|*91QYFe*j}X2+Mjc+SBg(q#Jk+V*{0 zHN0oomcPF!XZwwBfm_4PKRrALWOwJJz4!Vz$?#Utgk5@1SgnLjWIuh6-&f%n%eK4h zXC=cTrUP3q2F|{g%N8aZ$=PEkqk1rDs-Z)0R@m1KL7g=cfgfhxNHg(t`?u%Tj(^W& z^S(T)%$&MzN}TQF<(GL&O1~y^$W2vyBNJ=+;rYkNN|h%6xxVU!iyZ8a^b5ROFY+T} z>H=Sjq?R*$yu2SXXD<52@IyZ9sr_<G2A$yB>yO&qXi?=CpWL+KLuRB-ea|rg{<h<e z8$Y|5NL^61dd)C{WfGT>vcSS7vqnoU>->N%T9K<aZee+<Jl8~KmWOiVqB6CUud12; zKkbhHf2{uY=5+t#4-dCz|9Ym?d(D5tTA`nJdR#UzW_%Ukxc1j;+n)zzJX==RUJNi{ z)_AtZkV#-#=gSrG{{=ZD+z<WeuV&llm!P-U<O#Q9NAvmE7n7!Ge2m`_?mvB6{FH=D z^Qxr@E1n<Zd+>T0XIn4N>kPJEp|f@!Jkhvr$s&2}Spw?<+-k#bOzU`iZ?E;Ue3f=r zcCOnK&YxYO$nYnj<^gA`V`{<PISh9bJlJkE$g9|zuCXy-D9x7++qUB|tAlyMB*R$u zb8lx=|C+g>Ku-79gN~|eYmYe0a!{7p>E1LednudCV(nR{&YU_>n)~4?N9ODPuRjC% zlN%Pk*9>egF)K9=ul{1VGU`|NuBeXlzMZTeG#TtqaXQFM7hb@<;R5IWSs$0b3pe4O zaj~4CWPedW{7jY!Qf?9#40L}L_AV%p%s<DrEYFl{iT5woT{4+->qL~a1Z%Y>`dH75 zv*~xRo+3F*$o#kZu9xfla&zAYv1@$x`0S~;$b@UHbIIX*3=9nMptArz><o<B-JjvC z(qWMh`1dJG#?^kk1+$ktJ8}CS%e1%uHRtY+wtpAc7N9owR{{^8_(em>1-m?SW0V*^ zIy~F*=4sn5qv*XMX*qNKUuP%T?>%t+$gI@;5_aZGKL2M}J2^G?`$gl2pc5QCUHx3v dIVCjF|1679FbYP&C>RCA0|1y&z})~+0046f`8NOn literal 0 HcmV?d00001 diff --git a/spec/lib/mastodon/cli/emoji_spec.rb b/spec/lib/mastodon/cli/emoji_spec.rb index 5d109eb52..530da91e7 100644 --- a/spec/lib/mastodon/cli/emoji_spec.rb +++ b/spec/lib/mastodon/cli/emoji_spec.rb @@ -4,5 +4,59 @@ require 'rails_helper' require 'mastodon/cli/emoji' describe Mastodon::CLI::Emoji do + subject { cli.invoke(action, args, options) } + + let(:cli) { described_class.new } + let(:args) { [] } + let(:options) { {} } + it_behaves_like 'CLI Command' + + describe '#purge' do + let(:action) { :purge } + + context 'with existing custom emoji' do + before { Fabricate(:custom_emoji) } + + it 'reports a successful purge' do + expect { subject } + .to output_results('OK') + end + end + end + + describe '#import' do + context 'with existing custom emoji' do + let(:import_path) { Rails.root.join('spec', 'fixtures', 'files', 'elite-assets.tar.gz') } + let(:action) { :import } + let(:args) { [import_path] } + + it 'reports about imported emoji' do + expect { subject } + .to output_results('Imported 1') + .and change(CustomEmoji, :count).by(1) + end + end + end + + describe '#export' do + context 'with existing custom emoji' do + before { Fabricate(:custom_emoji) } + after { File.delete(export_path) } + + let(:export_path) { Rails.root.join('tmp', 'export.tar.gz') } + let(:args) { [Rails.root.join('tmp')] } + let(:action) { :export } + + it 'reports about exported emoji' do + expect { subject } + .to output_results('Exported 1') + .and change { File.exist?(export_path) }.from(false).to(true) + end + end + end + + def output_results(string) + output(a_string_including(string)).to_stdout + end end From 954169966b23214a044fa8deda16be4b903526d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 08:52:55 +0000 Subject: [PATCH 210/255] New Crowdin Translations (automated) (#28245) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/lt.json | 26 +++---- config/locales/simple_form.lt.yml | 91 ++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 13 deletions(-) diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index e588b8538..58c80e411 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -40,7 +40,7 @@ "account.follows.empty": "Šis (-i) naudotojas (-a) dar nieko neseka.", "account.follows_you": "Seka tave", "account.go_to_profile": "Eiti į profilį", - "account.hide_reblogs": "Slėpti \"boosts\" iš @{name}", + "account.hide_reblogs": "Slėpti pakėlimus iš @{name}", "account.in_memoriam": "Atminimui.", "account.joined_short": "Prisijungė", "account.languages": "Keisti prenumeruojamas kalbas", @@ -49,19 +49,19 @@ "account.media": "Medija", "account.mention": "Paminėti @{name}", "account.moved_to": "{name} nurodė, kad dabar jų nauja paskyra yra:", - "account.mute": "Užtildyti @{name}", + "account.mute": "Nutildyti @{name}", "account.mute_notifications_short": "Nutildyti pranešimus", "account.mute_short": "Nutildyti", - "account.muted": "Užtildytas", + "account.muted": "Nutildytas", "account.no_bio": "Nėra pateikto aprašymo.", - "account.open_original_page": "Atidaryti originalinį tinklalapį", + "account.open_original_page": "Atidaryti originalinį puslapį", "account.posts": "Įrašai", "account.posts_with_replies": "Įrašai ir atsakymai", "account.report": "Pranešti @{name}", - "account.requested": "Laukiama patvirtinimo. Spausk, kad atšaukti sekimo užklausą.", + "account.requested": "Laukiama patvirtinimo. Spausk, kad atšaukti sekimo užklausą", "account.requested_follow": "{name} paprašė tave sekti", "account.share": "Bendrinti @{name} profilį", - "account.show_reblogs": "Rodyti \"boosts\" iš @{name}", + "account.show_reblogs": "Rodyti pakėlimus iš @{name}", "account.statuses_counter": "{count, plural, one {{counter} įrašas} few {{counter} įrašai} many {{counter} įrašo} other {{counter} įrašų}}", "account.unblock": "Atblokuoti @{name}", "account.unblock_domain": "Atblokuoti domeną {domain}", @@ -73,7 +73,7 @@ "account.unmute_short": "Atitildyti", "account_note.placeholder": "Spausk norėdamas (-a) pridėti pastabą", "admin.dashboard.daily_retention": "Vartotojų išbuvimo rodiklis pagal dieną po registracijos", - "admin.dashboard.monthly_retention": "Vartotojų išbuvimo rodiklis pagal mėnesį po registracijos", + "admin.dashboard.monthly_retention": "Naudotojų išlaikymo rodiklis pagal mėnesį po registracijos", "admin.dashboard.retention.average": "Vidurkis", "admin.dashboard.retention.cohort": "Registravimo mėnuo", "admin.dashboard.retention.cohort_size": "Nauji naudotojai", @@ -117,9 +117,9 @@ "column.favourites": "Mėgstamiausi", "column.firehose": "Tiesioginiai padavimai", "column.follow_requests": "Sekti prašymus", - "column.home": "Pradžia", + "column.home": "Pagrindinis", "column.lists": "Sąrašai", - "column.mutes": "Užtildyti naudotojai", + "column.mutes": "Nutildyti naudotojai", "column.notifications": "Pranešimai", "column.pins": "Prisegti įrašai", "column.public": "Federacinė laiko skalė", @@ -141,13 +141,13 @@ "compose.saved.body": "Įrašas išsaugotas.", "compose_form.direct_message_warning_learn_more": "Sužinoti daugiau", "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.", - "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.", - "compose_form.lock_disclaimer": "Jūsų paskyra nėra {locked}. Kiekvienas gali jus sekti ir peržiūrėti tik sekėjams skirtus įrašus.", + "compose_form.hashtag_warning": "Šis įrašas nebus įtraukta į jokį saitažodį, nes ji nėra vieša. Tik viešų įrašų galima ieškoti pagal saitažodį.", + "compose_form.lock_disclaimer": "Tavo paskyra nėra {locked}. Bet kas gali sekti tave ir peržiūrėti tik sekėjams skirtus įrašus.", "compose_form.lock_disclaimer.lock": "užrakinta", "compose_form.placeholder": "Kas tavo mintyse?", "compose_form.poll.add_option": "Pridėti pasirinkimą", "compose_form.poll.duration": "Apklausos trukmė", - "compose_form.poll.option_placeholder": "Pasirinkimas {number}", + "compose_form.poll.option_placeholder": "{number} pasirinkimas", "compose_form.poll.remove_option": "Pašalinti šį pasirinkimą", "compose_form.poll.switch_to_multiple": "Keisti apklausą, kad būtų galima pasirinkti kelis pasirinkimus", "compose_form.poll.switch_to_single": "Pakeisti apklausą, kad būtų galima pasirinkti vieną variantą", @@ -528,6 +528,8 @@ "search_results.hashtags": "Saitažodžiai", "search_results.nothing_found": "Nepavyko rasti nieko pagal šiuos paieškos terminus.", "search_results.statuses": "Toots", + "server_banner.about_active_users": "Žmonės, kurie naudojosi šiuo serveriu per pastarąsias 30 dienų (mėnesio aktyvūs naudotojai)", + "server_banner.active_users": "aktyvūs naudotojai", "sign_in_banner.sign_in": "Prisijungimas", "sign_in_banner.text": "Prisijunk, kad galėtum sekti profilius arba saitažodžius, mėgsti, bendrinti ir atsakyti į įrašus. Taip pat gali bendrauti iš savo paskyros kitame serveryje.", "status.admin_status": "Open this status in the moderation interface", diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index d53b7105e..6eb90340d 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -63,6 +63,8 @@ lt: setting_use_pending_items: Slėpti laiko skalės naujienas po paspaudimo, vietoj automatinio kanalo slinkimo username: Gali naudoti raides, skaičius ir pabraukimus whole_word: Kai raktažodis ar frazė yra tik raidinis ir skaitmeninis, jis bus taikomas tik tada, jei atitiks visą žodį + email_domain_block: + with_dns_records: Bus bandoma išspręsti nurodyto domeno DNS įrašus, o rezultatai taip pat bus blokuojami featured_tag: name: 'Štai keletas pastaruoju metu dažniausiai saitažodžių, kurių tu naudojai:' filters: @@ -77,15 +79,98 @@ lt: site_contact_email: Kaip žmonės gali su tavimi susisiekti teisiniais ar pagalbos užklausimais. site_contact_username: Kaip žmonės gali tave pasiekti Mastodon. site_extended_description: Bet kokia papildoma informacija, kuri gali būti naudinga lankytojams ir naudotojams. Gali būti struktūrizuota naudojant Markdown sintaksę. + thumbnail: Maždaug 2:1 dydžio vaizdas, rodomas šalia tavo serverio informacijos. + timeline_preview: Atsijungę lankytojai galės naršyti naujausius viešus įrašus, esančius serveryje. trends: Trendai rodo, kurios įrašai, saitažodžiai ir naujienų istorijos tavo serveryje sulaukia didžiausio susidomėjimo. sessions: otp: 'Įvesk telefono programėlėje sugeneruotą dviejų tapatybės kodą arba naudok vieną iš atkūrimo kodų:' webauthn: Jei tai USB raktas, būtinai jį įkišk ir, jei reikia, paspausk. settings: indexable: Tavo profilio puslapis gali būti rodomas paieškos rezultatuose Google, Bing ir kituose. + user: + chosen_languages: Kai pažymėta, viešose laiko skalėse bus rodomi tik įrašai pasirinktomis kalbomis + role: Vaidmuo valdo, kokius leidimus naudotojas (-a) turi labels: + account: + indexable: Įtraukti viešus įrašus į paieškos rezultatus + show_collections: Rodyti sekimus ir sekėjus profilyje + unlocked: Automatiškai priimti naujus sekėjus + account_warning_preset: + title: Pavadinimas + admin_account_action: + include_statuses: Įtraukti praneštus įrašus į el. laišką + defaults: + avatar: Profilio nuotrauka + bot: Tai automatinė paskyra + chosen_languages: Filtruoti kalbas + display_name: Rodomas vardas + email: El. pašto adresas + expires_in: Nustoja galioti po + fields: Papildomi laukai + irreversible: Mesti vietoj slėpti + locale: Sąsajos kalba + max_uses: Maksimalus naudojimo skaičius + new_password: Naujas slaptažodis + note: Biografija + password: Slaptažodis + phrase: Raktažodis arba frazė + setting_auto_play_gif: Automatiškai leisti animuotų GIF + setting_boost_modal: Rodyti patvirtinimo dialogą prieš pakėliant įrašą + setting_default_language: Skelbimo kalba + setting_default_privacy: Skelbimo privatumas + setting_default_sensitive: Visada žymėti mediją kaip jautrią + setting_delete_modal: Rodyti patvirtinimo dialogą prieš ištrinant įrašą + setting_display_media: Medijos rodymas + setting_display_media_hide_all: Slėpti viską + setting_display_media_show_all: Rodyti viską + setting_expand_spoilers: Visada išplėsti įrašus, pažymėtus turinio įspėjimais + setting_hide_network: Slėpti savo socialinę diagramą + setting_system_font_ui: Naudoti numatytąjį sistemos šriftą + setting_theme: Svetainės tema + setting_use_pending_items: Lėtas režimas + title: Pavadinimas + type: Importo tipas + username: Naudotojo vardas + username_or_email: Naudotojo vardas arba el. paštas + whole_word: Visas žodis + email_domain_block: + with_dns_records: Įtraukti MX įrašus ir domeno IP adresus featured_tag: name: Saitažodis + filters: + actions: + hide: Slėpti visiškai + warn: Slėpti su įspėjimu + form_admin_settings: + activity_api_enabled: Skelbti suvestinį statistiką apie naudotojų veiklą per API + bootstrap_timeline_accounts: Visada rekomenduoti šias paskyras naujiems naudotojams + content_cache_retention_period: Turinio talpyklos išlaikymo laikotarpis + custom_css: Pasirinktinis CSS + mascot: Pasirinktinis talismanas (pasenęs) + registrations_mode: Kas gali užsiregistruoti + show_domain_blocks_rationale: Rodyti, kodėl domenai buvo užblokuoti + site_extended_description: Išplėstas aprašymas + site_short_description: Serverio aprašymas + site_terms: Privatumo politika + site_title: Serverio pavadinimas + theme: Numatytoji tema + thumbnail: Serverio miniatūra + invite_request: + text: Kodėl nori prisijungti? + notification_emails: + favourite: Kažkas pamėgo tavo įrašą + follow: Kažkas seka tave + follow_request: Kažkas paprašė sekti tave + mention: Kažkas paminėjo tave + pending_account: Reikia peržiūros naujam paskyrui + reblog: Kažkas pakėlė tavo įrašą + software_updates: + label: Yra nauja Mastodon versija + patch: Pranešti apie klaidų ištaisymo atnaujinimus + rule: + text: Taisyklė + settings: + show_application: Rodyti, iš kurios programėles išsiuntei įrašą tag: listable: Leisti šį saitažodį rodyti paieškose ir pasiūlymuose name: Saitažodis @@ -93,11 +178,15 @@ lt: usable: Leisti įrašams naudoti šį saitažodį user: role: Vaidmuo + time_zone: Laiko juosta user_role: + color: Ženklelio spalva + highlighted: Rodyti vaidmenį kaip ženklelį naudotojo profiliuose + name: Pavadinimas permissions_as_keys: Leidimai position: Prioritetas webhook: - events: Įgalinti įvykiai + events: Įjungti įvykiai template: Naudingosios apkrovos šablonas url: Galutinio taško URL 'no': Ne From 42afd303246abe1cf61752ab53cca466ea3cefdf Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 6 Dec 2023 05:19:24 -0500 Subject: [PATCH 211/255] Replace Sprockets with Propshaft (#28239) --- .github/renovate.json5 | 1 - Gemfile | 3 +-- Gemfile.lock | 15 ++++++--------- config/application.rb | 1 - config/environments/development.rb | 11 ----------- config/initializers/assets.rb | 16 ---------------- 6 files changed, 7 insertions(+), 40 deletions(-) delete mode 100644 config/initializers/assets.rb diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 895dbfbad..a7998ddfd 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -50,7 +50,6 @@ matchManagers: ['bundler'], matchPackageNames: [ 'rack', // Needs to be synced with Rails version - 'sprockets', // Requires manual upgrade https://github.com/rails/sprockets/blob/master/UPGRADING.md#guide-to-upgrading-from-sprockets-3x-to-4x 'strong_migrations', // Requires manual upgrade 'sidekiq', // Requires manual upgrade 'sidekiq-unique-jobs', // Requires manual upgrades and sync with Sidekiq version diff --git a/Gemfile b/Gemfile index e3fb39e16..cfcbcc0d3 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,7 @@ ruby '>= 3.0.0' gem 'puma', '~> 6.3' gem 'rails', '~> 7.1.1' -gem 'sprockets', '~> 3.7.2' +gem 'propshaft' gem 'thor', '~> 1.2' gem 'rack', '~> 2.2.7' @@ -89,7 +89,6 @@ gem 'sidekiq-unique-jobs', '~> 7.1' gem 'sidekiq-bulk', '~> 0.2.0' gem 'simple-navigation', '~> 4.4' gem 'simple_form', '~> 5.2' -gem 'sprockets-rails', '~> 3.4', require: 'sprockets/railtie' gem 'stoplight', '~> 3.0.1' gem 'strong_migrations', '1.6.4' gem 'tty-prompt', '~> 0.23', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 4a409a0ad..738562116 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -534,6 +534,11 @@ GEM net-smtp premailer (~> 1.7, >= 1.7.9) private_address_check (0.5.0) + propshaft (0.8.0) + actionpack (>= 7.0.0) + activesupport (>= 7.0.0) + rack + railties (>= 7.0.0) psych (5.1.1.1) stringio public_suffix (5.0.4) @@ -736,13 +741,6 @@ GEM simplecov-lcov (0.8.0) simplecov_json_formatter (0.1.4) smart_properties (1.17.0) - sprockets (3.7.2) - concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) - sprockets (>= 3.0.0) stackprof (0.2.25) statsd-ruby (1.5.0) stoplight (3.0.2) @@ -911,6 +909,7 @@ DEPENDENCIES posix-spawn premailer-rails private_address_check (~> 0.5) + propshaft public_suffix (~> 5.0) puma (~> 6.3) pundit (~> 2.3) @@ -949,8 +948,6 @@ DEPENDENCIES simple_form (~> 5.2) simplecov (~> 0.22) simplecov-lcov (~> 0.8) - sprockets (~> 3.7.2) - sprockets-rails (~> 3.4) stackprof stoplight (~> 3.0.1) strong_migrations (= 1.6.4) diff --git a/config/application.rb b/config/application.rb index 99ee4ffd7..b6426516e 100644 --- a/config/application.rb +++ b/config/application.rb @@ -14,7 +14,6 @@ require 'active_job/railtie' # require 'action_mailbox/engine' # require 'action_text/engine' # require 'rails/test_unit/railtie' -require 'sprockets/railtie' # Used to be implicitly required in action_mailbox/engine require 'mail' diff --git a/config/environments/development.rb b/config/environments/development.rb index e601fc014..3c13ada38 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -71,17 +71,6 @@ Rails.application.configure do # Highlight code that enqueued background job in logs. config.active_job.verbose_enqueue_logs = true - # Debug mode disables concatenation and preprocessing of assets. - config.assets.debug = true - - # Suppress logger output for asset requests. - config.assets.quiet = true - - # Adds additional error checking when serving assets at runtime. - # Checks for improperly declared sprockets dependencies. - # Raises helpful error messages. - config.assets.raise_runtime_errors = true - # Raises error for missing translations. # config.i18n.raise_on_missing_translations = true diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb deleted file mode 100644 index e1fd5f8ce..000000000 --- a/config/initializers/assets.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -# Be sure to restart your server when you modify this file. - -# Version of your assets, change this if you want to expire all your assets. -Rails.application.config.assets.version = '1.0' - -# Add additional assets to the asset load path. -# Rails.application.config.assets.paths << Emoji.images_path - -# Precompile additional assets. -# application.js, application.css, and all non-JS/CSS in the app/assets -# folder are already added. -# Rails.application.config.assets.precompile += %w( admin.js admin.css ) - -Rails.application.config.assets.initialize_on_precompile = true From ee83d5c7600b2cdc96db78c5ec40d8747853ba30 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 6 Dec 2023 08:42:12 -0500 Subject: [PATCH 212/255] Enable the eslint `react/no-unknown-property` rule (#28217) --- .eslintrc.js | 1 - .../mastodon/features/interaction_modal/index.jsx | 6 +++--- .../mastodon/features/ui/components/navigation_panel.jsx | 2 +- app/javascript/mastodon/features/video/index.jsx | 1 - package.json | 2 +- yarn.lock | 4 ++-- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 176879034..e2d16a54a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -120,7 +120,6 @@ module.exports = defineConfig({ 'react/jsx-uses-react': 'off', // not needed with new JSX transform 'react/jsx-wrap-multilines': 'error', 'react/no-deprecated': 'off', - 'react/no-unknown-property': 'off', 'react/react-in-jsx-scope': 'off', // not needed with new JSX transform 'react/self-closing-comp': 'error', diff --git a/app/javascript/mastodon/features/interaction_modal/index.jsx b/app/javascript/mastodon/features/interaction_modal/index.jsx index 4f145f9ed..216c63a7e 100644 --- a/app/javascript/mastodon/features/interaction_modal/index.jsx +++ b/app/javascript/mastodon/features/interaction_modal/index.jsx @@ -298,9 +298,9 @@ class LoginForm extends React.PureComponent { onFocus={this.handleFocus} onBlur={this.handleBlur} onKeyDown={this.handleKeyDown} - autocomplete='off' - autocapitalize='off' - spellcheck='false' + autoComplete='off' + autoCapitalize='off' + spellCheck='false' /> <Button onClick={this.handleSubmit} disabled={isSubmitting || error}><FormattedMessage id='interaction_modal.login.action' defaultMessage='Take me home' /></Button> diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx index 4b0e03a0f..d1b2a0910 100644 --- a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx +++ b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx @@ -82,7 +82,7 @@ class NavigationPanel extends Component { </div> {banner && - <div class='navigation-panel__banner'> + <div className='navigation-panel__banner'> {banner} </div> } diff --git a/app/javascript/mastodon/features/video/index.jsx b/app/javascript/mastodon/features/video/index.jsx index bef14ea27..9ff6d3589 100644 --- a/app/javascript/mastodon/features/video/index.jsx +++ b/app/javascript/mastodon/features/video/index.jsx @@ -612,7 +612,6 @@ class Video extends PureComponent { aria-label={alt} title={alt} lang={lang} - volume={volume} onClick={this.togglePlay} onKeyDown={this.handleVideoKeyDown} onPlay={this.handlePlay} diff --git a/package.json b/package.json index 543af8a4b..500d6d2cd 100644 --- a/package.json +++ b/package.json @@ -193,7 +193,7 @@ "eslint-plugin-jsx-a11y": "~6.8.0", "eslint-plugin-prettier": "^5.0.0", "eslint-plugin-promise": "~6.1.1", - "eslint-plugin-react": "~7.33.0", + "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "husky": "^8.0.3", "jest": "^29.5.0", diff --git a/yarn.lock b/yarn.lock index 9e1622680..774eefec8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2371,7 +2371,7 @@ __metadata: eslint-plugin-jsx-a11y: "npm:~6.8.0" eslint-plugin-prettier: "npm:^5.0.0" eslint-plugin-promise: "npm:~6.1.1" - eslint-plugin-react: "npm:~7.33.0" + eslint-plugin-react: "npm:^7.33.2" eslint-plugin-react-hooks: "npm:^4.6.0" file-loader: "npm:^6.2.0" font-awesome: "npm:^4.7.0" @@ -7501,7 +7501,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react@npm:~7.33.0": +"eslint-plugin-react@npm:^7.33.2": version: 7.33.2 resolution: "eslint-plugin-react@npm:7.33.2" dependencies: From 23b16aaab0f475d8584e948d2f4ce6d64a68cac3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 14:50:59 +0100 Subject: [PATCH 213/255] Update dependency selenium-webdriver to v4.16.0 (#28246) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 738562116..cd04f2782 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -707,7 +707,7 @@ GEM scenic (1.7.0) activerecord (>= 4.0.0) railties (>= 4.0.0) - selenium-webdriver (4.15.0) + selenium-webdriver (4.16.0) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) From af66d3d836b89286423d4ba9fe1518bb6317b499 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Wed, 6 Dec 2023 09:15:54 -0500 Subject: [PATCH 214/255] Use `following` and `followers` scopes in CLI (#28154) --- lib/mastodon/cli/accounts.rb | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/mastodon/cli/accounts.rb b/lib/mastodon/cli/accounts.rb index 33520df25..414675303 100644 --- a/lib/mastodon/cli/accounts.rb +++ b/lib/mastodon/cli/accounts.rb @@ -472,15 +472,13 @@ module Mastodon::CLI end total = 0 - total += Account.where(id: ::Follow.where(account: account).select(:target_account_id)).count if options[:follows] - total += Account.where(id: ::Follow.where(target_account: account).select(:account_id)).count if options[:followers] + total += account.following.reorder(nil).count if options[:follows] + total += account.followers.reorder(nil).count if options[:followers] progress = create_progress_bar(total) processed = 0 if options[:follows] - scope = Account.where(id: ::Follow.where(account: account).select(:target_account_id)) - - scope.find_each do |target_account| + account.following.reorder(nil).find_each do |target_account| UnfollowService.new.call(account, target_account) rescue => e progress.log pastel.red("Error processing #{target_account.id}: #{e}") @@ -493,9 +491,7 @@ module Mastodon::CLI end if options[:followers] - scope = Account.where(id: ::Follow.where(target_account: account).select(:account_id)) - - scope.find_each do |target_account| + account.followers.reorder(nil).find_each do |target_account| UnfollowService.new.call(target_account, account) rescue => e progress.log pastel.red("Error processing #{target_account.id}: #{e}") From 658ad7a6cabe0c8b6b3ae11db1a4cc8434152ec4 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Wed, 6 Dec 2023 23:22:25 +0100 Subject: [PATCH 215/255] Fix flaky tests related to file creation (#28248) --- .../post_deployment_migration_generator_spec.rb | 2 +- spec/lib/mastodon/cli/emoji_spec.rb | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/spec/generators/post_deployment_migration_generator_spec.rb b/spec/generators/post_deployment_migration_generator_spec.rb index d770a78e9..55e70a791 100644 --- a/spec/generators/post_deployment_migration_generator_spec.rb +++ b/spec/generators/post_deployment_migration_generator_spec.rb @@ -12,7 +12,7 @@ describe PostDeploymentMigrationGenerator, type: :generator do include FileUtils tests described_class - destination File.expand_path('../../tmp', __dir__) + destination Rails.root.join('tmp', 'generator-test') before { prepare_destination } after { rm_rf(destination_root) } diff --git a/spec/lib/mastodon/cli/emoji_spec.rb b/spec/lib/mastodon/cli/emoji_spec.rb index 530da91e7..3441413b9 100644 --- a/spec/lib/mastodon/cli/emoji_spec.rb +++ b/spec/lib/mastodon/cli/emoji_spec.rb @@ -41,11 +41,17 @@ describe Mastodon::CLI::Emoji do describe '#export' do context 'with existing custom emoji' do - before { Fabricate(:custom_emoji) } - after { File.delete(export_path) } + before do + FileUtils.rm_rf(export_path.dirname) + FileUtils.mkdir_p(export_path.dirname) - let(:export_path) { Rails.root.join('tmp', 'export.tar.gz') } - let(:args) { [Rails.root.join('tmp')] } + Fabricate(:custom_emoji) + end + + after { FileUtils.rm_rf(export_path.dirname) } + + let(:export_path) { Rails.root.join('tmp', 'cli-tests', 'export.tar.gz') } + let(:args) { [export_path.dirname.to_s] } let(:action) { :export } it 'reports about exported emoji' do From 5e8a38e2540e4c067fe8756bb78a1cc854943db6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 09:42:47 +0100 Subject: [PATCH 216/255] Update dependency oj to v3.16.2 (#28263) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index cd04f2782..45ad60558 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -484,7 +484,8 @@ GEM nokogiri (1.15.5) mini_portile2 (~> 2.8.2) racc (~> 1.4) - oj (3.16.1) + oj (3.16.2) + bigdecimal (~> 3.1) omniauth (2.1.1) hashie (>= 3.4.6) rack (>= 2.2.3) From 54db2006a96639a51d42353bef8c18b5f55b1c3c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 08:44:16 +0000 Subject: [PATCH 217/255] Update dependency sass-loader to v10.5.0 (#28254) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 774eefec8..45f58eaad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14663,8 +14663,8 @@ __metadata: linkType: hard "sass-loader@npm:^10.2.0": - version: 10.4.1 - resolution: "sass-loader@npm:10.4.1" + version: 10.5.0 + resolution: "sass-loader@npm:10.5.0" dependencies: klona: "npm:^2.0.4" loader-utils: "npm:^2.0.0" @@ -14673,7 +14673,7 @@ __metadata: semver: "npm:^7.3.2" peerDependencies: fibers: ">= 3.1.0" - node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 sass: ^1.3.0 webpack: ^4.36.0 || ^5.0.0 peerDependenciesMeta: @@ -14683,7 +14683,7 @@ __metadata: optional: true sass: optional: true - checksum: bf04a440fe471928f3cf884bc12c6b70bc391795b35510b1b9021e8a2cca3b8f966aef9518f4171e87e9cb78193a774f695921e6b61881a1580ae0a3c7b1b5e4 + checksum: be5da7784fd21c4f526cc3afaa1a765ba44cdc2f9798ecbac87b296ab44184ac5ba9bbda68a7a86f8cdcb6130acceefeb8912260fca14bdfc97f9dad02658400 languageName: node linkType: hard From 336d6260ba8ace929bfb5482cc72740d013dd1a0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 09:44:45 +0100 Subject: [PATCH 218/255] Update dependency chewy to v7.3.5 (#28253) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 45ad60558..7a7fdb01c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -197,7 +197,7 @@ GEM activesupport cbor (0.5.9.6) charlock_holmes (0.7.7) - chewy (7.3.4) + chewy (7.3.5) activesupport (>= 5.2) elasticsearch (>= 7.12.0, < 7.14.0) elasticsearch-dsl From 7593465c23d4b0c4d44304712f7957aa1d9ce9d7 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Thu, 7 Dec 2023 10:05:08 +0100 Subject: [PATCH 219/255] Fix error when processing link preview with an array as `inLanguage` (#28252) --- app/lib/link_details_extractor.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/lib/link_details_extractor.rb b/app/lib/link_details_extractor.rb index a96612cab..bb031986d 100644 --- a/app/lib/link_details_extractor.rb +++ b/app/lib/link_details_extractor.rb @@ -37,6 +37,7 @@ class LinkDetailsExtractor def language lang = json['inLanguage'] + lang = lang.first if lang.is_a?(Array) lang.is_a?(Hash) ? (lang['alternateName'] || lang['name']) : lang end From e0dacf6b4ce090cf6a30f8b1f37283b174b32c40 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 10:38:44 +0100 Subject: [PATCH 220/255] New Crowdin Translations (automated) (#28264) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/hu.json | 54 ++++++++++++------------- config/locales/activerecord.hu.yml | 2 +- config/locales/devise.hu.yml | 8 ++-- config/locales/hu.yml | 28 ++++++------- config/locales/simple_form.hu.yml | 8 ++-- config/locales/simple_form.hy.yml | 2 +- 6 files changed, 51 insertions(+), 51 deletions(-) diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 9bef81417..d890e4188 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -13,7 +13,7 @@ "about.rules": "Kiszolgáló szabályai", "account.account_note_header": "Feljegyzés", "account.add_or_remove_from_list": "Hozzáadás vagy eltávolítás a listákról", - "account.badges.bot": "Bot", + "account.badges.bot": "Automatizált", "account.badges.group": "Csoport", "account.block": "@{name} letiltása", "account.block_domain": "Domain blokkolása: {domain}", @@ -63,8 +63,8 @@ "account.share": "@{name} profiljának megosztása", "account.show_reblogs": "@{name} megtolásainak mutatása", "account.statuses_counter": "{count, plural, one {{counter} Bejegyzés} other {{counter} Bejegyzés}}", - "account.unblock": "@{name} tiltásának feloldása", - "account.unblock_domain": "{domain} domain tiltás feloldása", + "account.unblock": "@{name} letiltásának feloldása", + "account.unblock_domain": "{domain} domain tiltásának feloldása", "account.unblock_short": "Tiltás feloldása", "account.unendorse": "Ne jelenjen meg a profilodon", "account.unfollow": "Követés megszüntetése", @@ -138,21 +138,21 @@ "compose.language.search": "Nyelv keresése...", "compose.published.body": "A bejegyzés publikálásra került.", "compose.published.open": "Megnyitás", - "compose.saved.body": "A bejegyzés mentésre került.", + "compose.saved.body": "A bejegyzés mentve.", "compose_form.direct_message_warning_learn_more": "Tudj meg többet", - "compose_form.encryption_warning": "A bejegyzések Mastodonon nem használnak végpontok közötti titkosítást. Ne ossz meg semmilyen érzékeny információt Mastodonon.", + "compose_form.encryption_warning": "A bejegyzések a Mastodonon nem használnak végpontok közti titkosítást. Ne ossz meg semmilyen érzékeny információt a Mastodonon.", "compose_form.hashtag_warning": "Ez a bejegyzésed nem fog megjelenni semmilyen hashtag alatt, mivel nem nyilvános. Csak a nyilvános bejegyzések kereshetők hashtaggel.", "compose_form.lock_disclaimer": "A fiókod nincs {locked}. Bárki követni tud, hogy megtekintse a kizárólag követőknek szánt bejegyzéseket.", - "compose_form.lock_disclaimer.lock": "lezárva", + "compose_form.lock_disclaimer.lock": "zárolva", "compose_form.placeholder": "Mi jár a fejedben?", "compose_form.poll.add_option": "Lehetőség hozzáadása", "compose_form.poll.duration": "Szavazás időtartama", "compose_form.poll.option_placeholder": "{number}. lehetőség", - "compose_form.poll.remove_option": "Lehetőség törlése", + "compose_form.poll.remove_option": "Lehetőség eltávolítása", "compose_form.poll.switch_to_multiple": "Szavazás megváltoztatása több választásosra", "compose_form.poll.switch_to_single": "Szavazás megváltoztatása egyetlen választásosra", "compose_form.publish": "Közzététel", - "compose_form.publish_form": "Közzététel", + "compose_form.publish_form": "Új bejegyzés", "compose_form.publish_loud": "{publish}!", "compose_form.save_changes": "Módosítások mentése", "compose_form.sensitive.hide": "{count, plural, one {Média kényesnek jelölése} other {Média kényesnek jelölése}}", @@ -195,13 +195,13 @@ "copy_icon_button.copied": "A szöveg a vágólapra másolva", "copypaste.copied": "Másolva", "copypaste.copy_to_clipboard": "Másolás vágólapra", - "directory.federated": "Az ismert fediverzumból", + "directory.federated": "Az ismert födiverzumból", "directory.local": "Csak {domain} tartományból", "directory.new_arrivals": "Új csatlakozók", "directory.recently_active": "Nemrég aktív", "disabled_account_banner.account_settings": "Fiókbeállítások", "disabled_account_banner.text": "A(z) {disabledAccount} fiókod jelenleg le van tiltva.", - "dismissable_banner.community_timeline": "Ezek a legfrissebb nyilvános bejegyzések, amelyeket {domain} tartományban levő kiszolgáló fiókjait használó emberek tettek közzé.", + "dismissable_banner.community_timeline": "Ezek a legfrissebb nyilvános bejegyzések, amelyeket a(z) {domain} kiszolgáló fiókjait használó emberek tették közzé.", "dismissable_banner.dismiss": "Elvetés", "dismissable_banner.explore_links": "Jelenleg ezekről a hírekről beszélgetnek az ezen és a központosítás nélküli hálózat többi kiszolgálóján lévő emberek.", "dismissable_banner.explore_statuses": "Ezek jelenleg népszerűvé váló bejegyzések a háló különböző szegleteiből. Az újabb vagy több megtolással rendelkező bejegyzéseket, illetve a kedvencnek jelöléssel rendelkezőeket rangsoroljuk előrébb.", @@ -216,14 +216,14 @@ "emoji_button.food": "Étel és Ital", "emoji_button.label": "Emodzsi beszúrása", "emoji_button.nature": "Természet", - "emoji_button.not_found": "Nincsenek emodzsik!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "Nem találhatók emodzsik", "emoji_button.objects": "Tárgyak", "emoji_button.people": "Emberek", "emoji_button.recent": "Gyakran használt", "emoji_button.search": "Keresés...", "emoji_button.search_results": "Keresési találatok", "emoji_button.symbols": "Szimbólumok", - "emoji_button.travel": "Utazás és Helyek", + "emoji_button.travel": "Utazás és helyek", "empty_column.account_hides_collections": "Ez a felhasználó úgy döntött, hogy nem teszi elérhetővé ezt az információt.", "empty_column.account_suspended": "Fiók felfüggesztve", "empty_column.account_timeline": "Itt nincs bejegyzés!", @@ -245,7 +245,7 @@ "empty_column.mutes": "Még egy felhasználót sem némítottál le.", "empty_column.notifications": "Jelenleg még nincsenek értesítéseid. Ha mások kapcsolatba lépnek veled, ezek itt lesznek láthatóak.", "empty_column.public": "Jelenleg itt nincs semmi! Írj valamit nyilvánosan vagy kövess más kiszolgálón levő felhasználókat, hogy megtöltsd.", - "error.unexpected_crash.explanation": "Egy hiba vagy böngésző inkompatibilitás miatt ez az oldal nem jeleníthető meg rendesen.", + "error.unexpected_crash.explanation": "Egy kód- vagy böngészőkompatibilitási hiba miatt ez az oldal nem jeleníthető meg helyesen.", "error.unexpected_crash.explanation_addons": "Ezt az oldalt nem lehet helyesen megjeleníteni. Ezt a hibát valószínűleg egy böngésző kiegészítő vagy egy automatikus fordító okozza.", "error.unexpected_crash.next_steps": "Próbáld frissíteni az oldalt. Ha ez nem segít, egy másik böngészőn vagy appon keresztül még mindig használhatod a Mastodont.", "error.unexpected_crash.next_steps_addons": "Próbáld letiltani őket és frissíteni az oldalt. Ha ez nem segít, egy másik böngészőn vagy appon keresztül még mindig használhatod a Mastodont.", @@ -278,13 +278,13 @@ "firehose.remote": "Egyéb kiszolgálók", "follow_request.authorize": "Hitelesítés", "follow_request.reject": "Elutasítás", - "follow_requests.unlocked_explanation": "Bár a fiókod nincs zárolva, a(z) {domain} csapata úgy gondolta, hogy talán kézzel szeretnéd ellenőrizni a fiók követési kéréseit.", + "follow_requests.unlocked_explanation": "Bár a fiókod nincs zárolva, a(z) {domain} csapata úgy gondolta, hogy talán kézzel szeretnéd ellenőrizni ezen fiókok követési kéréseit.", "followed_tags": "Követett hashtagek", "footer.about": "Névjegy", "footer.directory": "Profiltár", "footer.get_app": "Alkalmazás beszerzése", "footer.invite": "Emberek meghívása", - "footer.keyboard_shortcuts": "Billentyűparancsok", + "footer.keyboard_shortcuts": "Gyorsbillentyűk", "footer.privacy_policy": "Adatvédelmi szabályzat", "footer.source_code": "Forráskód megtekintése", "footer.status": "Állapot", @@ -347,13 +347,13 @@ "keyboard_shortcuts.favourite": "Bejegyzés kedvencnek jelölése", "keyboard_shortcuts.favourites": "Kedvencek lista megnyitása", "keyboard_shortcuts.federated": "Föderációs idővonal megnyitása", - "keyboard_shortcuts.heading": "Billentyűparancsok", + "keyboard_shortcuts.heading": "Gyorsbillentyűk", "keyboard_shortcuts.home": "Saját idővonal megnyitása", "keyboard_shortcuts.hotkey": "Gyorsbillentyű", "keyboard_shortcuts.legend": "jelmagyarázat megjelenítése", - "keyboard_shortcuts.local": "helyi idővonal megnyitása", + "keyboard_shortcuts.local": "Helyi idővonal megnyitása", "keyboard_shortcuts.mention": "Szerző megemlítése", - "keyboard_shortcuts.muted": "némított felhasználók listájának megnyitása", + "keyboard_shortcuts.muted": "Némított felhasználók listájának megnyitása", "keyboard_shortcuts.my_profile": "Saját profil megnyitása", "keyboard_shortcuts.notifications": "Értesítések oszlop megnyitása", "keyboard_shortcuts.open_media": "Média megnyitása", @@ -389,7 +389,7 @@ "lists.replies_policy.list": "A lista tagjai", "lists.replies_policy.none": "Senki", "lists.replies_policy.title": "Nekik mutassuk a válaszokat:", - "lists.search": "Keresés a követett személyek között", + "lists.search": "Keresés a követett emberek között", "lists.subheading": "Saját listák", "load_pending": "{count, plural, one {# új elem} other {# új elem}}", "loading_indicator.label": "Betöltés…", @@ -399,7 +399,7 @@ "mute_modal.hide_notifications": "Rejtsük el a felhasználótól származó értesítéseket?", "mute_modal.indefinite": "Határozatlan", "navigation_bar.about": "Névjegy", - "navigation_bar.advanced_interface": "Haladó webes felület engedélyezése", + "navigation_bar.advanced_interface": "Megnyitás a speciális webes felületben", "navigation_bar.blocks": "Letiltott felhasználók", "navigation_bar.bookmarks": "Könyvjelzők", "navigation_bar.community_timeline": "Helyi idővonal", @@ -411,9 +411,9 @@ "navigation_bar.explore": "Felfedezés", "navigation_bar.favourites": "Kedvencek", "navigation_bar.filters": "Némított szavak", - "navigation_bar.follow_requests": "Követési kérelmek", + "navigation_bar.follow_requests": "Követési kérések", "navigation_bar.followed_tags": "Követett hashtagek", - "navigation_bar.follows_and_followers": "Követettek és követők", + "navigation_bar.follows_and_followers": "Követések és követők", "navigation_bar.lists": "Listák", "navigation_bar.logout": "Kijelentkezés", "navigation_bar.mutes": "Némított felhasználók", @@ -449,7 +449,7 @@ "notifications.column_settings.follow_request": "Új követési kérelmek:", "notifications.column_settings.mention": "Megemlítések:", "notifications.column_settings.poll": "Szavazási eredmények:", - "notifications.column_settings.push": "Push értesítések", + "notifications.column_settings.push": "Leküldéses értesítések", "notifications.column_settings.reblog": "Megtolások:", "notifications.column_settings.show": "Megjelenítés az oszlopban", "notifications.column_settings.sound": "Hang lejátszása", @@ -480,7 +480,7 @@ "onboarding.compose.template": "Üdvözlet, #Mastodon!", "onboarding.follows.empty": "Sajnos jelenleg nem jeleníthető meg eredmény. Kipróbálhatod a keresést vagy böngészheted a felfedező oldalon a követni kívánt személyeket, vagy próbáld meg később.", "onboarding.follows.lead": "A saját hírfolyamod az elsődleges tapasztalás a Mastodonon. Minél több embert követsz, annál aktívabb és érdekesebb a dolog. Az induláshoz itt van néhány javaslat:", - "onboarding.follows.title": "Népszerű a Mastodonon", + "onboarding.follows.title": "Szabd személyre a kezdőlapodat", "onboarding.profile.discoverable": "Saját profil beállítása felfedezhetőként", "onboarding.profile.discoverable_hint": "A Mastodonon a felfedezhetőség választása esetén a saját bejegyzéseid megjelenhetnek a keresési eredmények és a felkapott tartalmak között, valamint a profilod a hozzád hasonló érdeklődési körrel rendelkező embereknél is ajánlásra kerülhet.", "onboarding.profile.display_name": "Megjelenített név", @@ -499,14 +499,14 @@ "onboarding.start.lead": "Az új Mastodon-fiók használatra kész. Így hozhatod ki belőle a legtöbbet:", "onboarding.start.skip": "Szeretnél előreugrani?", "onboarding.start.title": "Ez sikerült!", - "onboarding.steps.follow_people.body": "Te állítod össze a saját hírfolyamodat. Töltsd meg érdekes emberekkel.", + "onboarding.steps.follow_people.body": "A Mastodon az érdekes emberek követéséről szól.", "onboarding.steps.follow_people.title": "{count, plural, one {egy ember} other {# ember}} követése", "onboarding.steps.publish_status.body": "Üdvözöljük a világot.", "onboarding.steps.publish_status.title": "Az első bejegyzés létrehozása", "onboarding.steps.setup_profile.body": "Mások nagyobb valószínűséggel lépnek kapcsolatba veled egy kitöltött profil esetén.", "onboarding.steps.setup_profile.title": "Profilod testreszabása", - "onboarding.steps.share_profile.body": "Tudasd az ismerőseiddel, hogyan találhatnak meg a Mastodonon!", - "onboarding.steps.share_profile.title": "Profilod megosztása", + "onboarding.steps.share_profile.body": "Tudasd az ismerőseiddel, hogyan találhatnak meg a Mastodonon", + "onboarding.steps.share_profile.title": "Oszd meg a Mastodon profilodat", "onboarding.tips.2fa": "<strong>Tudtad?</strong> A fiókod biztonságossá teheted, ha a fiók beállításaiban beállítod a kétlépcsős hitelesítést. Bármilyen választott TOTP alkalmazással működik, nincs szükség telefonszámra!", "onboarding.tips.accounts_from_other_servers": "<strong>Tudtad?</strong> Mivel a Mastodon decentralizált, egyes profilok, amelyekkel találkozol, más kiszolgálókon lesznek tárolva. És mégis zökkenőmentesen kommunikálhatsz velük! A kiszolgáló a felhasználónevük második felében található!", "onboarding.tips.migration": "<strong>Tudtad?</strong> Ha úgy érzed, hogy a {domain} már nem jó kiszolgáló a számodra, átköltözhetsz egy másik Mastodon kiszolgálóra anélkül, hogy elveszítenéd a követőidet. Akár saját kiszolgálót is üzemeltethetsz!", diff --git a/config/locales/activerecord.hu.yml b/config/locales/activerecord.hu.yml index e5757ba64..f34ade044 100644 --- a/config/locales/activerecord.hu.yml +++ b/config/locales/activerecord.hu.yml @@ -20,7 +20,7 @@ hu: attributes: username: invalid: csak betűket, számokat vagy alávonást tartalmazhat - reserved: fenntartott + reserved: foglalt admin/webhook: attributes: url: diff --git a/config/locales/devise.hu.yml b/config/locales/devise.hu.yml index bbf6a6399..6eb1524ed 100644 --- a/config/locales/devise.hu.yml +++ b/config/locales/devise.hu.yml @@ -44,7 +44,7 @@ hu: action: Jelszó módosítása explanation: A fiókodhoz tartozó jelszó módosítását kezdeményezted. extra: Amennyiben nem te kezdeményezted a módosítást, kérjük tekintsd ezt az emailt tárgytalannak. A jelszavad változatlan marad mindaddig, amíg újat nem hozol létre a fenti linkre kattintva. - subject: 'Mastodon: Jelszó visszaállítási lépések' + subject: 'Mastodon: Jelszóvisszaállítási utasítások' title: Jelszó visszaállítása two_factor_disabled: explanation: A fiókod kétlépcsős hitelesítését kikapcsoltuk. A bejelentkezés mostantól csak az e-mail cím és a jelszó használatával lesz lehetséges. @@ -52,14 +52,14 @@ hu: title: Kétlépcsős hitelesítés kikapcsolva two_factor_enabled: explanation: A kétlépcsős hitelesítést engedélyeztük a fiókodban. A bejelentkezéshez a párosított TOTP alkalmazás által generált tokenre lesz szükség. - subject: Kétlépcsős azonosítás engedélyezve + subject: 'Mastodon: Kétlépcsős azonosítás engedélyezve' title: Kétlépcsős hitelesítés engedélyezve two_factor_recovery_codes_changed: explanation: A korábbi helyreállítási kódok letiltásra és újragenerálásra kerültek. - subject: Kétlépcsős helyreállítási kódok újra létrejöttek + subject: 'Mastodon: Kétlépcsős helyreállítási kódok újból előállítva' title: A kétlépcsős kódok megváltoztak unlock_instructions: - subject: 'Mastodon: Feloldási lépések' + subject: 'Mastodon: Feloldási utasítások' webauthn_credential: added: explanation: A következő biztonsági kulcsot hozzáadtuk a fiókodhoz diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 7057883e1..5da1a4e06 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -4,7 +4,7 @@ hu: about_mastodon_html: 'A jövő közösségi hálózata: Hirdetések és céges megfigyelés nélkül, etikus dizájnnal és decentralizációval! Legyél a saját adataid ura a Mastodonnal!' contact_missing: Nincs megadva contact_unavailable: N/A - hosted_on: "%{domain} Mastodon szerver" + hosted_on: "%{domain} Mastodon-kiszolgáló" title: Névjegy accounts: follow: Követés @@ -747,7 +747,7 @@ hu: desc_html: Ez hCaptcha-ból származó külső scripteket használ, mely biztonsági vagy adatvédelmi résnek bizonyulhat. Ezen kívül ez <strong>a regisztrációs folyamatot jelentősen megnehezítheti bizonyos (kifejezetten különleges szükségletű) emberek számára</strong>. Emiatt fontold meg más módszerek, mint pl. jóváhagyás-alapú vagy meghívásalapú regisztráció használatát. title: Az új felhasználóknak egy CAPTCHA-t kell megoldaniuk, hogy megerősítsék a fiókjuk regisztrációját content_retention: - preamble: Felhasználók által generált tartalom Mastodonon való tárolásának szabályozása. + preamble: A felhasználók által előállított tartalom Mastodonon való tárolásának szabályozása. title: Tartalom megtartása default_noindex: desc_html: Azokat a felhasználókat érinti, akik nem módosították ezt a beállítást @@ -1007,8 +1007,8 @@ hu: hint_html: Ha másik fiókról kívánsz átlépni erre a fiókra, itt létrehozhatsz egy aliast, amelyre szükség van, mielőtt folytathatod a követők áthelyezését a régi fiókból erre. Ez az áthelyezés önmagában <strong>ártalmatlan és visszafordítható</strong> folyamat. <strong>A fiók áttelepítése a régi fiókból indul el. </strong> remove: Alias szétkapcsolása appearance: - advanced_web_interface: Haladó webes felület - advanced_web_interface_hint: 'Ha szeretnéd, a teljes képernyőszélességet felhasználhatod. A haladó webes felülettel különböző oszlopokat állíthatsz be, hogy egyszerre annyi infót láthass, amennyit csak akarsz: Saját idővonal, értesítések, föderációs idővonal, bármennyi lista vagy hashtag.' + advanced_web_interface: Speciális webes felület + advanced_web_interface_hint: 'Ha szeretnéd, a képernyő teljes szélességét kihasználhatod. A speciális webes felülettel különböző oszlopokat állíthatsz be, hogy egyszerre annyi információt láthass, amennyit csak akarsz: Kezdőoldal, értesítések, föderációs idővonal, bármennyi lista vagy hashtag.' animations_and_accessibility: Animáció és akadálymentesítés confirmation_dialogs: Megerősítő párbeszédablakok discovery: Felfedezés @@ -1052,7 +1052,7 @@ hu: delete_account: Felhasználói fiók törlése delete_account_html: Felhasználói fiókod törléséhez <a href="%{path}">kattints ide</a>. A rendszer újbóli megerősítést fog kérni. description: - prefix_invited_by_user: "@%{name} meghív téged, hogy csatlakozz ehhez a Mastodon kiszolgálóhoz." + prefix_invited_by_user: "@%{name} meghív téged, hogy csatlakozz ehhez a Mastodon-kiszolgálóhoz." prefix_sign_up: Regisztrláj még ma a Mastodonra! suffix: Egy fiókkal követhetsz másokat, bejegyzéseket tehetsz közzé, eszmét cserélhetsz más Mastodon szerverek felhasználóival! didnt_get_confirmation: Nem kaptál visszaigazoló hivatkozást? @@ -1101,7 +1101,7 @@ hu: title: 'Bejelentkezés ide: %{domain}' sign_up: manual_review: A(z) %{domain} regisztrációi a moderátorok kézi felülvizsgálatán mennek át. Hogy segítsd a regisztráció feldolgozását, írj röviden magadról, és hogy miért szeretnél fiókot a(z) %{domain} oldalon. - preamble: Egy fiókkal ezen a Mastodon kiszolgálón követhetsz bárkit a hálózaton, függetlenül attól, hogy az illető fiókja melyik kiszolgálón található. + preamble: Egy fiókkal ezen a Mastodon-kiszolgálón követhetsz bárkit a hálózaton, függetlenül attól, hogy az illető fiókja melyik kiszolgálón található. title: Állítsuk be a fiókod a %{domain} kiszolgálón. status: account_status: Fiók állapota @@ -1234,7 +1234,7 @@ hu: filters: contexts: account: Profil - home: Saját idővonal + home: Kezdőlap és listák notifications: Értesítések public: Nyilvános idővonalak thread: Beszélgetések @@ -1245,7 +1245,7 @@ hu: statuses_hint_html: Ez a szűrő egyedi bejegyzések kiválasztására vonatkozik, függetlenül attól, hogy megfelelnek-e a lenti kulcsszavaknak. <a href="%{path}">Engedélyezze vagy távolítsa el a bejegyzéseket a szűrőből</a>. title: Szűrő szerkesztése errors: - deprecated_api_multiple_keywords: Ezek a paraméterek nem módosíthatóak az alkalmazásból, mert több mint egy szűrőkulcsszóra is hatással vannak. Használd az alkalmazás vagy a webes felület újabb verzióját. + deprecated_api_multiple_keywords: Ezek a paraméterek nem módosíthatók az alkalmazásból, mert egynél több szűrőkulcsszóra is hatással vannak. Használd az alkalmazás vagy a webes felület újabb verzióját. invalid_context: A megadott kontextus hamis vagy hiányzik index: contexts: 'Szűrés helye: %{contexts}' @@ -1396,7 +1396,7 @@ hu: unsubscribe: action: Igen, leiratkozás complete: Leiratkozva - confirmation_html: Biztos vagy benne, hogy le szeretnél iratkozni arról, hogy %{type} típusú üzeneteket kapj a %{domain} Mastodon kiszolgálón a %{email} címedre? Bármikor újra feliratkozhatsz az <a href="%{settings_path}">email értesítések beállításainál</a>. + confirmation_html: 'Biztos, hogy leiratkozol arról, hogy %{type} típusú üzeneteket kapj a %{domain} Mastodon-kiszolgálótól erre a címedre: %{email}? Bármikor újra feliratkozhatsz az <a href="%{settings_path}">e-mail-értesítések beállításánál</a>.' emails: notification_emails: favourite: kedvencnek jelölésről email értesítő @@ -1405,7 +1405,7 @@ hu: mention: megemlítésről email értesítő reblog: megtolásról email értesítő resubscribe_html: Ha tévedésből iratkoztál le, újra feliratkozhatsz az <a href="%{settings_path}">email értesítések beállításainál</a>. - success_html: Mostantól nem kapsz %{type} típusú üzeneket a %{domain} Mastodon kiszolgálón a %{email} címedre. + success_html: 'Mostantól nem kapsz %{type} típusú üzeneket a(z) %{domain} Mastodon-kiszolgálón erre a címedre: %{email}.' title: Leiratkozás media_attachments: validations: @@ -1743,9 +1743,9 @@ hu: tags: does_not_match_previous_name: nem illeszkedik az előző névvel themes: - contrast: Mastodon (Nagy kontrasztú) - default: Mastodon (Sötét) - mastodon-light: Mastodon (Világos) + contrast: Mastodon (nagy kontrasztú) + default: Mastodon (sötét) + mastodon-light: Mastodon (világos) time: formats: default: "%Y. %b %d., %H:%M" @@ -1782,7 +1782,7 @@ hu: subject: A %{date}-i fellebbezésedet visszautasították title: Fellebbezés visszautasítva backup_ready: - explanation: A Mastodon fiókod teljes mentését kérted. A mentés kész ás letölthető! + explanation: A Mastodon-fiókod teljes mentését kérted. A mentés elkészült, és letölthető. subject: Az adataidról készült archív letöltésre kész title: Archiválás suspicious_sign_in: diff --git a/config/locales/simple_form.hu.yml b/config/locales/simple_form.hu.yml index 70c225e8f..6e11f7fb9 100644 --- a/config/locales/simple_form.hu.yml +++ b/config/locales/simple_form.hu.yml @@ -81,8 +81,8 @@ hu: bootstrap_timeline_accounts: Ezek a fiókok ki lesznek tűzve az új felhasználók követési javaslatainak élére. closed_registrations_message: Akkor jelenik meg, amikor a regisztráció le van zárva content_cache_retention_period: A más kiszolgálókról származó bejegyzések megadott számú nap után törölve lesznek, ha pozitív értékre van állítva. Ez lehet, hogy nem fordítható vissza. - custom_css: A Mastodon webes verziójában használhatsz egyedi stílusokat. - mascot: Felülvágja a haladó webes felületen található illusztrációt. + custom_css: A Mastodon webes verziójában használhatsz egyéni stílusokat. + mascot: Felülbírálja a speciális webes felületen található illusztrációt. media_cache_retention_period: A letöltött médiafájlok megadott számú nap után törölve lesznek, ha pozitív értékre van állítva, és igény szerint újból le lesznek töltve. peers_api_enabled: Azon domainek listája, melyekkel ez a kiszolgáló találkozott a fediverzumban. Nem csatolunk adatot arról, hogy föderált kapcsolatban vagy-e az adott kiszolgálóval, csak arról, hogy a kiszolgálód tud a másikról. Ezt olyan szolgáltatások használják, melyek általában a föderációról készítenek statisztikákat. profile_directory: A profilok jegyzéke minden olyan felhasználót felsorol, akik engedélyezték a felfedezhetőségüket. @@ -103,7 +103,7 @@ hu: form_challenge: current_password: Beléptél egy biztonsági térben imports: - data: Egy másik Mastodon kiszolgálóról exportált CSV-fájl + data: Egy másik Mastodon-kiszolgálóról exportált CSV-fájl invite_request: text: Ez segít nekünk átnézni a jelentkezésedet ip_block: @@ -199,7 +199,7 @@ hu: otp_attempt: Kétlépcsős azonosító kód password: Jelszó phrase: Kulcsszó vagy kifejezés - setting_advanced_layout: Haladó webes felület engedélyezése + setting_advanced_layout: Speciális webes felület engedélyezése setting_aggregate_reblogs: Megtolások csoportosítása az idővonalakon setting_always_send_emails: E-mail értesítések küldése mindig setting_auto_play_gif: GIF-ek automatikus lejátszása diff --git a/config/locales/simple_form.hy.yml b/config/locales/simple_form.hy.yml index 56aa1d66b..9dbcd1301 100644 --- a/config/locales/simple_form.hy.yml +++ b/config/locales/simple_form.hy.yml @@ -43,7 +43,7 @@ hy: setting_display_media_hide_all: Երբեք մեդիա ցոյց չտալ setting_display_media_show_all: Մեդիա միշտ ցոյց տալ setting_use_blurhash: Կտորները հիմնուում են թաքցուած վիզուալի վրայ՝ խամրեցնելով դետալները - setting_use_pending_items: Թաքցնել հոսքի թարմացումները կտտոի ետեւում՝ աւտօմատ թարմացուող հոսքի փոխարէն + setting_use_pending_items: Թաքցնել հոսքի թարմացումները կոճակի ետեւում՝ աւտօմատ թարմացուող հոսքի փոխարէն username: Միայն լատինատառեր, թուեր եւ տակի գծիկ whole_word: Եթէ բանալի բառը կամ արտայայտութիւնը պարունակում է միայն այբբենական նիշեր եւ թուեր, ապա այն կիրառուելու է ամբողջ բառի հետ համընկնելու դէպքում միայն domain_allow: From 1d7b8234c94e13ad3f00455e7a5f0702e9379228 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 7 Dec 2023 04:41:00 -0500 Subject: [PATCH 221/255] Remove useless `reorder(nil)` call in `tootctl statuses` (#28141) --- lib/mastodon/cli/statuses.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mastodon/cli/statuses.rb b/lib/mastodon/cli/statuses.rb index 0d6018a2b..7acf3f9b7 100644 --- a/lib/mastodon/cli/statuses.rb +++ b/lib/mastodon/cli/statuses.rb @@ -120,7 +120,7 @@ module Mastodon::CLI say('Beginning removal of now-orphaned media attachments to free up disk space...') - scope = MediaAttachment.reorder(nil).unattached.where('created_at < ?', options[:days].pred.days.ago) + scope = MediaAttachment.unattached.where('created_at < ?', options[:days].pred.days.ago) processed = 0 removed = 0 progress = create_progress_bar(scope.count) From 0b4a3a04378ce43f2f314b9446b5053f6b374c6d Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 7 Dec 2023 07:15:50 -0500 Subject: [PATCH 222/255] Remove remaining `without_partial_double_verification` usage (#28127) --- spec/helpers/application_helper_spec.rb | 24 +++++++++----- spec/helpers/home_helper_spec.rb | 17 +++++++--- spec/helpers/media_component_helper_spec.rb | 36 +++++---------------- 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 3cc88014c..0a55770ba 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -29,15 +29,25 @@ describe ApplicationHelper do describe 'body_classes' do context 'with a body class string from a controller' do - before do - without_partial_double_verification do - allow(helper).to receive_messages(body_class_string: 'modal-layout compose-standalone', current_theme: 'default', current_account: Fabricate(:account)) - end - end + before { helper.extend controller_helpers } it 'uses the controller body classes in the result' do expect(helper.body_classes).to match(/modal-layout compose-standalone/) end + + private + + def controller_helpers + Module.new do + def body_class_string = 'modal-layout compose-standalone' + + def current_account + @current_account ||= Fabricate(:account) + end + + def current_theme = 'default' + end + end end end @@ -122,9 +132,7 @@ describe ApplicationHelper do describe 'available_sign_up_path' do context 'when registrations are closed' do before do - without_partial_double_verification do - allow(Setting).to receive(:registrations_mode).and_return('none') - end + allow(Setting).to receive(:[]).with('registrations_mode').and_return 'none' end it 'redirects to joinmastodon site' do diff --git a/spec/helpers/home_helper_spec.rb b/spec/helpers/home_helper_spec.rb index c6baec5a1..befc8a5c8 100644 --- a/spec/helpers/home_helper_spec.rb +++ b/spec/helpers/home_helper_spec.rb @@ -23,12 +23,19 @@ RSpec.describe HomeHelper do context 'with a valid account' do let(:account) { Fabricate(:account) } - it 'returns a link to the account' do - without_partial_double_verification do - allow(helper).to receive_messages(current_account: account, prefers_autoplay?: false) - result = helper.account_link_to(account) + before { helper.extend controller_helpers } - expect(result).to match "@#{account.acct}" + it 'returns a link to the account' do + result = helper.account_link_to(account) + + expect(result).to match "@#{account.acct}" + end + + private + + def controller_helpers + Module.new do + def current_account = Account.last end end end diff --git a/spec/helpers/media_component_helper_spec.rb b/spec/helpers/media_component_helper_spec.rb index 149f6a83a..af5d92769 100644 --- a/spec/helpers/media_component_helper_spec.rb +++ b/spec/helpers/media_component_helper_spec.rb @@ -3,16 +3,12 @@ require 'rails_helper' describe MediaComponentHelper do + before { helper.extend controller_helpers } + describe 'render_video_component' do let(:media) { Fabricate(:media_attachment, type: :video, status: Fabricate(:status)) } let(:result) { helper.render_video_component(media.status) } - before do - without_partial_double_verification do - allow(helper).to receive(:current_account).and_return(media.account) - end - end - it 'renders a react component for the video' do expect(parsed_html.div['data-component']).to eq('Video') end @@ -22,12 +18,6 @@ describe MediaComponentHelper do let(:media) { Fabricate(:media_attachment, type: :audio, status: Fabricate(:status)) } let(:result) { helper.render_audio_component(media.status) } - before do - without_partial_double_verification do - allow(helper).to receive(:current_account).and_return(media.account) - end - end - it 'renders a react component for the audio' do expect(parsed_html.div['data-component']).to eq('Audio') end @@ -37,12 +27,6 @@ describe MediaComponentHelper do let(:media) { Fabricate(:media_attachment, type: :audio, status: Fabricate(:status)) } let(:result) { helper.render_media_gallery_component(media.status) } - before do - without_partial_double_verification do - allow(helper).to receive(:current_account).and_return(media.account) - end - end - it 'renders a react component for the media gallery' do expect(parsed_html.div['data-component']).to eq('MediaGallery') end @@ -54,10 +38,6 @@ describe MediaComponentHelper do before do PreviewCardsStatus.create(status: status, preview_card: Fabricate(:preview_card)) - - without_partial_double_verification do - allow(helper).to receive(:current_account).and_return(status.account) - end end it 'returns the correct react component markup' do @@ -69,12 +49,6 @@ describe MediaComponentHelper do let(:status) { Fabricate(:status, poll: Fabricate(:poll)) } let(:result) { helper.render_poll_component(status) } - before do - without_partial_double_verification do - allow(helper).to receive(:current_account).and_return(status.account) - end - end - it 'returns the correct react component markup' do expect(parsed_html.div['data-component']).to eq('Poll') end @@ -85,4 +59,10 @@ describe MediaComponentHelper do def parsed_html Nokogiri::Slop(result) end + + def controller_helpers + Module.new do + def current_account = Account.last + end + end end From 5d97a897c8984d5f4fc0e2dca0799b5ab59a7c65 Mon Sep 17 00:00:00 2001 From: Ken Greeff <ken@kengreeff.com> Date: Thu, 7 Dec 2023 23:45:55 +1100 Subject: [PATCH 223/255] Add note to install libidn on MacOS (#28259) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index beab2c355..7b22d61b5 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ To set up **MacOS** for native development, complete the following steps: - Run `brew install postgresql@14` - Run `brew install redis` - Run `brew install imagemagick` +- Run `brew install libidn` - Install Foreman or a similar tool (such as [overmind](https://github.com/DarthSim/overmind)) to handle multiple process launching. - Navigate to Mastodon's root directory and run `brew install nvm` then `nvm use` to use the version from .nvmrc - Run `corepack enable && corepack prepare` From ad34d33bfd10d3ff8078032e9f390c30892e80c1 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 7 Dec 2023 08:49:14 -0500 Subject: [PATCH 224/255] Formalize some patterns in cli specs (#28255) --- spec/lib/mastodon/cli/accounts_spec.rb | 431 +++++++++--------- spec/lib/mastodon/cli/cache_spec.rb | 29 +- .../cli/canonical_email_blocks_spec.rb | 26 +- spec/lib/mastodon/cli/domains_spec.rb | 14 +- .../mastodon/cli/email_domain_blocks_spec.rb | 63 +-- spec/lib/mastodon/cli/emoji_spec.rb | 12 +- spec/lib/mastodon/cli/feeds_spec.rb | 29 +- spec/lib/mastodon/cli/ip_blocks_spec.rb | 113 ++--- spec/lib/mastodon/cli/main_spec.rb | 15 +- spec/lib/mastodon/cli/maintenance_spec.rb | 24 +- spec/lib/mastodon/cli/media_spec.rb | 73 ++- spec/lib/mastodon/cli/preview_cards_spec.rb | 33 +- spec/lib/mastodon/cli/settings_spec.rb | 39 +- spec/lib/mastodon/cli/statuses_spec.rb | 17 +- spec/lib/mastodon/cli/upgrade_spec.rb | 13 +- spec/rails_helper.rb | 1 + spec/support/command_line_helpers.rb | 9 + 17 files changed, 492 insertions(+), 449 deletions(-) create mode 100644 spec/support/command_line_helpers.rb diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index 3216d0d1b..06860c2ff 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -4,7 +4,11 @@ require 'rails_helper' require 'mastodon/cli/accounts' describe Mastodon::CLI::Accounts do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' @@ -27,15 +31,17 @@ describe Mastodon::CLI::Accounts do end describe '#create' do + let(:action) { :create } + shared_examples 'a new user with given email address and username' do it 'creates a new user with the specified email address' do - cli.invoke(:create, arguments, options) + subject expect(User.find_by(email: options[:email])).to be_present end it 'creates a new local account with the specified username' do - cli.invoke(:create, arguments, options) + subject expect(Account.find_local('tootctl_username')).to be_present end @@ -43,9 +49,8 @@ describe Mastodon::CLI::Accounts do it 'returns "OK" and newly generated password' do allow(SecureRandom).to receive(:hex).and_return('test_password') - expect { cli.invoke(:create, arguments, options) }.to output( - a_string_including("OK\nNew password: test_password") - ).to_stdout + expect { subject } + .to output_results("OK\nNew password: test_password") end end @@ -61,9 +66,8 @@ describe Mastodon::CLI::Accounts do let(:options) { { email: 'invalid' } } it 'exits with an error message' do - expect { cli.invoke(:create, arguments, options) }.to output( - a_string_including('Failure/Error: email') - ).to_stdout + expect { subject } + .to output_results('Failure/Error: email') .and raise_error(SystemExit) end end @@ -75,7 +79,7 @@ describe Mastodon::CLI::Accounts do it_behaves_like 'a new user with given email address and username' it 'creates a new user with confirmed status' do - cli.invoke(:create, arguments, options) + subject user = User.find_by(email: options[:email]) @@ -93,7 +97,7 @@ describe Mastodon::CLI::Accounts do it_behaves_like 'a new user with given email address and username' it 'creates a new user with approved status' do - cli.invoke(:create, arguments, options) + subject user = User.find_by(email: options[:email]) @@ -109,7 +113,7 @@ describe Mastodon::CLI::Accounts do it_behaves_like 'a new user with given email address and username' it 'creates a new user and assigns the specified role' do - cli.invoke(:create, arguments, options) + subject role = User.find_by(email: options[:email])&.role @@ -121,9 +125,8 @@ describe Mastodon::CLI::Accounts do let(:options) { { email: 'tootctl@example.com', role: '404' } } it 'exits with an error message indicating the role name was not found' do - expect { cli.invoke(:create, arguments, options) }.to output( - a_string_including('Cannot find user role with that name') - ).to_stdout + expect { subject } + .to output_results('Cannot find user role with that name') .and raise_error(SystemExit) end end @@ -139,16 +142,15 @@ describe Mastodon::CLI::Accounts do end it 'returns an error message indicating the username is already taken' do - expect { cli.invoke(:create, arguments, options) }.to output( - a_string_including("The chosen username is currently in use\nUse --force to reattach it anyway and delete the other user") - ).to_stdout + expect { subject } + .to output_results("The chosen username is currently in use\nUse --force to reattach it anyway and delete the other user") end context 'with --force option' do let(:options) { { email: 'tootctl_new@example.com', reattach: true, force: true } } it 'reattaches the account to the new user and deletes the previous user' do - cli.invoke(:create, arguments, options) + subject user = Account.find_local('tootctl_username')&.user @@ -173,20 +175,21 @@ describe Mastodon::CLI::Accounts do let(:arguments) { ['tootctl_username'] } it 'raises a required argument missing error (Thor::RequiredArgumentMissingError)' do - expect { cli.invoke(:create, arguments) } + expect { subject } .to raise_error(Thor::RequiredArgumentMissingError) end end end describe '#modify' do + let(:action) { :modify } + context 'when the given username is not found' do let(:arguments) { ['non_existent_username'] } it 'exits with an error message indicating the user was not found' do - expect { cli.invoke(:modify, arguments) }.to output( - a_string_including('No user with such username') - ).to_stdout + expect { subject } + .to output_results('No user with such username') .and raise_error(SystemExit) end end @@ -197,13 +200,12 @@ describe Mastodon::CLI::Accounts do context 'when no option is provided' do it 'returns a successful message' do - expect { cli.invoke(:modify, arguments) }.to output( - a_string_including('OK') - ).to_stdout + expect { subject } + .to output_results('OK') end it 'does not modify the user' do - cli.invoke(:modify, arguments) + subject expect(user).to eq(user.reload) end @@ -214,9 +216,8 @@ describe Mastodon::CLI::Accounts do let(:options) { { role: '404' } } it 'exits with an error message indicating the role was not found' do - expect { cli.invoke(:modify, arguments, options) }.to output( - a_string_including('Cannot find user role with that name') - ).to_stdout + expect { subject } + .to output_results('Cannot find user role with that name') .and raise_error(SystemExit) end end @@ -226,7 +227,7 @@ describe Mastodon::CLI::Accounts do let(:options) { { role: default_role.name } } it "updates the user's role to the specified role" do - cli.invoke(:modify, arguments, options) + subject role = user.reload.role @@ -241,7 +242,7 @@ describe Mastodon::CLI::Accounts do let(:user) { Fabricate(:user, role: role) } it "removes the user's role successfully" do - cli.invoke(:modify, arguments, options) + subject role = user.reload.role @@ -254,13 +255,13 @@ describe Mastodon::CLI::Accounts do let(:options) { { email: 'new_email@email.com' } } it "sets the user's unconfirmed email to the provided email address" do - cli.invoke(:modify, arguments, options) + subject expect(user.reload.unconfirmed_email).to eq(options[:email]) end it "does not update the user's original email address" do - cli.invoke(:modify, arguments, options) + subject expect(user.reload.email).to eq('old_email@email.com') end @@ -270,13 +271,13 @@ describe Mastodon::CLI::Accounts do let(:options) { { email: 'new_email@email.com', confirm: true } } it "updates the user's email address to the provided email" do - cli.invoke(:modify, arguments, options) + subject expect(user.reload.email).to eq(options[:email]) end it "sets the user's email address as confirmed" do - cli.invoke(:modify, arguments, options) + subject expect(user.reload.confirmed?).to be(true) end @@ -288,7 +289,7 @@ describe Mastodon::CLI::Accounts do let(:options) { { confirm: true } } it "confirms the user's email address" do - cli.invoke(:modify, arguments, options) + subject expect(user.reload.confirmed?).to be(true) end @@ -303,7 +304,7 @@ describe Mastodon::CLI::Accounts do end it 'approves the user' do - expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.approved }.from(false).to(true) + expect { subject }.to change { user.reload.approved }.from(false).to(true) end end @@ -312,7 +313,7 @@ describe Mastodon::CLI::Accounts do let(:options) { { disable: true } } it 'disables the user' do - expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.disabled }.from(false).to(true) + expect { subject }.to change { user.reload.disabled }.from(false).to(true) end end @@ -321,7 +322,7 @@ describe Mastodon::CLI::Accounts do let(:options) { { enable: true } } it 'enables the user' do - expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.disabled }.from(true).to(false) + expect { subject }.to change { user.reload.disabled }.from(true).to(false) end end @@ -331,9 +332,8 @@ describe Mastodon::CLI::Accounts do it 'returns a new password for the user' do allow(SecureRandom).to receive(:hex).and_return('new_password') - expect { cli.invoke(:modify, arguments, options) }.to output( - a_string_including('new_password') - ).to_stdout + expect { subject } + .to output_results('new_password') end end @@ -342,7 +342,7 @@ describe Mastodon::CLI::Accounts do let(:options) { { disable_2fa: true } } it 'disables the two-factor authentication for the user' do - expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.otp_required_for_login }.from(true).to(false) + expect { subject }.to change { user.reload.otp_required_for_login }.from(true).to(false) end end @@ -351,9 +351,8 @@ describe Mastodon::CLI::Accounts do let(:options) { { email: 'invalid' } } it 'exits with an error message' do - expect { cli.invoke(:modify, arguments, options) }.to output( - a_string_including('Failure/Error: email') - ).to_stdout + expect { subject } + .to output_results('Failure/Error: email') .and raise_error(SystemExit) end end @@ -361,9 +360,8 @@ describe Mastodon::CLI::Accounts do end describe '#delete' do + let(:action) { :delete } let(:account) { Fabricate(:account) } - let(:arguments) { [account.username] } - let(:options) { { email: account.user.email } } let(:delete_account_service) { instance_double(DeleteAccountService) } before do @@ -372,26 +370,29 @@ describe Mastodon::CLI::Accounts do end context 'when both username and --email are provided' do + let(:arguments) { [account.username] } + let(:options) { { email: account.user.email } } + it 'exits with an error message indicating that only one should be used' do - expect { cli.invoke(:delete, arguments, options) }.to output( - a_string_including('Use username or --email, not both') - ).to_stdout + expect { subject } + .to output_results('Use username or --email, not both') .and raise_error(SystemExit) end end context 'when neither username nor --email are provided' do it 'exits with an error message indicating that no username was provided' do - expect { cli.invoke(:delete) }.to output( - a_string_including('No username provided') - ).to_stdout + expect { subject } + .to output_results('No username provided') .and raise_error(SystemExit) end end context 'when username is provided' do + let(:arguments) { [account.username] } + it 'deletes the specified user successfully' do - cli.invoke(:delete, arguments) + subject expect(delete_account_service).to have_received(:call).with(account, reserve_email: false).once end @@ -400,15 +401,14 @@ describe Mastodon::CLI::Accounts do let(:options) { { dry_run: true } } it 'does not delete the specified user' do - cli.invoke(:delete, arguments, options) + subject expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false) end it 'outputs a successful message in dry run mode' do - expect { cli.invoke(:delete, arguments, options) }.to output( - a_string_including('OK (DRY RUN)') - ).to_stdout + expect { subject } + .to output_results('OK (DRY RUN)') end end @@ -416,17 +416,18 @@ describe Mastodon::CLI::Accounts do let(:arguments) { ['non_existent_username'] } it 'exits with an error message indicating that no user was found' do - expect { cli.invoke(:delete, arguments) }.to output( - a_string_including('No user with such username') - ).to_stdout + expect { subject } + .to output_results('No user with such username') .and raise_error(SystemExit) end end end context 'when --email is provided' do + let(:options) { { email: account.user.email } } + it 'deletes the specified user successfully' do - cli.invoke(:delete, nil, options) + subject expect(delete_account_service).to have_received(:call).with(account, reserve_email: false).once end @@ -435,15 +436,14 @@ describe Mastodon::CLI::Accounts do let(:options) { { email: account.user.email, dry_run: true } } it 'does not delete the user' do - cli.invoke(:delete, nil, options) + subject expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false) end it 'outputs a successful message in dry run mode' do - expect { cli.invoke(:delete, nil, options) }.to output( - a_string_including('OK (DRY RUN)') - ).to_stdout + expect { subject } + .to output_results('OK (DRY RUN)') end end @@ -451,9 +451,8 @@ describe Mastodon::CLI::Accounts do let(:options) { { email: '404@example.com' } } it 'exits with an error message indicating that no user was found' do - expect { cli.invoke(:delete, nil, options) }.to output( - a_string_including('No user with such email') - ).to_stdout + expect { subject } + .to output_results('No user with such email') .and raise_error(SystemExit) end end @@ -461,6 +460,7 @@ describe Mastodon::CLI::Accounts do end describe '#approve' do + let(:action) { :approve } let(:total_users) { 4 } before do @@ -469,8 +469,10 @@ describe Mastodon::CLI::Accounts do end context 'with --all option' do + let(:options) { { all: true } } + it 'approves all pending registrations' do - cli.invoke(:approve, nil, all: true) + subject expect(User.pluck(:approved).all?(true)).to be(true) end @@ -481,7 +483,7 @@ describe Mastodon::CLI::Accounts do let(:options) { { number: 2 } } it 'approves the earliest n pending registrations' do - cli.invoke(:approve, nil, options) + subject n_earliest_pending_registrations = User.order(created_at: :asc).first(options[:number]) @@ -489,7 +491,7 @@ describe Mastodon::CLI::Accounts do end it 'does not approve the remaining pending registrations' do - cli.invoke(:approve, nil, options) + subject pending_registrations = User.order(created_at: :asc).last(total_users - options[:number]) @@ -498,10 +500,11 @@ describe Mastodon::CLI::Accounts do end context 'when the number is negative' do + let(:options) { { number: -1 } } + it 'exits with an error message indicating that the number must be positive' do - expect { cli.invoke(:approve, nil, number: -1) }.to output( - a_string_including('Number must be positive') - ).to_stdout + expect { subject } + .to output_results('Number must be positive') .and raise_error(SystemExit) end end @@ -510,13 +513,13 @@ describe Mastodon::CLI::Accounts do let(:options) { { number: total_users * 2 } } it 'approves all users' do - cli.invoke(:approve, nil, options) + subject expect(User.pluck(:approved).all?(true)).to be(true) end it 'does not raise any error' do - expect { cli.invoke(:approve, nil, options) } + expect { subject } .to_not raise_error end end @@ -528,7 +531,7 @@ describe Mastodon::CLI::Accounts do let(:arguments) { [user.account.username] } it 'approves the specified user successfully' do - cli.invoke(:approve, arguments) + subject expect(user.reload.approved?).to be(true) end @@ -538,9 +541,8 @@ describe Mastodon::CLI::Accounts do let(:arguments) { ['non_existent_username'] } it 'exits with an error message indicating that no such account was found' do - expect { cli.invoke(:approve, arguments) }.to output( - a_string_including('No such account') - ).to_stdout + expect { subject } + .to output_results('No such account') .and raise_error(SystemExit) end end @@ -548,13 +550,14 @@ describe Mastodon::CLI::Accounts do end describe '#follow' do + let(:action) { :follow } + context 'when the given username is not found' do let(:arguments) { ['non_existent_username'] } it 'exits with an error message indicating that no account with the given username was found' do - expect { cli.invoke(:follow, arguments) }.to output( - a_string_including('No such account') - ).to_stdout + expect { subject } + .to output_results('No such account') .and raise_error(SystemExit) end end @@ -565,6 +568,7 @@ describe Mastodon::CLI::Accounts do let!(:follower_rony) { Fabricate(:account, username: 'rony') } let!(:follower_charles) { Fabricate(:account, username: 'charles') } let(:follow_service) { instance_double(FollowService, call: nil) } + let(:arguments) { [target_account.username] } before do allow(FollowService).to receive(:new).and_return(follow_service) @@ -572,7 +576,7 @@ describe Mastodon::CLI::Accounts do end it 'makes all local accounts follow the target account' do - cli.follow(target_account.username) + subject expect(follow_service).to have_received(:call).with(follower_bob, target_account, any_args).once expect(follow_service).to have_received(:call).with(follower_rony, target_account, any_args).once @@ -580,21 +584,21 @@ describe Mastodon::CLI::Accounts do end it 'displays a successful message' do - expect { cli.follow(target_account.username) }.to output( - a_string_including("OK, followed target from #{Account.local.count} accounts") - ).to_stdout + expect { subject } + .to output_results("OK, followed target from #{Account.local.count} accounts") end end end describe '#unfollow' do + let(:action) { :unfollow } + context 'when the given username is not found' do let(:arguments) { ['non_existent_username'] } it 'exits with an error message indicating that no account with the given username was found' do - expect { cli.invoke(:unfollow, arguments) }.to output( - a_string_including('No such account') - ).to_stdout + expect { subject } + .to output_results('No such account') .and raise_error(SystemExit) end end @@ -605,6 +609,7 @@ describe Mastodon::CLI::Accounts do let!(:follower_rambo) { Fabricate(:account, username: 'rambo', domain: nil) } let!(:follower_ana) { Fabricate(:account, username: 'ana', domain: nil) } let(:unfollow_service) { instance_double(UnfollowService, call: nil) } + let(:arguments) { [target_account.username] } before do accounts = [follower_chris, follower_rambo, follower_ana] @@ -614,7 +619,7 @@ describe Mastodon::CLI::Accounts do end it 'makes all local accounts unfollow the target account' do - cli.unfollow(target_account.username) + subject expect(unfollow_service).to have_received(:call).with(follower_chris, target_account).once expect(unfollow_service).to have_received(:call).with(follower_rambo, target_account).once @@ -622,21 +627,21 @@ describe Mastodon::CLI::Accounts do end it 'displays a successful message' do - expect { cli.unfollow(target_account.username) }.to output( - a_string_including('OK, unfollowed target from 3 accounts') - ).to_stdout + expect { subject } + .to output_results('OK, unfollowed target from 3 accounts') end end end describe '#backup' do + let(:action) { :backup } + context 'when the given username is not found' do let(:arguments) { ['non_existent_username'] } it 'exits with an error message indicating that there is no such account' do - expect { cli.invoke(:backup, arguments) }.to output( - a_string_including('No user with such username') - ).to_stdout + expect { subject } + .to output_results('No user with such username') .and raise_error(SystemExit) end end @@ -647,22 +652,21 @@ describe Mastodon::CLI::Accounts do let(:arguments) { [account.username] } it 'creates a new backup for the specified user' do - expect { cli.invoke(:backup, arguments) }.to change { user.backups.count }.by(1) + expect { subject }.to change { user.backups.count }.by(1) end it 'creates a backup job' do allow(BackupWorker).to receive(:perform_async) - cli.invoke(:backup, arguments) + subject latest_backup = user.backups.last expect(BackupWorker).to have_received(:perform_async).with(latest_backup.id).once end it 'displays a successful message' do - expect { cli.invoke(:backup, arguments) }.to output( - a_string_including('OK') - ).to_stdout + expect { subject } + .to output_results('OK') end end end @@ -724,9 +728,8 @@ describe Mastodon::CLI::Accounts do end it 'displays a successful message' do - expect { cli.refresh }.to output( - a_string_including('Refreshed 2 accounts') - ).to_stdout + expect { cli.refresh } + .to output_results('Refreshed 2 accounts') end context 'with --dry-run option' do @@ -761,9 +764,8 @@ describe Mastodon::CLI::Accounts do end it 'displays a successful message with (DRY RUN)' do - expect { cli.refresh }.to output( - a_string_including('Refreshed 2 accounts (DRY RUN)') - ).to_stdout + expect { cli.refresh } + .to output_results('Refreshed 2 accounts (DRY RUN)') end end end @@ -823,9 +825,7 @@ describe Mastodon::CLI::Accounts do allow(account_example_com_a).to receive(:reset_avatar!).and_raise(Mastodon::UnexpectedResponseError) expect { cli.refresh(*arguments) } - .to output( - a_string_including("Account failed: #{account_example_com_a.username}@#{account_example_com_a.domain}") - ).to_stdout + .to output_results("Account failed: #{account_example_com_a.username}@#{account_example_com_a.domain}") end end @@ -833,9 +833,8 @@ describe Mastodon::CLI::Accounts do it 'exits with an error message' do allow(Account).to receive(:find_remote).with(account_example_com_b.username, account_example_com_b.domain).and_return(nil) - expect { cli.refresh(*arguments) }.to output( - a_string_including('No such account') - ).to_stdout + expect { cli.refresh(*arguments) } + .to output_results('No such account') .and raise_error(SystemExit) end end @@ -878,7 +877,6 @@ describe Mastodon::CLI::Accounts do allow(cli).to receive(:parallelize_with_progress).and_yield(account_example_com_a) .and_yield(account_example_com_b) .and_return([2, nil]) - cli.options = { domain: domain } end @@ -925,32 +923,33 @@ describe Mastodon::CLI::Accounts do context 'when neither a list of accts nor options are provided' do it 'exits with an error message' do - expect { cli.refresh }.to output( - a_string_including('No account(s) given') - ).to_stdout + expect { cli.refresh } + .to output_results('No account(s) given') .and raise_error(SystemExit) end end end describe '#rotate' do + let(:action) { :rotate } + context 'when neither username nor --all option are given' do it 'exits with an error message' do - expect { cli.rotate }.to output( - a_string_including('No account(s) given') - ).to_stdout + expect { subject } + .to output_results('No account(s) given') .and raise_error(SystemExit) end end context 'when a username is given' do let(:account) { Fabricate(:account) } + let(:arguments) { [account.username] } it 'correctly rotates keys for the specified account' do old_private_key = account.private_key old_public_key = account.public_key - cli.rotate(account.username) + subject account.reload expect(account.private_key).to_not eq(old_private_key) @@ -960,16 +959,17 @@ describe Mastodon::CLI::Accounts do it 'broadcasts the new keys for the specified account' do allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_in) - cli.rotate(account.username) + subject expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_in).with(anything, account.id, anything).once end context 'when the given username is not found' do + let(:arguments) { ['non_existent_username'] } + it 'exits with an error message when the specified username is not found' do - expect { cli.rotate('non_existent_username') }.to output( - a_string_including('No such account') - ).to_stdout + expect { subject } + .to output_results('No such account') .and raise_error(SystemExit) end end @@ -977,17 +977,13 @@ describe Mastodon::CLI::Accounts do context 'when --all option is provided' do let!(:accounts) { Fabricate.times(2, :account) } - let(:options) { { all: true } } - - before do - cli.options = { all: true } - end + let(:options) { { all: true } } it 'correctly rotates keys for all local accounts' do old_private_keys = accounts.map(&:private_key) old_public_keys = accounts.map(&:public_key) - cli.rotate + subject accounts.each(&:reload) expect(accounts.map(&:private_key)).to_not eq(old_private_keys) @@ -997,7 +993,7 @@ describe Mastodon::CLI::Accounts do it 'broadcasts the new keys for each account' do allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_in) - cli.rotate + subject accounts.each do |account| expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_in).with(anything, account.id, anything).once @@ -1007,11 +1003,12 @@ describe Mastodon::CLI::Accounts do end describe '#merge' do + let(:action) { :merge } + shared_examples 'an account not found' do |acct| it 'exits with an error message indicating that there is no such account' do - expect { cli.invoke(:merge, arguments) }.to output( - a_string_including("No such account (#{acct})") - ).to_stdout + expect { subject } + .to output_results("No such account (#{acct})") .and raise_error(SystemExit) end end @@ -1061,9 +1058,8 @@ describe Mastodon::CLI::Accounts do end it 'exits with an error message indicating that the accounts do not have the same pub key' do - expect { cli.invoke(:merge, arguments) }.to output( - a_string_including("Accounts don't have the same public key, might not be duplicates!\nOverride with --force") - ).to_stdout + expect { subject } + .to output_results("Accounts don't have the same public key, might not be duplicates!\nOverride with --force") .and raise_error(SystemExit) end @@ -1076,13 +1072,13 @@ describe Mastodon::CLI::Accounts do end it 'merges "from_account" into "to_account"' do - cli.invoke(:merge, arguments, options) + subject expect(to_account).to have_received(:merge_with!).with(from_account).once end it 'deletes "from_account"' do - cli.invoke(:merge, arguments, options) + subject expect(from_account).to have_received(:destroy).once end @@ -1104,13 +1100,13 @@ describe Mastodon::CLI::Accounts do end it 'merges "from_account" into "to_account"' do - cli.invoke(:merge, arguments) + subject expect(to_account).to have_received(:merge_with!).with(from_account).once end it 'deletes "from_account"' do - cli.invoke(:merge, arguments) + subject expect(from_account).to have_received(:destroy) end @@ -1118,6 +1114,7 @@ describe Mastodon::CLI::Accounts do end describe '#cull' do + let(:action) { :cull } let(:delete_account_service) { instance_double(DeleteAccountService, call: nil) } let!(:tom) { Fabricate(:account, updated_at: 30.days.ago, username: 'tom', uri: 'https://example.com/users/tom', domain: 'example.com', protocol: :activitypub) } let!(:bob) { Fabricate(:account, updated_at: 30.days.ago, last_webfingered_at: nil, username: 'bob', uri: 'https://example.org/users/bob', domain: 'example.org', protocol: :activitypub) } @@ -1138,14 +1135,14 @@ describe Mastodon::CLI::Accounts do end it 'deletes all inactive remote accounts that longer exist in the origin server' do - cli.cull + subject expect(delete_account_service).to have_received(:call).with(bob, reserve_username: false).once expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once end it 'does not delete any active remote account that still exists in the origin server' do - cli.cull + subject expect(delete_account_service).to_not have_received(:call).with(tom, reserve_username: false) expect(delete_account_service).to_not have_received(:call).with(ana, reserve_username: false) @@ -1153,18 +1150,17 @@ describe Mastodon::CLI::Accounts do end it 'touches inactive remote accounts that have not been deleted' do - expect { cli.cull }.to(change { tales.reload.updated_at }) + expect { subject }.to(change { tales.reload.updated_at }) end it 'displays the summary correctly' do - expect { cli.cull }.to output( - a_string_including('Visited 5 accounts, removed 2') - ).to_stdout + expect { subject } + .to output_results('Visited 5 accounts, removed 2') end end context 'when a domain is specified' do - let(:domain) { 'example.net' } + let(:arguments) { ['example.net'] } before do stub_parallelize_with_progress! @@ -1173,16 +1169,15 @@ describe Mastodon::CLI::Accounts do end it 'deletes inactive remote accounts that longer exist in the specified domain' do - cli.cull(domain) + subject expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once expect(delete_account_service).to have_received(:call).with(tales, reserve_username: false).once end it 'displays the summary correctly' do - expect { cli.cull(domain) }.to output( - a_string_including('Visited 2 accounts, removed 2') - ).to_stdout + expect { subject } + .to output_results('Visited 2 accounts, removed 2') end end @@ -1195,15 +1190,14 @@ describe Mastodon::CLI::Accounts do end it 'skips accounts from the unavailable domain' do - cli.cull + subject expect(delete_account_service).to_not have_received(:call).with(tales, reserve_username: false) end it 'displays the summary correctly' do - expect { cli.cull }.to output( - a_string_including("Visited 5 accounts, removed 0\nThe following domains were not available during the check:\n example.net") - ).to_stdout + expect { subject } + .to output_results("Visited 5 accounts, removed 0\nThe following domains were not available during the check:\n example.net") end end @@ -1242,25 +1236,25 @@ describe Mastodon::CLI::Accounts do end describe '#reset_relationships' do + let(:action) { :reset_relationships } let(:target_account) { Fabricate(:account) } let(:arguments) { [target_account.username] } context 'when no option is given' do it 'exits with an error message indicating that at least one option is required' do - expect { cli.invoke(:reset_relationships, arguments) }.to output( - a_string_including('Please specify either --follows or --followers, or both') - ).to_stdout + expect { subject } + .to output_results('Please specify either --follows or --followers, or both') .and raise_error(SystemExit) end end context 'when the given username is not found' do let(:arguments) { ['non_existent_username'] } + let(:options) { { follows: true } } it 'exits with an error message indicating that there is no such account' do - expect { cli.invoke(:reset_relationships, arguments, follows: true) }.to output( - a_string_including('No such account') - ).to_stdout + expect { subject } + .to output_results('No such account') .and raise_error(SystemExit) end end @@ -1277,7 +1271,7 @@ describe Mastodon::CLI::Accounts do end it 'resets all "following" relationships from the target account' do - cli.invoke(:reset_relationships, arguments, options) + subject expect(target_account.reload.following).to be_empty end @@ -1285,15 +1279,14 @@ describe Mastodon::CLI::Accounts do it 'calls BootstrapTimelineWorker once to rebuild the timeline' do allow(BootstrapTimelineWorker).to receive(:perform_async) - cli.invoke(:reset_relationships, arguments, options) + subject expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once end it 'displays a successful message' do - expect { cli.invoke(:reset_relationships, arguments, options) }.to output( - a_string_including("Processed #{total_relationships} relationships") - ).to_stdout + expect { subject } + .to output_results("Processed #{total_relationships} relationships") end end @@ -1305,15 +1298,14 @@ describe Mastodon::CLI::Accounts do end it 'resets all "followers" relationships from the target account' do - cli.invoke(:reset_relationships, arguments, options) + subject expect(target_account.reload.followers).to be_empty end it 'displays a successful message' do - expect { cli.invoke(:reset_relationships, arguments, options) }.to output( - a_string_including("Processed #{total_relationships} relationships") - ).to_stdout + expect { subject } + .to output_results("Processed #{total_relationships} relationships") end end @@ -1326,13 +1318,13 @@ describe Mastodon::CLI::Accounts do end it 'resets all "followers" relationships from the target account' do - cli.invoke(:reset_relationships, arguments, options) + subject expect(target_account.reload.followers).to be_empty end it 'resets all "following" relationships from the target account' do - cli.invoke(:reset_relationships, arguments, options) + subject expect(target_account.reload.following).to be_empty end @@ -1340,21 +1332,21 @@ describe Mastodon::CLI::Accounts do it 'calls BootstrapTimelineWorker once to rebuild the timeline' do allow(BootstrapTimelineWorker).to receive(:perform_async) - cli.invoke(:reset_relationships, arguments, options) + subject expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once end it 'displays a successful message' do - expect { cli.invoke(:reset_relationships, arguments, options) }.to output( - a_string_including("Processed #{total_relationships} relationships") - ).to_stdout + expect { subject } + .to output_results("Processed #{total_relationships} relationships") end end end end describe '#prune' do + let(:action) { :prune } let!(:local_account) { Fabricate(:account) } let!(:bot_account) { Fabricate(:account, bot: true, domain: 'example.com') } let!(:group_account) { Fabricate(:account, actor_type: 'Group', domain: 'example.com') } @@ -1369,7 +1361,7 @@ describe Mastodon::CLI::Accounts do end it 'prunes all remote accounts with no interactions with local users' do - cli.prune + subject prunable_account_ids = prunable_accounts.pluck(:id) @@ -1377,42 +1369,39 @@ describe Mastodon::CLI::Accounts do end it 'displays a successful message' do - expect { cli.prune }.to output( - a_string_including("OK, pruned #{prunable_accounts.size} accounts") - ).to_stdout + expect { subject } + .to output_results("OK, pruned #{prunable_accounts.size} accounts") end it 'does not prune local accounts' do - cli.prune + subject expect(Account.exists?(id: local_account.id)).to be(true) end it 'does not prune bot accounts' do - cli.prune + subject expect(Account.exists?(id: bot_account.id)).to be(true) end it 'does not prune group accounts' do - cli.prune + subject expect(Account.exists?(id: group_account.id)).to be(true) end it 'does not prune accounts that have been mentioned' do - cli.prune + subject expect(Account.exists?(id: mentioned_account.id)).to be true end context 'with --dry-run option' do - before do - cli.options = { dry_run: true } - end + let(:options) { { dry_run: true } } it 'does not prune any account' do - cli.prune + subject prunable_account_ids = prunable_accounts.pluck(:id) @@ -1420,14 +1409,14 @@ describe Mastodon::CLI::Accounts do end it 'displays a successful message with (DRY RUN)' do - expect { cli.prune }.to output( - a_string_including("OK, pruned #{prunable_accounts.size} accounts (DRY RUN)") - ).to_stdout + expect { subject } + .to output_results("OK, pruned #{prunable_accounts.size} accounts (DRY RUN)") end end end describe '#migrate' do + let(:action) { :migrate } let!(:source_account) { Fabricate(:account) } let!(:target_account) { Fabricate(:account, domain: 'example.com') } let(:arguments) { [source_account.username] } @@ -1441,7 +1430,7 @@ describe Mastodon::CLI::Accounts do shared_examples 'a successful migration' do it 'calls the MoveService for the last migration' do - cli.invoke(:migrate, arguments, options) + subject last_migration = source_account.migrations.last @@ -1449,9 +1438,8 @@ describe Mastodon::CLI::Accounts do end it 'displays a successful message' do - expect { cli.invoke(:migrate, arguments, options) }.to output( - a_string_including("OK, migrated #{source_account.acct} to #{target_account.acct}") - ).to_stdout + expect { subject } + .to output_results("OK, migrated #{source_account.acct} to #{target_account.acct}") end end @@ -1459,29 +1447,27 @@ describe Mastodon::CLI::Accounts do let(:options) { { replay: true, target: "#{target_account.username}@example.com" } } it 'exits with an error message indicating that using both options is not possible' do - expect { cli.invoke(:migrate, arguments, options) }.to output( - a_string_including('Use --replay or --target, not both') - ).to_stdout + expect { subject } + .to output_results('Use --replay or --target, not both') .and raise_error(SystemExit) end end context 'when no option is given' do it 'exits with an error message indicating that at least one option must be used' do - expect { cli.invoke(:migrate, arguments, {}) }.to output( - a_string_including('Use either --replay or --target') - ).to_stdout + expect { subject } + .to output_results('Use either --replay or --target') .and raise_error(SystemExit) end end context 'when the given username is not found' do let(:arguments) { ['non_existent_username'] } + let(:options) { { replay: true } } it 'exits with an error message indicating that there is no such account' do - expect { cli.invoke(:migrate, arguments, replay: true) }.to output( - a_string_including("No such account: #{arguments.first}") - ).to_stdout + expect { subject } + .to output_results("No such account: #{arguments.first}") .and raise_error(SystemExit) end end @@ -1491,9 +1477,8 @@ describe Mastodon::CLI::Accounts do context 'when the specified account has no previous migrations' do it 'exits with an error message indicating that the given account has no previous migrations' do - expect { cli.invoke(:migrate, arguments, options) }.to output( - a_string_including('The specified account has not performed any migration') - ).to_stdout + expect { subject } + .to output_results('The specified account has not performed any migration') .and raise_error(SystemExit) end end @@ -1515,9 +1500,8 @@ describe Mastodon::CLI::Accounts do end it 'exits with an error message' do - expect { cli.invoke(:migrate, arguments, options) }.to output( - a_string_including('The specified account is not redirecting to its last migration target. Use --force if you want to replay the migration anyway') - ).to_stdout + expect { subject } + .to output_results('The specified account is not redirecting to its last migration target. Use --force if you want to replay the migration anyway') .and raise_error(SystemExit) end end @@ -1544,9 +1528,8 @@ describe Mastodon::CLI::Accounts do end it 'exits with an error message indicating that there is no such account' do - expect { cli.invoke(:migrate, arguments, options) }.to output( - a_string_including("The specified target account could not be found: #{options[:target]}") - ).to_stdout + expect { subject } + .to output_results("The specified target account could not be found: #{options[:target]}") .and raise_error(SystemExit) end end @@ -1557,7 +1540,7 @@ describe Mastodon::CLI::Accounts do end it 'creates a migration for the specified account with the target account' do - cli.invoke(:migrate, arguments, options) + subject last_migration = source_account.migrations.last @@ -1569,9 +1552,8 @@ describe Mastodon::CLI::Accounts do context 'when the migration record is invalid' do it 'exits with an error indicating that the validation failed' do - expect { cli.invoke(:migrate, arguments, options) }.to output( - a_string_including('Error: Validation failed') - ).to_stdout + expect { subject } + .to output_results('Error: Validation failed') .and raise_error(SystemExit) end end @@ -1582,9 +1564,8 @@ describe Mastodon::CLI::Accounts do end it 'exits with an error message' do - expect { cli.invoke(:migrate, arguments, options) }.to output( - a_string_including('The specified account is redirecting to a different target account. Use --force if you want to change the migration target') - ).to_stdout + expect { subject } + .to output_results('The specified account is redirecting to a different target account. Use --force if you want to change the migration target') .and raise_error(SystemExit) end end diff --git a/spec/lib/mastodon/cli/cache_spec.rb b/spec/lib/mastodon/cli/cache_spec.rb index c1ce04710..b1515801e 100644 --- a/spec/lib/mastodon/cli/cache_spec.rb +++ b/spec/lib/mastodon/cli/cache_spec.rb @@ -4,22 +4,29 @@ require 'rails_helper' require 'mastodon/cli/cache' describe Mastodon::CLI::Cache do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' describe '#clear' do + let(:action) { :clear } + before { allow(Rails.cache).to receive(:clear) } it 'clears the Rails cache' do - expect { cli.invoke(:clear) }.to output( - a_string_including('OK') - ).to_stdout + expect { subject } + .to output_results('OK') expect(Rails.cache).to have_received(:clear) end end describe '#recount' do + let(:action) { :recount } + context 'with the `accounts` argument' do let(:arguments) { ['accounts'] } let(:account_stat) { Fabricate(:account_stat) } @@ -29,9 +36,8 @@ describe Mastodon::CLI::Cache do end it 're-calculates account records in the cache' do - expect { cli.invoke(:recount, arguments) }.to output( - a_string_including('OK') - ).to_stdout + expect { subject } + .to output_results('OK') expect(account_stat.reload.statuses_count).to be_zero end @@ -46,9 +52,8 @@ describe Mastodon::CLI::Cache do end it 're-calculates account records in the cache' do - expect { cli.invoke(:recount, arguments) }.to output( - a_string_including('OK') - ).to_stdout + expect { subject } + .to output_results('OK') expect(status_stat.reload.replies_count).to be_zero end @@ -58,9 +63,9 @@ describe Mastodon::CLI::Cache do let(:arguments) { ['other-type'] } it 'Exits with an error message' do - expect { cli.invoke(:recount, arguments) }.to output( - a_string_including('Unknown') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('Unknown') + .and raise_error(SystemExit) end end end diff --git a/spec/lib/mastodon/cli/canonical_email_blocks_spec.rb b/spec/lib/mastodon/cli/canonical_email_blocks_spec.rb index 6e4675748..1745ea01b 100644 --- a/spec/lib/mastodon/cli/canonical_email_blocks_spec.rb +++ b/spec/lib/mastodon/cli/canonical_email_blocks_spec.rb @@ -4,42 +4,45 @@ require 'rails_helper' require 'mastodon/cli/canonical_email_blocks' describe Mastodon::CLI::CanonicalEmailBlocks do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' describe '#find' do + let(:action) { :find } let(:arguments) { ['user@example.com'] } context 'when a block is present' do before { Fabricate(:canonical_email_block, email: 'user@example.com') } it 'announces the presence of the block' do - expect { cli.invoke(:find, arguments) }.to output( - a_string_including('user@example.com is blocked') - ).to_stdout + expect { subject } + .to output_results('user@example.com is blocked') end end context 'when a block is not present' do it 'announces the absence of the block' do - expect { cli.invoke(:find, arguments) }.to output( - a_string_including('user@example.com is not blocked') - ).to_stdout + expect { subject } + .to output_results('user@example.com is not blocked') end end end describe '#remove' do + let(:action) { :remove } let(:arguments) { ['user@example.com'] } context 'when a block is present' do before { Fabricate(:canonical_email_block, email: 'user@example.com') } it 'removes the block' do - expect { cli.invoke(:remove, arguments) }.to output( - a_string_including('Unblocked user@example.com') - ).to_stdout + expect { subject } + .to output_results('Unblocked user@example.com') expect(CanonicalEmailBlock.matching_email('user@example.com')).to be_empty end @@ -47,9 +50,8 @@ describe Mastodon::CLI::CanonicalEmailBlocks do context 'when a block is not present' do it 'announces the absence of the block' do - expect { cli.invoke(:remove, arguments) }.to output( - a_string_including('user@example.com is not blocked') - ).to_stdout + expect { subject } + .to output_results('user@example.com is not blocked') end end end diff --git a/spec/lib/mastodon/cli/domains_spec.rb b/spec/lib/mastodon/cli/domains_spec.rb index add754159..a10907f76 100644 --- a/spec/lib/mastodon/cli/domains_spec.rb +++ b/spec/lib/mastodon/cli/domains_spec.rb @@ -4,20 +4,26 @@ require 'rails_helper' require 'mastodon/cli/domains' describe Mastodon::CLI::Domains do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' describe '#purge' do + let(:action) { :purge } + context 'with accounts from the domain' do - let(:options) { {} } let(:domain) { 'host.example' } let!(:account) { Fabricate(:account, domain: domain) } + let(:arguments) { [domain] } it 'removes the account' do - expect { cli.invoke(:purge, [domain], options) }.to output( - a_string_including('Removed 1 accounts') - ).to_stdout + expect { subject } + .to output_results('Removed 1 accounts') + expect { account.reload }.to raise_error(ActiveRecord::RecordNotFound) end end diff --git a/spec/lib/mastodon/cli/email_domain_blocks_spec.rb b/spec/lib/mastodon/cli/email_domain_blocks_spec.rb index f5cb6c332..13deb05b6 100644 --- a/spec/lib/mastodon/cli/email_domain_blocks_spec.rb +++ b/spec/lib/mastodon/cli/email_domain_blocks_spec.rb @@ -4,96 +4,99 @@ require 'rails_helper' require 'mastodon/cli/email_domain_blocks' describe Mastodon::CLI::EmailDomainBlocks do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' describe '#list' do + let(:action) { :list } + context 'with email domain block records' do let!(:parent_block) { Fabricate(:email_domain_block) } let!(:child_block) { Fabricate(:email_domain_block, parent: parent_block) } - let(:options) { {} } it 'lists the blocks' do - expect { cli.invoke(:list, [], options) }.to output( - a_string_including(parent_block.domain) - .and(a_string_including(child_block.domain)) - ).to_stdout + expect { subject } + .to output_results( + parent_block.domain, + child_block.domain + ) end end end describe '#add' do - context 'without any options' do - let(:options) { {} } + let(:action) { :add } + context 'without any options' do it 'warns about usage and exits' do - expect { cli.invoke(:add, [], options) }.to output( - a_string_including('No domain(s) given') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('No domain(s) given') + .and raise_error(SystemExit) end end context 'when blocks exist' do let(:options) { {} } let(:domain) { 'host.example' } + let(:arguments) { [domain] } before { Fabricate(:email_domain_block, domain: domain) } it 'does not add a new block' do - expect { cli.invoke(:add, [domain], options) }.to output( - a_string_including('is already blocked') - ).to_stdout + expect { subject } + .to output_results('is already blocked') .and(not_change(EmailDomainBlock, :count)) end end context 'when no blocks exist' do - let(:options) { {} } let(:domain) { 'host.example' } + let(:arguments) { [domain] } it 'adds a new block' do - expect { cli.invoke(:add, [domain], options) }.to output( - a_string_including('Added 1') - ).to_stdout + expect { subject } + .to output_results('Added 1') .and(change(EmailDomainBlock, :count).by(1)) end end end describe '#remove' do - context 'without any options' do - let(:options) { {} } + let(:action) { :remove } + context 'without any options' do it 'warns about usage and exits' do - expect { cli.invoke(:remove, [], options) }.to output( - a_string_including('No domain(s) given') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('No domain(s) given') + .and raise_error(SystemExit) end end context 'when blocks exist' do - let(:options) { {} } let(:domain) { 'host.example' } + let(:arguments) { [domain] } before { Fabricate(:email_domain_block, domain: domain) } it 'removes the block' do - expect { cli.invoke(:remove, [domain], options) }.to output( - a_string_including('Removed 1') - ).to_stdout + expect { subject } + .to output_results('Removed 1') .and(change(EmailDomainBlock, :count).by(-1)) end end context 'when no blocks exist' do - let(:options) { {} } let(:domain) { 'host.example' } + let(:arguments) { [domain] } it 'does not remove a block' do - expect { cli.invoke(:remove, [domain], options) }.to output( - a_string_including('is not yet blocked') - ).to_stdout + expect { subject } + .to output_results('is not yet blocked') .and(not_change(EmailDomainBlock, :count)) end end diff --git a/spec/lib/mastodon/cli/emoji_spec.rb b/spec/lib/mastodon/cli/emoji_spec.rb index 3441413b9..d05e972e7 100644 --- a/spec/lib/mastodon/cli/emoji_spec.rb +++ b/spec/lib/mastodon/cli/emoji_spec.rb @@ -4,10 +4,10 @@ require 'rails_helper' require 'mastodon/cli/emoji' describe Mastodon::CLI::Emoji do - subject { cli.invoke(action, args, options) } + subject { cli.invoke(action, arguments, options) } let(:cli) { described_class.new } - let(:args) { [] } + let(:arguments) { [] } let(:options) { {} } it_behaves_like 'CLI Command' @@ -29,7 +29,7 @@ describe Mastodon::CLI::Emoji do context 'with existing custom emoji' do let(:import_path) { Rails.root.join('spec', 'fixtures', 'files', 'elite-assets.tar.gz') } let(:action) { :import } - let(:args) { [import_path] } + let(:arguments) { [import_path] } it 'reports about imported emoji' do expect { subject } @@ -51,7 +51,7 @@ describe Mastodon::CLI::Emoji do after { FileUtils.rm_rf(export_path.dirname) } let(:export_path) { Rails.root.join('tmp', 'cli-tests', 'export.tar.gz') } - let(:args) { [export_path.dirname.to_s] } + let(:arguments) { [export_path.dirname.to_s] } let(:action) { :export } it 'reports about exported emoji' do @@ -61,8 +61,4 @@ describe Mastodon::CLI::Emoji do end end end - - def output_results(string) - output(a_string_including(string)).to_stdout - end end diff --git a/spec/lib/mastodon/cli/feeds_spec.rb b/spec/lib/mastodon/cli/feeds_spec.rb index e16113c85..199798052 100644 --- a/spec/lib/mastodon/cli/feeds_spec.rb +++ b/spec/lib/mastodon/cli/feeds_spec.rb @@ -4,20 +4,25 @@ require 'rails_helper' require 'mastodon/cli/feeds' describe Mastodon::CLI::Feeds do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' describe '#build' do + let(:action) { :build } + before { Fabricate(:account) } context 'with --all option' do let(:options) { { all: true } } it 'regenerates feeds for all accounts' do - expect { cli.invoke(:build, [], options) }.to output( - a_string_including('Regenerated feeds') - ).to_stdout + expect { subject } + .to output_results('Regenerated feeds') end end @@ -27,9 +32,8 @@ describe Mastodon::CLI::Feeds do let(:arguments) { ['alice'] } it 'regenerates feeds for the account' do - expect { cli.invoke(:build, arguments) }.to output( - a_string_including('OK') - ).to_stdout + expect { subject } + .to output_results('OK') end end @@ -37,22 +41,23 @@ describe Mastodon::CLI::Feeds do let(:arguments) { ['invalid-username'] } it 'displays an error and exits' do - expect { cli.invoke(:build, arguments) }.to output( - a_string_including('No such account') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('No such account') + .and raise_error(SystemExit) end end end describe '#clear' do + let(:action) { :clear } + before do allow(redis).to receive(:del).with(key_namespace) end it 'clears the redis `feed:*` namespace' do - expect { cli.invoke(:clear) }.to output( - a_string_including('OK') - ).to_stdout + expect { subject } + .to output_results('OK') expect(redis).to have_received(:del).with(key_namespace).once end diff --git a/spec/lib/mastodon/cli/ip_blocks_spec.rb b/spec/lib/mastodon/cli/ip_blocks_spec.rb index 684314dc7..dc967a69c 100644 --- a/spec/lib/mastodon/cli/ip_blocks_spec.rb +++ b/spec/lib/mastodon/cli/ip_blocks_spec.rb @@ -4,11 +4,16 @@ require 'rails_helper' require 'mastodon/cli/ip_blocks' describe Mastodon::CLI::IpBlocks do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' describe '#add' do + let(:action) { :add } let(:ip_list) do [ '192.0.2.1', @@ -25,10 +30,11 @@ describe Mastodon::CLI::IpBlocks do ] end let(:options) { { severity: 'no_access' } } + let(:arguments) { ip_list } shared_examples 'ip address blocking' do it 'blocks all specified IP addresses' do - cli.invoke(:add, ip_list, options) + subject blocked_ip_addresses = IpBlock.where(ip: ip_list).pluck(:ip) expected_ip_addresses = ip_list.map { |ip| IPAddr.new(ip) } @@ -37,7 +43,7 @@ describe Mastodon::CLI::IpBlocks do end it 'sets the severity for all blocked IP addresses' do - cli.invoke(:add, ip_list, options) + subject blocked_ips_severity = IpBlock.where(ip: ip_list).pluck(:severity).all?(options[:severity]) @@ -45,9 +51,8 @@ describe Mastodon::CLI::IpBlocks do end it 'displays a success message with a summary' do - expect { cli.invoke(:add, ip_list, options) }.to output( - a_string_including("Added #{ip_list.size}, skipped 0, failed 0") - ).to_stdout + expect { subject } + .to output_results("Added #{ip_list.size}, skipped 0, failed 0") end end @@ -57,19 +62,19 @@ describe Mastodon::CLI::IpBlocks do context 'when a specified IP address is already blocked' do let!(:blocked_ip) { IpBlock.create(ip: ip_list.last, severity: options[:severity]) } + let(:arguments) { ip_list } it 'skips the already blocked IP address' do allow(IpBlock).to receive(:new).and_call_original - cli.invoke(:add, ip_list, options) + subject expect(IpBlock).to_not have_received(:new).with(ip: ip_list.last) end it 'displays the correct summary' do - expect { cli.invoke(:add, ip_list, options) }.to output( - a_string_including("#{ip_list.last} is already blocked\nAdded #{ip_list.size - 1}, skipped 1, failed 0") - ).to_stdout + expect { subject } + .to output_results("#{ip_list.last} is already blocked\nAdded #{ip_list.size - 1}, skipped 1, failed 0") end context 'with --force option' do @@ -77,7 +82,7 @@ describe Mastodon::CLI::IpBlocks do let(:options) { { severity: 'sign_up_requires_approval', force: true } } it 'overwrites the existing IP block record' do - expect { cli.invoke(:add, ip_list, options) } + expect { subject } .to change { blocked_ip.reload.severity } .from('no_access') .to('sign_up_requires_approval') @@ -89,11 +94,11 @@ describe Mastodon::CLI::IpBlocks do context 'when a specified IP address is invalid' do let(:ip_list) { ['320.15.175.0', '9.5.105.255', '0.0.0.0'] } + let(:arguments) { ip_list } it 'displays the correct summary' do - expect { cli.invoke(:add, ip_list, options) }.to output( - a_string_including("#{ip_list.first} is invalid\nAdded #{ip_list.size - 1}, skipped 0, failed 1") - ).to_stdout + expect { subject } + .to output_results("#{ip_list.first} is invalid\nAdded #{ip_list.size - 1}, skipped 0, failed 1") end end @@ -124,6 +129,7 @@ describe Mastodon::CLI::IpBlocks do context 'when a specified IP address fails to be blocked' do let(:ip_address) { '127.0.0.1' } let(:ip_block) { instance_double(IpBlock, ip: ip_address, save: false) } + let(:arguments) { [ip_address] } before do allow(IpBlock).to receive(:new).and_return(ip_block) @@ -132,24 +138,25 @@ describe Mastodon::CLI::IpBlocks do end it 'displays an error message' do - expect { cli.invoke(:add, [ip_address], options) } - .to output( - a_string_including("#{ip_address} could not be saved") - ).to_stdout + expect { subject } + .to output_results("#{ip_address} could not be saved") end end context 'when no IP address is provided' do + let(:arguments) { [] } + it 'exits with an error message' do - expect { cli.add }.to output( - a_string_including('No IP(s) given') - ).to_stdout + expect { subject } + .to output_results('No IP(s) given') .and raise_error(SystemExit) end end end describe '#remove' do + let(:action) { :remove } + context 'when removing exact matches' do let(:ip_list) do [ @@ -166,21 +173,21 @@ describe Mastodon::CLI::IpBlocks do '::/128', ] end + let(:arguments) { ip_list } before do ip_list.each { |ip| IpBlock.create(ip: ip, severity: :no_access) } end it 'removes exact IP blocks' do - cli.invoke(:remove, ip_list) + subject expect(IpBlock.where(ip: ip_list)).to_not exist end it 'displays success message with a summary' do - expect { cli.invoke(:remove, ip_list) }.to output( - a_string_including("Removed #{ip_list.size}, skipped 0") - ).to_stdout + expect { subject } + .to output_results("Removed #{ip_list.size}, skipped 0") end end @@ -192,13 +199,13 @@ describe Mastodon::CLI::IpBlocks do let(:options) { { force: true } } it 'removes blocks for IP ranges that cover given IP(s)' do - cli.invoke(:remove, arguments, options) + subject expect(IpBlock.where(id: [first_ip_range_block.id, second_ip_range_block.id])).to_not exist end it 'does not remove other IP ranges' do - cli.invoke(:remove, arguments, options) + subject expect(IpBlock.where(id: third_ip_range_block.id)).to exist end @@ -206,47 +213,46 @@ describe Mastodon::CLI::IpBlocks do context 'when a specified IP address is not blocked' do let(:unblocked_ip) { '192.0.2.1' } + let(:arguments) { [unblocked_ip] } it 'skips the IP address' do - expect { cli.invoke(:remove, [unblocked_ip]) }.to output( - a_string_including("#{unblocked_ip} is not yet blocked") - ).to_stdout + expect { subject } + .to output_results("#{unblocked_ip} is not yet blocked") end it 'displays the summary correctly' do - expect { cli.invoke(:remove, [unblocked_ip]) }.to output( - a_string_including('Removed 0, skipped 1') - ).to_stdout + expect { subject } + .to output_results('Removed 0, skipped 1') end end context 'when a specified IP address is invalid' do let(:invalid_ip) { '320.15.175.0' } + let(:arguments) { [invalid_ip] } it 'skips the invalid IP address' do - expect { cli.invoke(:remove, [invalid_ip]) }.to output( - a_string_including("#{invalid_ip} is invalid") - ).to_stdout + expect { subject } + .to output_results("#{invalid_ip} is invalid") end it 'displays the summary correctly' do - expect { cli.invoke(:remove, [invalid_ip]) }.to output( - a_string_including('Removed 0, skipped 1') - ).to_stdout + expect { subject } + .to output_results('Removed 0, skipped 1') end end context 'when no IP address is provided' do it 'exits with an error message' do - expect { cli.remove }.to output( - a_string_including('No IP(s) given') - ).to_stdout + expect { subject } + .to output_results('No IP(s) given') .and raise_error(SystemExit) end end end describe '#export' do + let(:action) { :export } + let(:first_ip_range_block) { IpBlock.create(ip: '192.168.0.0/24', severity: :no_access) } let(:second_ip_range_block) { IpBlock.create(ip: '10.0.0.0/16', severity: :no_access) } let(:third_ip_range_block) { IpBlock.create(ip: '127.0.0.1', severity: :sign_up_block) } @@ -255,15 +261,13 @@ describe Mastodon::CLI::IpBlocks do let(:options) { { format: 'plain' } } it 'exports blocked IPs with "no_access" severity in plain format' do - expect { cli.invoke(:export, nil, options) }.to output( - a_string_including("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}") - ).to_stdout + expect { subject } + .to output_results("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}") end it 'does not export bloked IPs with different severities' do - expect { cli.invoke(:export, nil, options) }.to_not output( - a_string_including("#{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}") - ).to_stdout + expect { subject } + .to_not output_results("#{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}") end end @@ -271,23 +275,20 @@ describe Mastodon::CLI::IpBlocks do let(:options) { { format: 'nginx' } } it 'exports blocked IPs with "no_access" severity in plain format' do - expect { cli.invoke(:export, nil, options) }.to output( - a_string_including("deny #{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};\ndeny #{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix};") - ).to_stdout + expect { subject } + .to output_results("deny #{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};\ndeny #{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix};") end it 'does not export bloked IPs with different severities' do - expect { cli.invoke(:export, nil, options) }.to_not output( - a_string_including("deny #{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};") - ).to_stdout + expect { subject } + .to_not output_results("deny #{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};") end end context 'when --format option is not provided' do it 'exports blocked IPs in plain format by default' do - expect { cli.export }.to output( - a_string_including("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}") - ).to_stdout + expect { subject } + .to output_results("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}") end end end diff --git a/spec/lib/mastodon/cli/main_spec.rb b/spec/lib/mastodon/cli/main_spec.rb index b5b5d6906..59f1fc478 100644 --- a/spec/lib/mastodon/cli/main_spec.rb +++ b/spec/lib/mastodon/cli/main_spec.rb @@ -4,13 +4,20 @@ require 'rails_helper' require 'mastodon/cli/main' describe Mastodon::CLI::Main do + subject { cli.invoke(action, arguments, options) } + + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } + it_behaves_like 'CLI Command' - describe 'version' do + describe '#version' do + let(:action) { :version } + it 'returns the Mastodon version' do - expect { described_class.new.invoke(:version) }.to output( - a_string_including(Mastodon::Version.to_s) - ).to_stdout + expect { subject } + .to output_results(Mastodon::Version.to_s) end end end diff --git a/spec/lib/mastodon/cli/maintenance_spec.rb b/spec/lib/mastodon/cli/maintenance_spec.rb index 95e695ab5..02169b7a4 100644 --- a/spec/lib/mastodon/cli/maintenance_spec.rb +++ b/spec/lib/mastodon/cli/maintenance_spec.rb @@ -4,20 +4,26 @@ require 'rails_helper' require 'mastodon/cli/maintenance' describe Mastodon::CLI::Maintenance do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' describe '#fix_duplicates' do + let(:action) { :fix_duplicates } + context 'when the database version is too old' do before do allow(ActiveRecord::Migrator).to receive(:current_version).and_return(2000_01_01_000000) # Earlier than minimum end it 'Exits with error message' do - expect { cli.invoke :fix_duplicates }.to output( - a_string_including('is too old') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('is too old') + .and raise_error(SystemExit) end end @@ -28,9 +34,9 @@ describe Mastodon::CLI::Maintenance do end it 'Exits with error message' do - expect { cli.invoke :fix_duplicates }.to output( - a_string_including('more recent') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('more recent') + .and raise_error(SystemExit) end end @@ -41,9 +47,9 @@ describe Mastodon::CLI::Maintenance do end it 'Exits with error message' do - expect { cli.invoke :fix_duplicates }.to output( - a_string_including('Sidekiq is running') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('Sidekiq is running') + .and raise_error(SystemExit) end end end diff --git a/spec/lib/mastodon/cli/media_spec.rb b/spec/lib/mastodon/cli/media_spec.rb index 6d510c1f5..6bbe7e746 100644 --- a/spec/lib/mastodon/cli/media_spec.rb +++ b/spec/lib/mastodon/cli/media_spec.rb @@ -4,18 +4,24 @@ require 'rails_helper' require 'mastodon/cli/media' describe Mastodon::CLI::Media do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' describe '#remove' do + let(:action) { :remove } + context 'with --prune-profiles and --remove-headers' do let(:options) { { prune_profiles: true, remove_headers: true } } it 'warns about usage and exits' do - expect { cli.invoke(:remove, [], options) }.to output( - a_string_including('--prune-profiles and --remove-headers should not be specified simultaneously') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('--prune-profiles and --remove-headers should not be specified simultaneously') + .and raise_error(SystemExit) end end @@ -23,9 +29,9 @@ describe Mastodon::CLI::Media do let(:options) { { include_follows: true } } it 'warns about usage and exits' do - expect { cli.invoke(:remove, [], options) }.to output( - a_string_including('--include-follows can only be used with --prune-profiles or --remove-headers') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('--include-follows can only be used with --prune-profiles or --remove-headers') + .and raise_error(SystemExit) end end @@ -38,9 +44,8 @@ describe Mastodon::CLI::Media do let(:options) { { prune_profiles: true } } it 'removes account avatars' do - expect { cli.invoke(:remove, [], options) }.to output( - a_string_including('Visited 1') - ).to_stdout + expect { subject } + .to output_results('Visited 1') expect(account.reload.avatar).to be_blank end @@ -50,9 +55,8 @@ describe Mastodon::CLI::Media do let(:options) { { remove_headers: true } } it 'removes account header' do - expect { cli.invoke(:remove, [], options) }.to output( - a_string_including('Visited 1') - ).to_stdout + expect { subject } + .to output_results('Visited 1') expect(account.reload.header).to be_blank end @@ -64,9 +68,8 @@ describe Mastodon::CLI::Media do context 'without options' do it 'removes account avatars' do - expect { cli.invoke(:remove) }.to output( - a_string_including('Removed 1') - ).to_stdout + expect { subject } + .to output_results('Removed 1') expect(media_attachment.reload.file).to be_blank expect(media_attachment.reload.thumbnail).to be_blank @@ -76,25 +79,24 @@ describe Mastodon::CLI::Media do end describe '#usage' do - context 'without options' do - let(:options) { {} } + let(:action) { :usage } + context 'without options' do it 'reports about storage size' do - expect { cli.invoke(:usage, [], options) }.to output( - a_string_including('0 Bytes') - ).to_stdout + expect { subject } + .to output_results('0 Bytes') end end end describe '#refresh' do - context 'without any options' do - let(:options) { {} } + let(:action) { :refresh } + context 'without any options' do it 'warns about usage and exits' do - expect { cli.invoke(:refresh, [], options) }.to output( - a_string_including('Specify the source') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('Specify the source') + .and raise_error(SystemExit) end end @@ -108,9 +110,8 @@ describe Mastodon::CLI::Media do let(:status) { Fabricate(:status) } it 'redownloads the attachment file' do - expect { cli.invoke(:refresh, [], options) }.to output( - a_string_including('Downloaded 1 media') - ).to_stdout + expect { subject } + .to output_results('Downloaded 1 media') end end @@ -119,9 +120,9 @@ describe Mastodon::CLI::Media do let(:options) { { account: 'not-real-user@example.host' } } it 'warns about usage and exits' do - expect { cli.invoke(:refresh, [], options) }.to output( - a_string_including('No such account') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('No such account') + .and raise_error(SystemExit) end end @@ -135,9 +136,8 @@ describe Mastodon::CLI::Media do let(:account) { Fabricate(:account) } it 'redownloads the attachment file' do - expect { cli.invoke(:refresh, [], options) }.to output( - a_string_including('Downloaded 1 media') - ).to_stdout + expect { subject } + .to output_results('Downloaded 1 media') end end end @@ -153,9 +153,8 @@ describe Mastodon::CLI::Media do let(:account) { Fabricate(:account, domain: domain) } it 'redownloads the attachment file' do - expect { cli.invoke(:refresh, [], options) }.to output( - a_string_including('Downloaded 1 media') - ).to_stdout + expect { subject } + .to output_results('Downloaded 1 media') end end end diff --git a/spec/lib/mastodon/cli/preview_cards_spec.rb b/spec/lib/mastodon/cli/preview_cards_spec.rb index a766d250e..951ae3758 100644 --- a/spec/lib/mastodon/cli/preview_cards_spec.rb +++ b/spec/lib/mastodon/cli/preview_cards_spec.rb @@ -4,11 +4,17 @@ require 'rails_helper' require 'mastodon/cli/preview_cards' describe Mastodon::CLI::PreviewCards do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' describe '#remove' do + let(:action) { :remove } + context 'with relevant preview cards' do before do Fabricate(:preview_card, updated_at: 10.years.ago, type: :link) @@ -18,10 +24,11 @@ describe Mastodon::CLI::PreviewCards do context 'with no arguments' do it 'deletes thumbnails for local preview cards' do - expect { cli.invoke(:remove) }.to output( - a_string_including('Removed 2 preview cards') - .and(a_string_including('approx. 119 KB')) - ).to_stdout + expect { subject } + .to output_results( + 'Removed 2 preview cards', + 'approx. 119 KB' + ) end end @@ -29,10 +36,11 @@ describe Mastodon::CLI::PreviewCards do let(:options) { { link: true } } it 'deletes thumbnails for local preview cards' do - expect { cli.invoke(:remove, [], options) }.to output( - a_string_including('Removed 1 link-type preview cards') - .and(a_string_including('approx. 59.6 KB')) - ).to_stdout + expect { subject } + .to output_results( + 'Removed 1 link-type preview cards', + 'approx. 59.6 KB' + ) end end @@ -40,10 +48,11 @@ describe Mastodon::CLI::PreviewCards do let(:options) { { days: 365 } } it 'deletes thumbnails for local preview cards' do - expect { cli.invoke(:remove, [], options) }.to output( - a_string_including('Removed 1 preview cards') - .and(a_string_including('approx. 59.6 KB')) - ).to_stdout + expect { subject } + .to output_results( + 'Removed 1 preview cards', + 'approx. 59.6 KB' + ) end end end diff --git a/spec/lib/mastodon/cli/settings_spec.rb b/spec/lib/mastodon/cli/settings_spec.rb index 7dcd1110b..02d1042c5 100644 --- a/spec/lib/mastodon/cli/settings_spec.rb +++ b/spec/lib/mastodon/cli/settings_spec.rb @@ -7,59 +7,64 @@ describe Mastodon::CLI::Settings do it_behaves_like 'CLI Command' describe 'subcommand "registrations"' do + subject { cli.invoke(action, arguments, options) } + let(:cli) { Mastodon::CLI::Registrations.new } + let(:arguments) { [] } + let(:options) { {} } before do Setting.registrations_mode = nil end describe '#open' do + let(:action) { :open } + it 'changes "registrations_mode" to "open"' do - expect { cli.open }.to change(Setting, :registrations_mode).from(nil).to('open') + expect { subject }.to change(Setting, :registrations_mode).from(nil).to('open') end it 'displays success message' do - expect { cli.open }.to output( - a_string_including('OK') - ).to_stdout + expect { subject } + .to output_results('OK') end end describe '#approved' do + let(:action) { :approved } + it 'changes "registrations_mode" to "approved"' do - expect { cli.approved }.to change(Setting, :registrations_mode).from(nil).to('approved') + expect { subject }.to change(Setting, :registrations_mode).from(nil).to('approved') end it 'displays success message' do - expect { cli.approved }.to output( - a_string_including('OK') - ).to_stdout + expect { subject } + .to output_results('OK') end context 'with --require-reason' do - before do - cli.options = { require_reason: true } - end + let(:options) { { require_reason: true } } it 'changes "registrations_mode" to "approved"' do - expect { cli.approved }.to change(Setting, :registrations_mode).from(nil).to('approved') + expect { subject }.to change(Setting, :registrations_mode).from(nil).to('approved') end it 'sets "require_invite_text" to "true"' do - expect { cli.approved }.to change(Setting, :require_invite_text).from(false).to(true) + expect { subject }.to change(Setting, :require_invite_text).from(false).to(true) end end end describe '#close' do + let(:action) { :close } + it 'changes "registrations_mode" to "none"' do - expect { cli.close }.to change(Setting, :registrations_mode).from(nil).to('none') + expect { subject }.to change(Setting, :registrations_mode).from(nil).to('none') end it 'displays success message' do - expect { cli.close }.to output( - a_string_including('OK') - ).to_stdout + expect { subject } + .to output_results('OK') end end end diff --git a/spec/lib/mastodon/cli/statuses_spec.rb b/spec/lib/mastodon/cli/statuses_spec.rb index 70e4e2c08..63d494bbb 100644 --- a/spec/lib/mastodon/cli/statuses_spec.rb +++ b/spec/lib/mastodon/cli/statuses_spec.rb @@ -4,26 +4,31 @@ require 'rails_helper' require 'mastodon/cli/statuses' describe Mastodon::CLI::Statuses do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' describe '#remove', use_transactional_tests: false do + let(:action) { :remove } + context 'with small batch size' do let(:options) { { batch_size: 0 } } it 'exits with error message' do - expect { cli.invoke :remove, [], options }.to output( - a_string_including('Cannot run') - ).to_stdout.and raise_error(SystemExit) + expect { subject } + .to output_results('Cannot run') + .and raise_error(SystemExit) end end context 'with default batch size' do it 'removes unreferenced statuses' do - expect { cli.invoke :remove }.to output( - a_string_including('Done after') - ).to_stdout + expect { subject } + .to output_results('Done after') end end end diff --git a/spec/lib/mastodon/cli/upgrade_spec.rb b/spec/lib/mastodon/cli/upgrade_spec.rb index 0d6494eee..6861e0488 100644 --- a/spec/lib/mastodon/cli/upgrade_spec.rb +++ b/spec/lib/mastodon/cli/upgrade_spec.rb @@ -4,23 +4,26 @@ require 'rails_helper' require 'mastodon/cli/upgrade' describe Mastodon::CLI::Upgrade do + subject { cli.invoke(action, arguments, options) } + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } it_behaves_like 'CLI Command' describe '#storage_schema' do - context 'with records that dont need upgrading' do - let(:options) { {} } + let(:action) { :storage_schema } + context 'with records that dont need upgrading' do before do Fabricate(:account) Fabricate(:media_attachment) end it 'does not upgrade storage for the attachments' do - expect { cli.invoke(:storage_schema, [], options) }.to output( - a_string_including('Upgraded storage schema of 0 records') - ).to_stdout + expect { subject } + .to output_results('Upgraded storage schema of 0 records') end end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index d30e7201c..4394b470e 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -88,6 +88,7 @@ RSpec.configure do |config| config.include Chewy::Rspec::Helpers config.include Redisable config.include SignedRequestHelpers, type: :request + config.include CommandLineHelpers, type: :cli config.around(:each, use_transactional_tests: false) do |example| self.use_transactional_tests = false diff --git a/spec/support/command_line_helpers.rb b/spec/support/command_line_helpers.rb new file mode 100644 index 000000000..6f9d63d93 --- /dev/null +++ b/spec/support/command_line_helpers.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module CommandLineHelpers + def output_results(*args) + output( + include(*args) + ).to_stdout + end +end From da3d8aff799e9b92ebe76e2dc8f6f953869a1e42 Mon Sep 17 00:00:00 2001 From: Michael Stanclift <mx@vmstan.com> Date: Thu, 7 Dec 2023 08:40:44 -0600 Subject: [PATCH 225/255] Error handling for attachment batch delete process (#28184) Co-authored-by: Claire <claire.github-309c@sitedethib.com> --- app/lib/attachment_batch.rb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/lib/attachment_batch.rb b/app/lib/attachment_batch.rb index 13a9da828..b28f5c3d7 100644 --- a/app/lib/attachment_batch.rb +++ b/app/lib/attachment_batch.rb @@ -4,7 +4,8 @@ class AttachmentBatch # Maximum amount of objects you can delete in an S3 API call. It's # important to remember that this does not correspond to the number # of records in the batch, since records can have multiple attachments - LIMIT = 1_000 + LIMIT = ENV.fetch('S3_BATCH_DELETE_LIMIT', 1000).to_i + MAX_RETRY = ENV.fetch('S3_BATCH_DELETE_RETRY', 3).to_i # Attributes generated and maintained by Paperclip (not all of them # are always used on every class, however) @@ -95,6 +96,7 @@ class AttachmentBatch # objects can be processed at once, so we have to potentially # separate them into multiple calls. + retries = 0 keys.each_slice(LIMIT) do |keys_slice| logger.debug { "Deleting #{keys_slice.size} objects" } @@ -102,6 +104,17 @@ class AttachmentBatch objects: keys_slice.map { |key| { key: key } }, quiet: true, }) + rescue => e + retries += 1 + + if retries < MAX_RETRY + logger.debug "Retry #{retries}/#{MAX_RETRY} after #{e.message}" + sleep 2**retries + retry + else + logger.error "Batch deletion from S3 failed after #{e.message}" + raise e + end end end From 3918dc68c7cf7d6f7d2352f9aa4b68d4d02b7d6a Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 7 Dec 2023 09:49:05 -0500 Subject: [PATCH 226/255] Use composite primary key for `PreviewCardsStatus` model (#28208) --- app/models/preview_cards_status.rb | 4 +--- app/models/status.rb | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/models/preview_cards_status.rb b/app/models/preview_cards_status.rb index 341771e4d..214eec22e 100644 --- a/app/models/preview_cards_status.rb +++ b/app/models/preview_cards_status.rb @@ -9,9 +9,7 @@ # url :string # class PreviewCardsStatus < ApplicationRecord - # Composite primary keys are not properly supported in Rails. However, - # we shouldn't need this anyway... - self.primary_key = nil + self.primary_key = [:preview_card_id, :status_id] belongs_to :preview_card belongs_to :status diff --git a/app/models/status.rb b/app/models/status.rb index eb7159dc6..4bdadae06 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -82,8 +82,7 @@ class Status < ApplicationRecord has_and_belongs_to_many :tags - # Because of a composite primary key, the `dependent` option cannot be used on this association - has_one :preview_cards_status, inverse_of: :status # rubocop:disable Rails/HasManyOrHasOneDependent + has_one :preview_cards_status, inverse_of: :status, dependent: :delete has_one :notification, as: :activity, dependent: :destroy has_one :status_stat, inverse_of: :status, dependent: nil @@ -146,7 +145,6 @@ class Status < ApplicationRecord # The `prepend: true` option below ensures this runs before # the `dependent: destroy` callbacks remove relevant records before_destroy :unlink_from_conversations!, prepend: true - before_destroy :reset_preview_card! cache_associated :application, :media_attachments, From 8d8ae05a186bb8a5fca719dc6ea5a057d1aa197f Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Thu, 7 Dec 2023 10:27:41 -0500 Subject: [PATCH 227/255] Add spec coverage for `CLI::Media#lookup` command (#28266) --- spec/lib/mastodon/cli/media_spec.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/spec/lib/mastodon/cli/media_spec.rb b/spec/lib/mastodon/cli/media_spec.rb index 6bbe7e746..24e1467a3 100644 --- a/spec/lib/mastodon/cli/media_spec.rb +++ b/spec/lib/mastodon/cli/media_spec.rb @@ -89,6 +89,32 @@ describe Mastodon::CLI::Media do end end + describe '#lookup' do + let(:action) { :lookup } + let(:arguments) { [url] } + + context 'with valid url not connected to a record' do + let(:url) { 'https://example.host/assets/1' } + + it 'warns about url and exits' do + expect { subject } + .to output_results('Not a media URL') + .and raise_error(SystemExit) + end + end + + context 'with a valid media url' do + let(:status) { Fabricate(:status) } + let(:media_attachment) { Fabricate(:media_attachment, status: status) } + let(:url) { media_attachment.file.url(:original) } + + it 'displays the url of a connected status' do + expect { subject } + .to output_results(status.id.to_s) + end + end + end + describe '#refresh' do let(:action) { :refresh } From 7e514688b3db1a88636ebb24afcaf1d637366f40 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 8 Dec 2023 04:27:33 -0500 Subject: [PATCH 228/255] Convert `api/v2/search` controller spec to request spec (#28269) --- .../api/v2/search_spec.rb} | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) rename spec/{controllers/api/v2/search_controller_spec.rb => requests/api/v2/search_spec.rb} (79%) diff --git a/spec/controllers/api/v2/search_controller_spec.rb b/spec/requests/api/v2/search_spec.rb similarity index 79% rename from spec/controllers/api/v2/search_controller_spec.rb rename to spec/requests/api/v2/search_spec.rb index a16716a10..d0778cba4 100644 --- a/spec/controllers/api/v2/search_controller_spec.rb +++ b/spec/requests/api/v2/search_spec.rb @@ -2,25 +2,21 @@ require 'rails_helper' -RSpec.describe Api::V2::SearchController do - render_views - +describe 'Search API' do context 'with token' do - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:search') } + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'read:search' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'GET #index' do + describe 'GET /api/v2/search' do let!(:bob) { Fabricate(:account, username: 'bob_test') } let!(:ana) { Fabricate(:account, username: 'ana_test') } let!(:tom) { Fabricate(:account, username: 'tom_test') } let(:params) { { q: 'test' } } it 'returns http success' do - get :index, params: params + get '/api/v2/search', headers: headers, params: params expect(response).to have_http_status(200) end @@ -29,7 +25,7 @@ RSpec.describe Api::V2::SearchController do let(:params) { { q: 'test', type: 'accounts' } } it 'returns all matching accounts' do - get :index, params: params + get '/api/v2/search', headers: headers, params: params expect(body_as_json[:accounts].pluck(:id)).to contain_exactly(bob.id.to_s, ana.id.to_s, tom.id.to_s) end @@ -38,7 +34,7 @@ RSpec.describe Api::V2::SearchController do let(:params) { { q: 'test1', resolve: '1' } } it 'returns http unauthorized' do - get :index, params: params + get '/api/v2/search', headers: headers, params: params expect(response).to have_http_status(200) end @@ -48,7 +44,7 @@ RSpec.describe Api::V2::SearchController do let(:params) { { q: 'test1', offset: 1 } } it 'returns http unauthorized' do - get :index, params: params + get '/api/v2/search', headers: headers, params: params expect(response).to have_http_status(200) end @@ -62,7 +58,7 @@ RSpec.describe Api::V2::SearchController do end it 'returns only the followed accounts' do - get :index, params: params + get '/api/v2/search', headers: headers, params: params expect(body_as_json[:accounts].pluck(:id)).to contain_exactly(ana.id.to_s) end @@ -73,7 +69,7 @@ RSpec.describe Api::V2::SearchController do before { allow(Search).to receive(:new).and_raise(Mastodon::SyntaxError) } it 'returns http unprocessable_entity' do - get :index, params: params + get '/api/v2/search', headers: headers, params: params expect(response).to have_http_status(422) end @@ -83,7 +79,7 @@ RSpec.describe Api::V2::SearchController do before { allow(Search).to receive(:new).and_raise(ActiveRecord::RecordNotFound) } it 'returns http not_found' do - get :index, params: params + get '/api/v2/search', headers: headers, params: params expect(response).to have_http_status(404) end @@ -92,11 +88,11 @@ RSpec.describe Api::V2::SearchController do end context 'without token' do - describe 'GET #index' do + describe 'GET /api/v2/search' do let(:search_params) { nil } before do - get :index, params: search_params + get '/api/v2/search', params: search_params end context 'without a `q` param' do From 8de86eabbff9d5ff42f2340b1906a8595cd898e8 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 8 Dec 2023 04:51:57 -0500 Subject: [PATCH 229/255] Add spec for `CLI::Domains#crawl` command (#28271) --- lib/mastodon/cli/domains.rb | 6 ++-- spec/lib/mastodon/cli/domains_spec.rb | 47 +++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/lib/mastodon/cli/domains.rb b/lib/mastodon/cli/domains.rb index 329f17167..e092497dc 100644 --- a/lib/mastodon/cli/domains.rb +++ b/lib/mastodon/cli/domains.rb @@ -97,6 +97,8 @@ module Mastodon::CLI say("Removed #{custom_emojis_count} custom emojis#{dry_run_mode_suffix}", :green) end + CRAWL_SLEEP_TIME = 20 + option :concurrency, type: :numeric, default: 50, aliases: [:c] option :format, type: :string, default: 'summary', aliases: [:f] option :exclude_suspended, type: :boolean, default: false, aliases: [:x] @@ -168,8 +170,8 @@ module Mastodon::CLI pool.post(domain, &work_unit) end - sleep 20 - sleep 20 until pool.queue_length.zero? + sleep CRAWL_SLEEP_TIME + sleep CRAWL_SLEEP_TIME until pool.queue_length.zero? pool.shutdown pool.wait_for_termination(20) diff --git a/spec/lib/mastodon/cli/domains_spec.rb b/spec/lib/mastodon/cli/domains_spec.rb index a10907f76..24f341c12 100644 --- a/spec/lib/mastodon/cli/domains_spec.rb +++ b/spec/lib/mastodon/cli/domains_spec.rb @@ -28,4 +28,51 @@ describe Mastodon::CLI::Domains do end end end + + describe '#crawl' do + let(:action) { :crawl } + + context 'with accounts from the domain' do + let(:domain) { 'host.example' } + + before do + Fabricate(:account, domain: domain) + stub_request(:get, 'https://host.example/api/v1/instance').to_return(status: 200, body: {}.to_json) + stub_request(:get, 'https://host.example/api/v1/instance/peers').to_return(status: 200, body: {}.to_json) + stub_request(:get, 'https://host.example/api/v1/instance/activity').to_return(status: 200, body: {}.to_json) + stub_const('Mastodon::CLI::Domains::CRAWL_SLEEP_TIME', 0) + end + + context 'with --format of summary' do + let(:options) { { format: 'summary' } } + + it 'crawls the domains and summarizes results' do + expect { subject } + .to output_results('Visited 1 domains, 0 failed') + end + end + + context 'with --format of domains' do + let(:options) { { format: 'domains' } } + + it 'crawls the domains and summarizes results' do + expect { subject } + .to output_results(domain) + end + end + + context 'with --format of json' do + let(:options) { { format: 'json' } } + + it 'crawls the domains and summarizes results' do + expect { subject } + .to output_results(json_summary) + end + + def json_summary + Oj.dump('host.example': { activity: {} }) + end + end + end + end end From f37a1535efc7913c0f8b5d2c8e6588ff496c9984 Mon Sep 17 00:00:00 2001 From: JakePaustian <87162217+JakePaustian@users.noreply.github.com> Date: Fri, 8 Dec 2023 03:52:28 -0600 Subject: [PATCH 230/255] Update CONTRIBUTING.md with additional requirements for API additions (#28274) Co-authored-by: Jake Paustian <jake1500@iastate.edu> --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c1a5fef79..b68a9bde3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,6 +11,10 @@ You can contribute in the following ways: If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon). +## API Changes and Additions + +Please note that any changes or additions made to the API should have an accompanying pull request on [our documentation repository](https://github.com/mastodon/documentation). + ## Bug reports Bug reports and feature suggestions must use descriptive and concise titles and be submitted to [GitHub Issues](https://github.com/mastodon/mastodon/issues). Please use the search function to make sure that you are not submitting duplicates, and that a similar report or request has not already been resolved or rejected. From ca1b7efb069a3cd4532d0d635f70ea47358714c8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 8 Dec 2023 10:52:32 +0100 Subject: [PATCH 231/255] New Crowdin Translations (automated) (#28275) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/fr.json | 2 +- app/javascript/mastodon/locales/hu.json | 4 ++-- app/javascript/mastodon/locales/my.json | 12 ++++++++++++ app/javascript/mastodon/locales/pt-PT.json | 2 +- config/locales/my.yml | 1 + 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 03b656cc4..7db4bf7bc 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -702,7 +702,7 @@ "timeline_hint.resources.followers": "Les abonnés", "timeline_hint.resources.follows": "Les abonnements", "timeline_hint.resources.statuses": "Messages plus anciens", - "trends.counter_by_accounts": "{count, plural, one {{counter} personne} other {{counter} personnes}} au cours {days, plural, one {des dernières 24h} other {des {days} derniers jours}}", + "trends.counter_by_accounts": "{count, plural, one {{counter} pers.} other {{counter} pers.}} sur {days, plural, one {les dernières 24h} other {les {days} derniers jours}}", "trends.trending_now": "Tendance en ce moment", "ui.beforeunload": "Votre brouillon sera perdu si vous quittez Mastodon.", "units.short.billion": "{count}Md", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index d890e4188..386b15811 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -479,7 +479,7 @@ "onboarding.actions.go_to_home": "Ugrás a saját hírfolyamra", "onboarding.compose.template": "Üdvözlet, #Mastodon!", "onboarding.follows.empty": "Sajnos jelenleg nem jeleníthető meg eredmény. Kipróbálhatod a keresést vagy böngészheted a felfedező oldalon a követni kívánt személyeket, vagy próbáld meg később.", - "onboarding.follows.lead": "A saját hírfolyamod az elsődleges tapasztalás a Mastodonon. Minél több embert követsz, annál aktívabb és érdekesebb a dolog. Az induláshoz itt van néhány javaslat:", + "onboarding.follows.lead": "A kezdőlapod a Mastodon használatának elsődleges módja. Minél több embert követsz, annál aktívabbak és érdekesebbek lesznek a dolgok. Az induláshoz itt van néhány javaslat:", "onboarding.follows.title": "Szabd személyre a kezdőlapodat", "onboarding.profile.discoverable": "Saját profil beállítása felfedezhetőként", "onboarding.profile.discoverable_hint": "A Mastodonon a felfedezhetőség választása esetén a saját bejegyzéseid megjelenhetnek a keresési eredmények és a felkapott tartalmak között, valamint a profilod a hozzád hasonló érdeklődési körrel rendelkező embereknél is ajánlásra kerülhet.", @@ -720,7 +720,7 @@ "upload_form.undo": "Törlés", "upload_form.video_description": "Leírás siket, hallássérült, vak vagy gyengénlátó emberek számára", "upload_modal.analyzing_picture": "Kép elemzése…", - "upload_modal.apply": "Alkalmazás", + "upload_modal.apply": "Alkalmaz", "upload_modal.applying": "Alkalmazás…", "upload_modal.choose_image": "Kép kiválasztása", "upload_modal.description_placeholder": "A gyors, barna róka átugrik a lusta kutya fölött", diff --git a/app/javascript/mastodon/locales/my.json b/app/javascript/mastodon/locales/my.json index 4078a4c06..917419d17 100644 --- a/app/javascript/mastodon/locales/my.json +++ b/app/javascript/mastodon/locales/my.json @@ -21,6 +21,7 @@ "account.blocked": "ဘလော့ထားသည်", "account.browse_more_on_origin_server": "မူရင်းပရိုဖိုင်တွင် ပိုမိုကြည့်ရှုပါ။", "account.cancel_follow_request": "စောင့်ကြည့်မှု ပယ်ဖျက်ခြင်း", + "account.copy": "လင့်ခ်ကို ပရိုဖိုင်သို့ ကူးယူပါ", "account.direct": "@{name} သီးသန့် သိရှိနိုင်အောင် မန်းရှင်းခေါ်မည်", "account.disable_notifications": "@{name} ပို့စ်တင်သည့်အခါ ကျွန်ုပ်ထံ အသိပေးခြင်း မပြုလုပ်ရန်။", "account.domain_blocked": "ဒိုမိန်း ပိတ်ပင်ထားခဲ့သည်", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "ဖတ်ပြီးသားအဖြစ်မှတ်ထားပါ", "conversation.open": "Conversation ကိုကြည့်မည်", "conversation.with": "{အမည်များ} ဖြင့်", + "copy_icon_button.copied": "ကလစ်ဘုတ်သို့ ကူးပါ", "copypaste.copied": "ကူယူပြီးပါပြီ", "copypaste.copy_to_clipboard": "ကလစ်ဘုတ်သို့ ကူးပါ", "directory.federated": "သင် သိသော ဖက်ဒီမှ", @@ -389,6 +391,7 @@ "lists.search": "မိမိဖောလိုးထားသူများမှရှာဖွေမည်", "lists.subheading": "သင့်၏စာရင်းများ", "load_pending": "{count, plural, one {# new item} other {# new items}}", + "loading_indicator.label": "လုပ်ဆောင်နေသည်…", "media_gallery.toggle_visible": "{number, plural, one {Hide image} other {Hide images}}", "moved_to_account_banner.text": "{movedToAccount} အကောင့်သို့ပြောင်းလဲထားသဖြင့် {disabledAccount} အကောင့်မှာပိတ်ထားသည်", "mute_modal.duration": "ကြာချိန်", @@ -477,6 +480,13 @@ "onboarding.follows.empty": "ယခုအချိန် မည်သည့်ရလဒ်ကိုမျှ မပြသနိုင်ပါ။ လူများကိုစောင့်ကြည့်ရန်အတွက် Explore စာမျက်နှာကို အသုံးပြု၍ စမ်းကြည့်နိုင်သည် သို့မဟုတ် နောက်မှ ထပ်စမ်းကြည့်ပါ။", "onboarding.follows.lead": "သင့်ကိုယ်ပိုင်ပို့စ်များ တင်နိုင်သည်။ သင်စောင့်ကြည့်သူ များလေလေ၊ စိတ်ဝင်စားစရာကောင်းသောပို့စ်များ တွေ့ရလေဖြစ်သည်။ ဤပရိုဖိုင်များမှာ ကောင်းမွန်သောအစပြုမှုတစ်ခုဖြစ်ပြီး ၎င်းတို့ကိုစောင့်ကြည့်ခြင်းမှလည်း အချိန်မရွေး ပယ်ဖျက်နိုင်ပါသည်။", "onboarding.follows.title": "Mastodon တွင် ရေပန်းစားခြင်း", + "onboarding.profile.discoverable": "ပရိုဖိုင် ရှာဖွေနိုင်ပါမည်", + "onboarding.profile.display_name": "ဖော်ပြမည့်အမည်", + "onboarding.profile.display_name_hint": "သင့်အမည်အပြည့်အစုံ သို့မဟုတ် သင့်အမည်ပြောင်။", + "onboarding.profile.note": "ကိုယ်ရေးအကျဉ်း", + "onboarding.profile.save_and_continue": "သိမ်းပြီး ဆက်လုပ်ပါ", + "onboarding.profile.title": "ပရိုဖိုင်စနစ် ထည့်သွင်းခြင်း", + "onboarding.profile.upload_avatar": "ပရိုဖိုင်ပုံ အပ်လုဒ်လုပ်ပါ", "onboarding.share.lead": "Mastodon တွင် သင့်အား မည်သို့ရှာတွေ့နိုင်သည်ကို အသိပေးပါ။", "onboarding.share.message": "Mastodon ရှိ ကျွန်ုပ်၏အမည်မှာ {username} ဖြစ်သည်။ ကျွန်ုပ်ကို {url} တွင် စောင့်ကြည့်နိုင်ပါသည်", "onboarding.share.next_steps": "ဖြစ်နိုင်ချေရှိသော နောက်အဆင့်များ -", @@ -520,6 +530,7 @@ "privacy.unlisted.short": "စာရင်းမသွင်းထားပါ", "privacy_policy.last_updated": "နောက်ဆုံး ပြင်ဆင်ခဲ့သည့်ရက်စွဲ {date}", "privacy_policy.title": "ကိုယ်ရေးအချက်အလက်မူဝါဒ", + "recommended": "အကြံပြုသည်", "refresh": "ပြန်လည်စတင်ပါ", "regeneration_indicator.label": "လုပ်ဆောင်နေသည်…", "regeneration_indicator.sublabel": "သင့်ပင်မစာမျက်နှာကို ပြင်ဆင်နေပါသည်။", @@ -590,6 +601,7 @@ "search.quick_action.status_search": "{x} နှင့် ကိုက်ညီသော ပို့စ်များ", "search.search_or_paste": "URL ရိုက်ထည့်ပါ သို့မဟုတ် ရှာဖွေပါ", "search_popout.full_text_search_disabled_message": "{domain} တွင် မရနိုင်ပါ။", + "search_popout.full_text_search_logged_out_message": "အကောင့်ဝင်ထားမှသာ ရနိုင်သည်။", "search_popout.language_code": "ISO ဘာသာစကားကုဒ်", "search_popout.options": "ရွေးချယ်ထားသည်များ ရှာဖွေရန်", "search_popout.quick_actions": "အမြန်လုပ်ဆောင်မှုများ", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index 2d1616960..d5055b0dc 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -7,7 +7,7 @@ "about.domain_blocks.silenced.explanation": "Normalmente não verá perfis e conteúdo deste servidor, a menos que os procure explicitamente ou opte por os seguir.", "about.domain_blocks.silenced.title": "Limitados", "about.domain_blocks.suspended.explanation": "Nenhum dado deste servidor será processado, armazenado ou trocado, impossibilitando qualquer interação ou comunicação com os utilizadores dessas instâncias.", - "about.domain_blocks.suspended.title": "Supensos", + "about.domain_blocks.suspended.title": "Suspensos", "about.not_available": "Esta informação não foi disponibilizada neste servidor.", "about.powered_by": "Rede social descentralizada baseada no {mastodon}", "about.rules": "Regras do servidor", diff --git a/config/locales/my.yml b/config/locales/my.yml index 03ed771a4..4ba4fcfad 100644 --- a/config/locales/my.yml +++ b/config/locales/my.yml @@ -1324,6 +1324,7 @@ my: '86400': ၁ ရက် expires_in_prompt: ဘယ်တော့မှ generate: ဖိတ်ကြားချက်လင့်ခ် ဖန်တီးပါ + invalid: ဤဖိတ်ကြားချက်မှာ မမှန်ကန်ပါ invited_by: သင့်ကို ဖိတ်ခေါ်ထားသည် - max_uses: other: "%{count} အသုံးပြုမှုများ" From a3cbb4b2f1aff565582c280c6408d01cf0b54350 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 8 Dec 2023 08:54:20 -0500 Subject: [PATCH 232/255] Add spec for `CLI::Search#deploy` command (#28272) --- spec/lib/mastodon/cli/search_spec.rb | 74 ++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/spec/lib/mastodon/cli/search_spec.rb b/spec/lib/mastodon/cli/search_spec.rb index 785dc2bd6..cb0c80c11 100644 --- a/spec/lib/mastodon/cli/search_spec.rb +++ b/spec/lib/mastodon/cli/search_spec.rb @@ -4,5 +4,79 @@ require 'rails_helper' require 'mastodon/cli/search' describe Mastodon::CLI::Search do + subject { cli.invoke(action, arguments, options) } + + let(:cli) { described_class.new } + let(:arguments) { [] } + let(:options) { {} } + it_behaves_like 'CLI Command' + + describe '#deploy' do + let(:action) { :deploy } + + context 'with concurrency out of range' do + let(:options) { { concurrency: -100 } } + + it 'Exits with error message' do + expect { subject } + .to output_results('this concurrency setting') + .and raise_error(SystemExit) + end + end + + context 'with batch size out of range' do + let(:options) { { batch_size: -100_000 } } + + it 'Exits with error message' do + expect { subject } + .to output_results('this batch_size setting') + .and raise_error(SystemExit) + end + end + + context 'without options' do + before { stub_search_indexes } + + let(:indexed_count) { 1 } + let(:deleted_count) { 2 } + + it 'reports about storage size' do + expect { subject } + .to output_results( + "Indexed #{described_class::INDICES.size * indexed_count} records", + "de-indexed #{described_class::INDICES.size * deleted_count}" + ) + end + end + + def stub_search_indexes + described_class::INDICES.each do |index| + allow(index) + .to receive_messages( + specification: instance_double(Chewy::Index::Specification, changed?: true, lock!: nil), + purge: nil + ) + + importer_double = importer_double_for(index) + allow(importer_double).to receive(:on_progress).and_yield([indexed_count, deleted_count]) + allow("Importer::#{index}Importer".constantize) + .to receive(:new) + .and_return(importer_double) + end + end + + def importer_double_for(index) + instance_double( + "Importer::#{index}Importer".constantize, + clean_up!: nil, + estimate!: 100, + import!: nil, + on_failure: nil, + # on_progress: nil, + optimize_for_import!: nil, + optimize_for_search!: nil + ) + end + end end From 490e4969a1a657cefbc9e4a9c11d5bffb5dc7a50 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Fri, 8 Dec 2023 08:54:48 -0500 Subject: [PATCH 233/255] Correct section naming in maintenance cli script (#28279) --- lib/mastodon/cli/maintenance.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/mastodon/cli/maintenance.rb b/lib/mastodon/cli/maintenance.rb index c53d74254..d0eff7da6 100644 --- a/lib/mastodon/cli/maintenance.rb +++ b/lib/mastodon/cli/maintenance.rb @@ -346,7 +346,7 @@ module Mastodon::CLI remove_index_if_exists!(:announcement_reactions, 'index_announcement_reactions_on_account_id_and_announcement_id') - say 'Removing duplicate account identity proofs…' + say 'Removing duplicate announcement reactions…' ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM announcement_reactions GROUP BY account_id, announcement_id, name HAVING count(*) > 1").each do |row| AnnouncementReaction.where(id: row['ids'].split(',')).sort_by(&:id).reverse.drop(1).each(&:destroy) end @@ -431,7 +431,7 @@ module Mastodon::CLI def deduplicate_domain_blocks! remove_index_if_exists!(:domain_blocks, 'index_domain_blocks_on_domain') - say 'Deduplicating domain_allows…' + say 'Deduplicating domain_blocks…' ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM domain_blocks GROUP BY domain HAVING count(*) > 1").each do |row| domain_blocks = DomainBlock.where(id: row['ids'].split(',')).by_severity.reverse.to_a @@ -462,7 +462,7 @@ module Mastodon::CLI UnavailableDomain.where(id: row['ids'].split(',')).sort_by(&:id).reverse.drop(1).each(&:destroy) end - say 'Restoring domain_allows indexes…' + say 'Restoring unavailable_domains indexes…' ActiveRecord::Base.connection.add_index :unavailable_domains, ['domain'], name: 'index_unavailable_domains_on_domain', unique: true end From afc8550b63434232bb06b196132f2a180516061b Mon Sep 17 00:00:00 2001 From: Michael Stanclift <mx@vmstan.com> Date: Mon, 11 Dec 2023 01:49:10 -0600 Subject: [PATCH 234/255] Change preview card deletes to be done using batch method (#28183) --- app/lib/vacuum/preview_cards_vacuum.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/lib/vacuum/preview_cards_vacuum.rb b/app/lib/vacuum/preview_cards_vacuum.rb index 14fdeda1c..9e34c87c3 100644 --- a/app/lib/vacuum/preview_cards_vacuum.rb +++ b/app/lib/vacuum/preview_cards_vacuum.rb @@ -14,9 +14,8 @@ class Vacuum::PreviewCardsVacuum private def vacuum_cached_images! - preview_cards_past_retention_period.find_each do |preview_card| - preview_card.image.destroy - preview_card.save + preview_cards_past_retention_period.find_in_batches do |preview_card| + AttachmentBatch.new(PreviewCard, preview_card).clear end end From bd88883b6e6c7c614eac3c97fc40783ea7b8c91b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 07:52:53 +0000 Subject: [PATCH 235/255] Update eslint (non-major) (#28313) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 128 +++++++++++++++++++++++++++--------------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/yarn.lock b/yarn.lock index 45f58eaad..4e1d0bd8c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1726,9 +1726,9 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.1.3": - version: 2.1.3 - resolution: "@eslint/eslintrc@npm:2.1.3" +"@eslint/eslintrc@npm:^2.1.4": + version: 2.1.4 + resolution: "@eslint/eslintrc@npm:2.1.4" dependencies: ajv: "npm:^6.12.4" debug: "npm:^4.3.2" @@ -1739,14 +1739,14 @@ __metadata: js-yaml: "npm:^4.1.0" minimatch: "npm:^3.1.2" strip-json-comments: "npm:^3.1.1" - checksum: f4103f4346126292eb15581c5a1d12bef03410fd3719dedbdb92e1f7031d46a5a2d60de8566790445d5d4b70b75ba050876799a11f5fff8265a91ee3fa77dab0 + checksum: 32f67052b81768ae876c84569ffd562491ec5a5091b0c1e1ca1e0f3c24fb42f804952fdd0a137873bc64303ba368a71ba079a6f691cee25beee9722d94cc8573 languageName: node linkType: hard -"@eslint/js@npm:8.54.0": - version: 8.54.0 - resolution: "@eslint/js@npm:8.54.0" - checksum: d61fb4a0be6af2d8cb290121c329697664a75d6255a29926d5454fb02aeb02b87112f67fdf218d10abac42f90c570ac366126751baefc5405d0e017ed0c946c5 +"@eslint/js@npm:8.55.0": + version: 8.55.0 + resolution: "@eslint/js@npm:8.55.0" + checksum: 88ab9fc57a651becd2b32ec40a3958db27fae133b1ae77bebd733aa5bbd00a92f325bb02f20ad680d31c731fa49b22f060a4777dd52eb3e27da013d940bd978d languageName: node linkType: hard @@ -3682,14 +3682,14 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^6.0.0": - version: 6.11.0 - resolution: "@typescript-eslint/eslint-plugin@npm:6.11.0" + version: 6.13.2 + resolution: "@typescript-eslint/eslint-plugin@npm:6.13.2" dependencies: "@eslint-community/regexpp": "npm:^4.5.1" - "@typescript-eslint/scope-manager": "npm:6.11.0" - "@typescript-eslint/type-utils": "npm:6.11.0" - "@typescript-eslint/utils": "npm:6.11.0" - "@typescript-eslint/visitor-keys": "npm:6.11.0" + "@typescript-eslint/scope-manager": "npm:6.13.2" + "@typescript-eslint/type-utils": "npm:6.13.2" + "@typescript-eslint/utils": "npm:6.13.2" + "@typescript-eslint/visitor-keys": "npm:6.13.2" debug: "npm:^4.3.4" graphemer: "npm:^1.4.0" ignore: "npm:^5.2.4" @@ -3702,44 +3702,44 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 6645aa09b9d51c5e3ea781eaf74da75b94f83f3e2d7b3dd988d5ce7eb82dd87e3509471cf2ee8c6b2428d907df5f1b02f29dbd04f54c2653f9566c8c4ce98009 + checksum: 531a4406d872738d165c6a66cb26e976523c94053b022a8210dc9fd10e91b79b705bc0fcc77145e9744e4108b53bdba55e02a10dc17757b22be92aff57849384 languageName: node linkType: hard "@typescript-eslint/parser@npm:^6.0.0": - version: 6.11.0 - resolution: "@typescript-eslint/parser@npm:6.11.0" + version: 6.13.2 + resolution: "@typescript-eslint/parser@npm:6.13.2" dependencies: - "@typescript-eslint/scope-manager": "npm:6.11.0" - "@typescript-eslint/types": "npm:6.11.0" - "@typescript-eslint/typescript-estree": "npm:6.11.0" - "@typescript-eslint/visitor-keys": "npm:6.11.0" + "@typescript-eslint/scope-manager": "npm:6.13.2" + "@typescript-eslint/types": "npm:6.13.2" + "@typescript-eslint/typescript-estree": "npm:6.13.2" + "@typescript-eslint/visitor-keys": "npm:6.13.2" debug: "npm:^4.3.4" peerDependencies: eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: e7caeb20069102e21f468fc0dbe7ff6fb6b1efa9e72f4c9f39d4a865ed0633f39130b593ef9ae8f394ca1d70563e15410faf30a482a97809951eaac6ed3a67da + checksum: 2c62b8cd8a37eb2ea59cd00e559f51a9f57af746e2040e872af3c58ddd3f4071ad7b7009789bdeb0e0d4ee0343bfe96ee77288020f3ae22d08e1674203f5e156 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/scope-manager@npm:6.11.0" +"@typescript-eslint/scope-manager@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/scope-manager@npm:6.13.2" dependencies: - "@typescript-eslint/types": "npm:6.11.0" - "@typescript-eslint/visitor-keys": "npm:6.11.0" - checksum: d8999e2d1a4cbde8a79df5e3ec416f0e3db9532d39f2f4bb5a0ebdf954ae75c183d3277579ba05268fe2c88e88ef87f0fa12f02bb8d95d9e67d92e411241f3a3 + "@typescript-eslint/types": "npm:6.13.2" + "@typescript-eslint/visitor-keys": "npm:6.13.2" + checksum: 9b159e5bb10dfb5953e71488200b4126378fc7e987ce7d90946aea9ec40cd66c7ada92399657c5d9794189b764ca6f4eb38a8dcb9e4c5aa50ab6000a39636b9c languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/type-utils@npm:6.11.0" +"@typescript-eslint/type-utils@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/type-utils@npm:6.13.2" dependencies: - "@typescript-eslint/typescript-estree": "npm:6.11.0" - "@typescript-eslint/utils": "npm:6.11.0" + "@typescript-eslint/typescript-estree": "npm:6.13.2" + "@typescript-eslint/utils": "npm:6.13.2" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.0.1" peerDependencies: @@ -3747,23 +3747,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: ff68f2e052b8d688f1dc1a0050746704c8e0ab6263b47f1f52da73a7d251678e4950af23a95e1cd8e3fcea2457e6e5294ddbe01d29dafa2fdfb5b11ed9452a3f + checksum: 1ca97c78abdf479aea0c54e869fda2ae2f69de1974cc063062ce7b5b16c7fdf497ea15c50a29dd5941ea1b6b77e8f1213a5c272a747e334ac69ede083f327468 languageName: node linkType: hard -"@typescript-eslint/types@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/types@npm:6.11.0" - checksum: 23182813db39a5e9b9bcc1e85306c953f7b8b22d3885e41fcac0bd725c170fbcb70f4ce55633678cc5921dcf062fa0e55635eb39480c118a4411a00354820223 +"@typescript-eslint/types@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/types@npm:6.13.2" + checksum: 029918ca5b1442bb4bc435773504ce32191e2c3e2fde8d4176bb6513f03e3dfa2aa9724b2d22b1640656d666b97f7a7ebfeaf67b881d5e07250828fa83e3ebe8 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/typescript-estree@npm:6.11.0" +"@typescript-eslint/typescript-estree@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/typescript-estree@npm:6.13.2" dependencies: - "@typescript-eslint/types": "npm:6.11.0" - "@typescript-eslint/visitor-keys": "npm:6.11.0" + "@typescript-eslint/types": "npm:6.13.2" + "@typescript-eslint/visitor-keys": "npm:6.13.2" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -3772,34 +3772,34 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 3e183e554e1bc74f065da3015f7137eb40c262f989c547701b1e3f4f20134e574e56b749288cd00d77b9d1ddb705546613c2457661ffc63b6060ffa97ba3aac8 + checksum: 1c4c59dce0c51fdfee34d9f418e64fe28e3ec1a97661efc8a3d2780bdff36aff38de9090d356a968f394fa6d4e9c058936ce9cd260d4c44a52761ecd74915bce languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.11.0, @typescript-eslint/utils@npm:^6.5.0": - version: 6.11.0 - resolution: "@typescript-eslint/utils@npm:6.11.0" +"@typescript-eslint/utils@npm:6.13.2, @typescript-eslint/utils@npm:^6.5.0": + version: 6.13.2 + resolution: "@typescript-eslint/utils@npm:6.13.2" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" "@types/json-schema": "npm:^7.0.12" "@types/semver": "npm:^7.5.0" - "@typescript-eslint/scope-manager": "npm:6.11.0" - "@typescript-eslint/types": "npm:6.11.0" - "@typescript-eslint/typescript-estree": "npm:6.11.0" + "@typescript-eslint/scope-manager": "npm:6.13.2" + "@typescript-eslint/types": "npm:6.13.2" + "@typescript-eslint/typescript-estree": "npm:6.13.2" semver: "npm:^7.5.4" peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: c91eb4578607959acc2b43ddc791571682e45601a19b25d5d120786ed4af607656f83c5c1fa71972e549ddfb5542acf2f7d443ae93b32ee28192c22c106b8883 + checksum: 84969be91e7949868eaaa289288c9d71927f0e427b572501b0991d8d62b40a4234f7287c35b35d276ccbb53e9ea5457b8250fcf4941e60e6b9ba4065fbfba416 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.11.0": - version: 6.11.0 - resolution: "@typescript-eslint/visitor-keys@npm:6.11.0" +"@typescript-eslint/visitor-keys@npm:6.13.2": + version: 6.13.2 + resolution: "@typescript-eslint/visitor-keys@npm:6.13.2" dependencies: - "@typescript-eslint/types": "npm:6.11.0" + "@typescript-eslint/types": "npm:6.13.2" eslint-visitor-keys: "npm:^3.4.1" - checksum: 5f48329422b7f286196661d39e93e9defd7c5cf80e6c84c8d03459853f5d9f86a5e91c5e80ea572dcdb907ebbe503bbcc77aeb8b468c294b2aa7b3ccfc81cb88 + checksum: c173bc1fcc42c3075a5ee094e7f3bf0279d98315c25ff49e20d02d79022b1d0402accfa113b070afb4d52a6f6d180594b67baa8b6a784eabdf82b54dd1ff454c languageName: node linkType: hard @@ -7313,13 +7313,13 @@ __metadata: linkType: hard "eslint-config-prettier@npm:^9.0.0": - version: 9.0.0 - resolution: "eslint-config-prettier@npm:9.0.0" + version: 9.1.0 + resolution: "eslint-config-prettier@npm:9.1.0" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: bc1f661915845c631824178942e5d02f858fe6d0ea796f0050d63e0f681927b92696e81139dd04714c08c3e7de580fd079c66162e40070155ba79eaee78ab5d0 + checksum: 6d332694b36bc9ac6fdb18d3ca2f6ac42afa2ad61f0493e89226950a7091e38981b66bac2b47ba39d15b73fff2cd32c78b850a9cf9eed9ca9a96bfb2f3a2f10d languageName: node linkType: hard @@ -7555,13 +7555,13 @@ __metadata: linkType: hard "eslint@npm:^8.41.0": - version: 8.54.0 - resolution: "eslint@npm:8.54.0" + version: 8.55.0 + resolution: "eslint@npm:8.55.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.6.1" - "@eslint/eslintrc": "npm:^2.1.3" - "@eslint/js": "npm:8.54.0" + "@eslint/eslintrc": "npm:^2.1.4" + "@eslint/js": "npm:8.55.0" "@humanwhocodes/config-array": "npm:^0.11.13" "@humanwhocodes/module-importer": "npm:^1.0.1" "@nodelib/fs.walk": "npm:^1.2.8" @@ -7598,7 +7598,7 @@ __metadata: text-table: "npm:^0.2.0" bin: eslint: bin/eslint.js - checksum: 4f205f832bdbd0218cde374b067791f4f76d7abe8de86b2dc849c273899051126d912ebf71531ee49b8eeaa22cad77febdc8f2876698dc2a76e84a8cb976af22 + checksum: d28c0b60f19bb7d355cb8393e77b018c8f548dba3f820b799c89bb2e0c436ee26084e700c5e57e1e97e7972ec93065277849141b82e7b0c0d02c2dc1e553a2a1 languageName: node linkType: hard From d0e7999a904d6d5eb290f2378ce36809bfecb502 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 07:53:13 +0000 Subject: [PATCH 236/255] Update dependency typescript to v5.3.3 (#28312) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4e1d0bd8c..34e22f052 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16495,22 +16495,22 @@ __metadata: linkType: hard "typescript@npm:5, typescript@npm:^5.0.4": - version: 5.3.2 - resolution: "typescript@npm:5.3.2" + version: 5.3.3 + resolution: "typescript@npm:5.3.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: d7dbe1fbe19039e36a65468ea64b5d338c976550394ba576b7af9c68ed40c0bc5d12ecce390e4b94b287a09a71bd3229f19c2d5680611f35b7c53a3898791159 + checksum: e33cef99d82573624fc0f854a2980322714986bc35b9cb4d1ce736ed182aeab78e2cb32b385efa493b2a976ef52c53e20d6c6918312353a91850e2b76f1ea44f languageName: node linkType: hard "typescript@patch:typescript@npm%3A5#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin<compat/typescript>": - version: 5.3.2 - resolution: "typescript@patch:typescript@npm%3A5.3.2#optional!builtin<compat/typescript>::version=5.3.2&hash=e012d7" + version: 5.3.3 + resolution: "typescript@patch:typescript@npm%3A5.3.3#optional!builtin<compat/typescript>::version=5.3.3&hash=e012d7" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 73c8bad74e732d93211c9d77f28b03307e2f5fc6a0afc73f4b783261ab567686a16d6ae958bdaef383a00be1b0b8c8b6741dd6ca3d13af4963fa7e47456d49c7 + checksum: 1d0a5f4ce496c42caa9a30e659c467c5686eae15d54b027ee7866744952547f1be1262f2d40de911618c242b510029d51d43ff605dba8fb740ec85ca2d3f9500 languageName: node linkType: hard From 7ddd937330103cc9030ee375c3e62904b0b7508f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 08:53:32 +0100 Subject: [PATCH 237/255] Update dependency prettier to v3.1.1 (#28311) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 34e22f052..7a1524204 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13312,11 +13312,11 @@ __metadata: linkType: hard "prettier@npm:^3.0.0": - version: 3.1.0 - resolution: "prettier@npm:3.1.0" + version: 3.1.1 + resolution: "prettier@npm:3.1.1" bin: prettier: bin/prettier.cjs - checksum: a45ea70aa97fde162ea4c4aba3dfc7859aa6a732a1db34458d9535dc3c2c16d3bc3fb5689e6cd76aa835562555303b02d9449fd2e15af3b73c8053557e25c5b6 + checksum: facc944ba20e194ff4db765e830ffbcb642803381f0d2033ed397e79904fa4ccc877dc25ad68f42d36985c01d051c990ca1b905fb83d2d7d65fe69e4386fa1a3 languageName: node linkType: hard From a117155728319e36f3a5d2256de83b0985a40e0c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 07:54:01 +0000 Subject: [PATCH 238/255] Update DefinitelyTyped types (non-major) (#28310) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7a1524204..f246cf412 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3027,11 +3027,11 @@ __metadata: linkType: hard "@types/emoji-mart@npm:^3.0.9": - version: 3.0.13 - resolution: "@types/emoji-mart@npm:3.0.13" + version: 3.0.14 + resolution: "@types/emoji-mart@npm:3.0.14" dependencies: "@types/react": "npm:*" - checksum: 840f920c3242e1d274f0102e67cb2d00434e1fd370e0bcc8983b43b6b62322b01e3ddcd5fb078c60883e613530a7c70b8c40060624897543cd4da9441ca81486 + checksum: 23ded65fce9b3355fbe903d3971cb67cc827a5d587464bb7e3f349615527ef4a9197b3bb59fa84c4391d1b901e7f200f686a7fc83f649ae2a51a0fb948cbadfb languageName: node linkType: hard @@ -3175,12 +3175,12 @@ __metadata: linkType: hard "@types/jest@npm:^29.5.2": - version: 29.5.10 - resolution: "@types/jest@npm:29.5.10" + version: 29.5.11 + resolution: "@types/jest@npm:29.5.11" dependencies: expect: "npm:^29.0.0" pretty-format: "npm:^29.0.0" - checksum: b46171d59d12a5f69bbe710f65eaf59a8073337c6b4a67dff8158575caec53f1c61f8a7d645b34d6ac3c4ea398acd30f0c5d1c4a131c0c918798019264a3397d + checksum: 524a3394845214581278bf4d75055927261fbeac7e1a89cd621bd0636da37d265fe0a85eac58b5778758faad1cbd7c7c361dfc190c78ebde03a91cce33463261 languageName: node linkType: hard @@ -3374,11 +3374,11 @@ __metadata: linkType: hard "@types/react-helmet@npm:^6.1.6": - version: 6.1.9 - resolution: "@types/react-helmet@npm:6.1.9" + version: 6.1.11 + resolution: "@types/react-helmet@npm:6.1.11" dependencies: "@types/react": "npm:*" - checksum: d1823582903d6e70f1f447c7bec9e844b6f85f5de84cbcde5c8bbeecc064db1394c786ed9b9ded30544afe5c91e57c7e8105171df1643998f64c0aeab9f7f2aa + checksum: f7b3bb2151d992a108ae46fed876fb9c8119108397d9a01d150c5642782997542c8b3c52e742b56e8689b7dbfa62ca9cfc76aa7e05dec4e60c652f7ef53fa783 languageName: node linkType: hard @@ -3495,13 +3495,13 @@ __metadata: linkType: hard "@types/react@npm:*, @types/react@npm:16 || 17 || 18, @types/react@npm:>=16.9.11, @types/react@npm:^18.2.7": - version: 18.2.41 - resolution: "@types/react@npm:18.2.41" + version: 18.2.43 + resolution: "@types/react@npm:18.2.43" dependencies: "@types/prop-types": "npm:*" "@types/scheduler": "npm:*" csstype: "npm:^3.0.2" - checksum: 5cc72491ce8be95e7bbedd8bf039ca971772ecd22d989feb045af7e73247c7e6cff25a2f1c2200be461fb2f6b5aacef739e1ba9fd83c744209dfd3ce8aa75afe + checksum: 10477a50fbd3c0cc5b8a2ade679f442717f68fb27c8460b2aa1d3256cd18c48f742bbe5b9ee37a8c4c5f832ffa37b3a23c09fd96dd880a8e3182d8929c05e803 languageName: node linkType: hard From b82fc8a2ca29f03f821add41bea5221ceac9cafd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 07:54:22 +0000 Subject: [PATCH 239/255] Update dependency ws to v8.15.0 (#28308) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index f246cf412..0ef881126 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17738,8 +17738,8 @@ __metadata: linkType: hard "ws@npm:^8.11.0, ws@npm:^8.12.1, ws@npm:^8.14.2": - version: 8.14.2 - resolution: "ws@npm:8.14.2" + version: 8.15.0 + resolution: "ws@npm:8.15.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -17748,7 +17748,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 35b4c2da048b8015c797fd14bcb5a5766216ce65c8a5965616a5440ca7b6c3681ee3cbd0ea0c184a59975556e9d58f2002abf8485a14d11d3371770811050a16 + checksum: b778a405b2589ffbf549323e2f404f1f72e372a049d332d2f0b1f33057e9fbb14a05aa474cb156e4584b418cd95edf4297c0ca5263d6519e8009064bf8e0b80d languageName: node linkType: hard From 11d2bd97165bf68439a8d2293c48b1fcefc8930c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 02:55:07 -0500 Subject: [PATCH 240/255] Fix intermittent failure from unspecified order in `api/v1/accounts/relationships` spec (#28306) --- .../api/v1/accounts/relationships_spec.rb | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/spec/requests/api/v1/accounts/relationships_spec.rb b/spec/requests/api/v1/accounts/relationships_spec.rb index cea45168a..b06ce0509 100644 --- a/spec/requests/api/v1/accounts/relationships_spec.rb +++ b/spec/requests/api/v1/accounts/relationships_spec.rb @@ -31,8 +31,8 @@ describe 'GET /api/v1/accounts/relationships' do .to have_http_status(200) expect(body_as_json) .to be_an(Enumerable) - .and have_attributes( - first: include( + .and contain_exactly( + include( following: true, followed_by: false ) @@ -53,9 +53,11 @@ describe 'GET /api/v1/accounts/relationships' do expect(body_as_json) .to be_an(Enumerable) .and have_attributes( - size: 2, - first: include(simon_item), - second: include(lewis_item) + size: 2 + ) + .and contain_exactly( + include(simon_item), + include(lewis_item) ) end end @@ -71,10 +73,12 @@ describe 'GET /api/v1/accounts/relationships' do expect(body_as_json) .to be_an(Enumerable) .and have_attributes( - size: 3, - first: include(simon_item), - second: include(lewis_item), - third: include(bob_item) + size: 3 + ) + .and contain_exactly( + include(simon_item), + include(lewis_item), + include(bob_item) ) end end @@ -88,9 +92,11 @@ describe 'GET /api/v1/accounts/relationships' do expect(body_as_json) .to be_an(Enumerable) .and have_attributes( - size: 2, - first: include(simon_item), - second: include(lewis_item) + size: 2 + ) + .and contain_exactly( + include(simon_item), + include(lewis_item) ) end end @@ -116,7 +122,6 @@ describe 'GET /api/v1/accounts/relationships' do muting: false, requested: false, domain_blocking: false, - } end @@ -129,7 +134,6 @@ describe 'GET /api/v1/accounts/relationships' do muting: false, requested: false, domain_blocking: false, - } end end @@ -149,8 +153,10 @@ describe 'GET /api/v1/accounts/relationships' do expect(body_as_json) .to be_an(Enumerable) .and have_attributes( - size: 1, - first: include( + size: 1 + ) + .and contain_exactly( + include( following: true, showing_reblogs: true ) @@ -168,8 +174,8 @@ describe 'GET /api/v1/accounts/relationships' do expect(body_as_json) .to be_an(Enumerable) - .and have_attributes( - first: include( + .and contain_exactly( + include( following: false, showing_reblogs: false ) From 78347d25567b1b8cf2cb9e1fd4cab002fd6aff59 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 02:55:45 -0500 Subject: [PATCH 241/255] Controller spec to request spec: `api/v1/accounts/familiar_followers` (#28305) --- .../v1/accounts/familiar_followers_spec.rb} | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) rename spec/{controllers/api/v1/accounts/familiar_followers_controller_spec.rb => requests/api/v1/accounts/familiar_followers_spec.rb} (53%) diff --git a/spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb b/spec/requests/api/v1/accounts/familiar_followers_spec.rb similarity index 53% rename from spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb rename to spec/requests/api/v1/accounts/familiar_followers_spec.rb index 3c7c7e8b8..fdc0a3a93 100644 --- a/spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb +++ b/spec/requests/api/v1/accounts/familiar_followers_spec.rb @@ -2,20 +2,16 @@ require 'rails_helper' -describe Api::V1::Accounts::FamiliarFollowersController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:follows') } +describe 'Accounts Familiar Followers API' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'read:follows' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } let(:account) { Fabricate(:account) } - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'GET #index' do + describe 'GET /api/v1/accounts/familiar_followers' do it 'returns http success' do - get :index, params: { account_id: account.id, limit: 2 } + get '/api/v1/accounts/familiar_followers', params: { account_id: account.id, limit: 2 }, headers: headers expect(response).to have_http_status(200) end @@ -26,7 +22,7 @@ describe Api::V1::Accounts::FamiliarFollowersController do it 'removes duplicate account IDs from params' do account_ids = [account_a, account_b, account_b, account_a, account_a].map { |a| a.id.to_s } - get :index, params: { id: account_ids } + get '/api/v1/accounts/familiar_followers', params: { id: account_ids }, headers: headers expect(body_as_json.pluck(:id)).to contain_exactly(account_a.id.to_s, account_b.id.to_s) end From 8f94502e7d092584c7bd723ae3e866c0aae2c95b Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 02:56:13 -0500 Subject: [PATCH 242/255] Controller spec to request spec: `api/v1/accounts/identify_proofs` (#28304) --- .../identity_proofs_controller_spec.rb | 23 ------------------- .../api/v1/accounts/identity_proofs_spec.rb | 19 +++++++++++++++ 2 files changed, 19 insertions(+), 23 deletions(-) delete mode 100644 spec/controllers/api/v1/accounts/identity_proofs_controller_spec.rb create mode 100644 spec/requests/api/v1/accounts/identity_proofs_spec.rb diff --git a/spec/controllers/api/v1/accounts/identity_proofs_controller_spec.rb b/spec/controllers/api/v1/accounts/identity_proofs_controller_spec.rb deleted file mode 100644 index 6351de761..000000000 --- a/spec/controllers/api/v1/accounts/identity_proofs_controller_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::Accounts::IdentityProofsController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } - let(:account) { Fabricate(:account) } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'GET #index' do - it 'returns http success' do - get :index, params: { account_id: account.id, limit: 2 } - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v1/accounts/identity_proofs_spec.rb b/spec/requests/api/v1/accounts/identity_proofs_spec.rb new file mode 100644 index 000000000..3727af7e8 --- /dev/null +++ b/spec/requests/api/v1/accounts/identity_proofs_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Accounts Identity Proofs API' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'read:accounts' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + let(:account) { Fabricate(:account) } + + describe 'GET /api/v1/accounts/identity_proofs' do + it 'returns http success' do + get "/api/v1/accounts/#{account.id}/identity_proofs", params: { limit: 2 }, headers: headers + + expect(response).to have_http_status(200) + end + end +end From a968898dc7d7a9c6ddea850a40d4f2fc9e7b446f Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 02:56:47 -0500 Subject: [PATCH 243/255] Controller spec to request spec: `api/v1/accounts/lists` (#28303) --- .../api/v1/accounts/lists_controller_spec.rb | 25 ------------------- spec/requests/api/v1/accounts/lists_spec.rb | 25 +++++++++++++++++++ 2 files changed, 25 insertions(+), 25 deletions(-) delete mode 100644 spec/controllers/api/v1/accounts/lists_controller_spec.rb create mode 100644 spec/requests/api/v1/accounts/lists_spec.rb diff --git a/spec/controllers/api/v1/accounts/lists_controller_spec.rb b/spec/controllers/api/v1/accounts/lists_controller_spec.rb deleted file mode 100644 index 418839cfa..000000000 --- a/spec/controllers/api/v1/accounts/lists_controller_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::Accounts::ListsController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:lists') } - let(:account) { Fabricate(:account) } - let(:list) { Fabricate(:list, account: user.account) } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - user.account.follow!(account) - list.accounts << account - end - - describe 'GET #index' do - it 'returns http success' do - get :index, params: { account_id: account.id } - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v1/accounts/lists_spec.rb b/spec/requests/api/v1/accounts/lists_spec.rb new file mode 100644 index 000000000..48c0337e5 --- /dev/null +++ b/spec/requests/api/v1/accounts/lists_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Accounts Lists API' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'read:lists' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + let(:account) { Fabricate(:account) } + let(:list) { Fabricate(:list, account: user.account) } + + before do + user.account.follow!(account) + list.accounts << account + end + + describe 'GET /api/v1/accounts/lists' do + it 'returns http success' do + get "/api/v1/accounts/#{account.id}/lists", headers: headers + + expect(response).to have_http_status(200) + end + end +end From e544b6df42a5ed8c2365f0a95d7e3e94c53c61f9 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 02:57:33 -0500 Subject: [PATCH 244/255] Controller spec to request spec: `api/v1/accounts/lookup` (#28302) --- .../api/v1/accounts/lookup_controller_spec.rb | 23 ------------------- spec/requests/api/v1/accounts/lookup_spec.rb | 19 +++++++++++++++ 2 files changed, 19 insertions(+), 23 deletions(-) delete mode 100644 spec/controllers/api/v1/accounts/lookup_controller_spec.rb create mode 100644 spec/requests/api/v1/accounts/lookup_spec.rb diff --git a/spec/controllers/api/v1/accounts/lookup_controller_spec.rb b/spec/controllers/api/v1/accounts/lookup_controller_spec.rb deleted file mode 100644 index 37407766f..000000000 --- a/spec/controllers/api/v1/accounts/lookup_controller_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::Accounts::LookupController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } - let(:account) { Fabricate(:account) } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'GET #show' do - it 'returns http success' do - get :show, params: { account_id: account.id, acct: account.acct } - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v1/accounts/lookup_spec.rb b/spec/requests/api/v1/accounts/lookup_spec.rb new file mode 100644 index 000000000..4c022c7c1 --- /dev/null +++ b/spec/requests/api/v1/accounts/lookup_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Accounts Lookup API' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'read:accounts' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + let(:account) { Fabricate(:account) } + + describe 'GET /api/v1/accounts/lookup' do + it 'returns http success' do + get '/api/v1/accounts/lookup', params: { account_id: account.id, acct: account.acct }, headers: headers + + expect(response).to have_http_status(200) + end + end +end From 94cc707ab398339dfe74472300056876fac81856 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 02:58:48 -0500 Subject: [PATCH 245/255] Controller spec to request spec: `api/v1/accounts/notes` (#28301) --- .../api/v1/accounts/notes_spec.rb} | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) rename spec/{controllers/api/v1/accounts/notes_controller_spec.rb => requests/api/v1/accounts/notes_spec.rb} (66%) diff --git a/spec/controllers/api/v1/accounts/notes_controller_spec.rb b/spec/requests/api/v1/accounts/notes_spec.rb similarity index 66% rename from spec/controllers/api/v1/accounts/notes_controller_spec.rb rename to spec/requests/api/v1/accounts/notes_spec.rb index 75599b32b..4f3ac68c7 100644 --- a/spec/controllers/api/v1/accounts/notes_controller_spec.rb +++ b/spec/requests/api/v1/accounts/notes_spec.rb @@ -2,21 +2,17 @@ require 'rails_helper' -describe Api::V1::Accounts::NotesController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:accounts') } +describe 'Accounts Notes API' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'write:accounts' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } let(:account) { Fabricate(:account) } let(:comment) { 'foo' } - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'POST #create' do + describe 'POST /api/v1/accounts/:account_id/note' do subject do - post :create, params: { account_id: account.id, comment: comment } + post "/api/v1/accounts/#{account.id}/note", params: { comment: comment }, headers: headers end context 'when account note has reasonable length', :aggregate_failures do From 809506bdd40871ae8c56fa755d8d61bc279095a0 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 02:59:40 -0500 Subject: [PATCH 246/255] Controller spec to request spec: `api/v1/accounts/pins` (#28300) --- .../api/v1/accounts/pins_controller_spec.rb | 40 ------------------ spec/requests/api/v1/accounts/pins_spec.rb | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 40 deletions(-) delete mode 100644 spec/controllers/api/v1/accounts/pins_controller_spec.rb create mode 100644 spec/requests/api/v1/accounts/pins_spec.rb diff --git a/spec/controllers/api/v1/accounts/pins_controller_spec.rb b/spec/controllers/api/v1/accounts/pins_controller_spec.rb deleted file mode 100644 index 36f525e75..000000000 --- a/spec/controllers/api/v1/accounts/pins_controller_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Api::V1::Accounts::PinsController do - let(:john) { Fabricate(:user) } - let(:kevin) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: john.id, scopes: 'write:accounts') } - - before do - kevin.account.followers << john.account - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'POST #create' do - subject { post :create, params: { account_id: kevin.account.id } } - - it 'creates account_pin', :aggregate_failures do - expect do - subject - end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(1) - expect(response).to have_http_status(200) - end - end - - describe 'DELETE #destroy' do - subject { delete :destroy, params: { account_id: kevin.account.id } } - - before do - Fabricate(:account_pin, account: john.account, target_account: kevin.account) - end - - it 'destroys account_pin', :aggregate_failures do - expect do - subject - end.to change { AccountPin.where(account: john.account, target_account: kevin.account).count }.by(-1) - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v1/accounts/pins_spec.rb b/spec/requests/api/v1/accounts/pins_spec.rb new file mode 100644 index 000000000..c293715f7 --- /dev/null +++ b/spec/requests/api/v1/accounts/pins_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Accounts Pins API' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'write:accounts' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + let(:kevin) { Fabricate(:user) } + + before do + kevin.account.followers << user.account + end + + describe 'POST /api/v1/accounts/:account_id/pin' do + subject { post "/api/v1/accounts/#{kevin.account.id}/pin", headers: headers } + + it 'creates account_pin', :aggregate_failures do + expect do + subject + end.to change { AccountPin.where(account: user.account, target_account: kevin.account).count }.by(1) + expect(response).to have_http_status(200) + end + end + + describe 'POST /api/v1/accounts/:account_id/unpin' do + subject { post "/api/v1/accounts/#{kevin.account.id}/unpin", headers: headers } + + before do + Fabricate(:account_pin, account: user.account, target_account: kevin.account) + end + + it 'destroys account_pin', :aggregate_failures do + expect do + subject + end.to change { AccountPin.where(account: user.account, target_account: kevin.account).count }.by(-1) + expect(response).to have_http_status(200) + end + end +end From 16ede59d0a01759a32e3abb6a352a3c397bd982c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 03:00:41 -0500 Subject: [PATCH 247/255] Controller spec to request spec: `api/v1/featured_tags/suggestions` (#28298) --- .../suggestions_controller_spec.rb | 23 ------------------- .../api/v1/featured_tags/suggestions_spec.rb | 19 +++++++++++++++ 2 files changed, 19 insertions(+), 23 deletions(-) delete mode 100644 spec/controllers/api/v1/featured_tags/suggestions_controller_spec.rb create mode 100644 spec/requests/api/v1/featured_tags/suggestions_spec.rb diff --git a/spec/controllers/api/v1/featured_tags/suggestions_controller_spec.rb b/spec/controllers/api/v1/featured_tags/suggestions_controller_spec.rb deleted file mode 100644 index 54c63dcc6..000000000 --- a/spec/controllers/api/v1/featured_tags/suggestions_controller_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V1::FeaturedTags::SuggestionsController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } - let(:account) { Fabricate(:account) } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'GET #index' do - it 'returns http success' do - get :index, params: { account_id: account.id, limit: 2 } - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v1/featured_tags/suggestions_spec.rb b/spec/requests/api/v1/featured_tags/suggestions_spec.rb new file mode 100644 index 000000000..f7b453b74 --- /dev/null +++ b/spec/requests/api/v1/featured_tags/suggestions_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Featured Tags Suggestions API' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'read:accounts' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + let(:account) { Fabricate(:account) } + + describe 'GET /api/v1/featured_tags/suggestions' do + it 'returns http success' do + get '/api/v1/featured_tags/suggestions', params: { account_id: account.id, limit: 2 }, headers: headers + + expect(response).to have_http_status(200) + end + end +end From f5d6143aa1eba03391841d6df8ed80e09a4b5e05 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 09:01:17 +0100 Subject: [PATCH 248/255] Update dependency addressable to v2.8.6 (#28296) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 7a7fdb01c..738bc7b8b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -118,7 +118,7 @@ GEM minitest (>= 5.1) mutex_m tzinfo (~> 2.0) - addressable (2.8.5) + addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) aes_key_wrap (1.1.0) android_key_attestation (0.3.0) From 253393f3a8281dcf5850aabd917da727518f49c4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 03:04:45 -0500 Subject: [PATCH 249/255] Only attempt to remove indexes that exist in `CLI::Maintenance` script (#28286) --- lib/mastodon/cli/maintenance.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mastodon/cli/maintenance.rb b/lib/mastodon/cli/maintenance.rb index d0eff7da6..553ca056d 100644 --- a/lib/mastodon/cli/maintenance.rb +++ b/lib/mastodon/cli/maintenance.rb @@ -712,7 +712,7 @@ module Mastodon::CLI end def remove_index_if_exists!(table, name) - ActiveRecord::Base.connection.remove_index(table, name: name) + ActiveRecord::Base.connection.remove_index(table, name: name) if ActiveRecord::Base.connection.index_name_exists?(table, name) rescue ArgumentError, ActiveRecord::StatementInvalid nil end From 0c640925009a8dbfb8a2be9e4b45d3e40f727a52 Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 03:13:28 -0500 Subject: [PATCH 250/255] Controller spec to request spec: `api/v1/accounts/search` (#28299) --- .../api/v1/accounts/search_controller_spec.rb | 22 ------------------- spec/requests/api/v1/accounts/search_spec.rb | 18 +++++++++++++++ 2 files changed, 18 insertions(+), 22 deletions(-) delete mode 100644 spec/controllers/api/v1/accounts/search_controller_spec.rb create mode 100644 spec/requests/api/v1/accounts/search_spec.rb diff --git a/spec/controllers/api/v1/accounts/search_controller_spec.rb b/spec/controllers/api/v1/accounts/search_controller_spec.rb deleted file mode 100644 index aa9455a4a..000000000 --- a/spec/controllers/api/v1/accounts/search_controller_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Api::V1::Accounts::SearchController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'GET #show' do - it 'returns http success' do - get :show, params: { q: 'query' } - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v1/accounts/search_spec.rb b/spec/requests/api/v1/accounts/search_spec.rb new file mode 100644 index 000000000..76b32e7b2 --- /dev/null +++ b/spec/requests/api/v1/accounts/search_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Accounts Search API' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'read:accounts' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + describe 'GET /api/v1/accounts/search' do + it 'returns http success' do + get '/api/v1/accounts/search', params: { q: 'query' }, headers: headers + + expect(response).to have_http_status(200) + end + end +end From 0e4233de9d8a0912b0d837e32043c325dfc2e0ff Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 03:13:57 -0500 Subject: [PATCH 251/255] Controller spec to request spec: `api/v2/suggestions` (#28297) --- .../api/v2/suggestions_controller_spec.rb | 22 ------------------- spec/requests/api/v2/suggestions_spec.rb | 18 +++++++++++++++ 2 files changed, 18 insertions(+), 22 deletions(-) delete mode 100644 spec/controllers/api/v2/suggestions_controller_spec.rb create mode 100644 spec/requests/api/v2/suggestions_spec.rb diff --git a/spec/controllers/api/v2/suggestions_controller_spec.rb b/spec/controllers/api/v2/suggestions_controller_spec.rb deleted file mode 100644 index 5e6508bfd..000000000 --- a/spec/controllers/api/v2/suggestions_controller_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Api::V2::SuggestionsController do - render_views - - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } - - before do - allow(controller).to receive(:doorkeeper_token) { token } - end - - describe 'GET #index' do - it 'returns http success' do - get :index - - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/v2/suggestions_spec.rb b/spec/requests/api/v2/suggestions_spec.rb new file mode 100644 index 000000000..5f1c97b8a --- /dev/null +++ b/spec/requests/api/v2/suggestions_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Suggestions API' do + let(:user) { Fabricate(:user) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } + let(:scopes) { 'read' } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + describe 'GET /api/v2/suggestions' do + it 'returns http success' do + get '/api/v2/suggestions', headers: headers + + expect(response).to have_http_status(200) + end + end +end From 79a81da69c86276fe17143954f06f6e6b58356d4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 09:22:52 +0100 Subject: [PATCH 252/255] New Crowdin Translations (automated) (#28291) Co-authored-by: GitHub Actions <noreply@github.com> --- app/javascript/mastodon/locales/en-GB.json | 7 +++ app/javascript/mastodon/locales/eo.json | 50 ++++++++++++++++++++ app/javascript/mastodon/locales/ko.json | 2 +- app/javascript/mastodon/locales/la.json | 16 +++---- app/javascript/mastodon/locales/ne.json | 54 +++++++++++++++++++++- app/javascript/mastodon/locales/sk.json | 1 + config/locales/activerecord.hr.yml | 15 ++++++ config/locales/activerecord.ru.yml | 2 +- config/locales/en-GB.yml | 16 +++++++ config/locales/sk.yml | 4 ++ 10 files changed, 156 insertions(+), 11 deletions(-) diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index 7745311be..1a67fecb6 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -21,6 +21,7 @@ "account.blocked": "Blocked", "account.browse_more_on_origin_server": "Browse more on the original profile", "account.cancel_follow_request": "Cancel follow", + "account.copy": "Copy link to profile", "account.direct": "Privately mention @{name}", "account.disable_notifications": "Stop notifying me when @{name} posts", "account.domain_blocked": "Domain blocked", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Mark as read", "conversation.open": "View conversation", "conversation.with": "With {names}", + "copy_icon_button.copied": "Copied to clipboard", "copypaste.copied": "Copied", "copypaste.copy_to_clipboard": "Copy to clipboard", "directory.federated": "From known fediverse", @@ -222,6 +224,7 @@ "emoji_button.search_results": "Search results", "emoji_button.symbols": "Symbols", "emoji_button.travel": "Travel & Places", + "empty_column.account_hides_collections": "This user has chosen to not make this information available", "empty_column.account_suspended": "Account suspended", "empty_column.account_timeline": "No posts here!", "empty_column.account_unavailable": "Profile unavailable", @@ -478,6 +481,8 @@ "onboarding.follows.empty": "Unfortunately, no results can be shown right now. You can try using search or browsing the explore page to find people to follow, or try again later.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Personalize your home feed", + "onboarding.profile.discoverable": "Make my profile discoverable", + "onboarding.profile.discoverable_hint": "When you opt in to discoverability on Mastodon, your posts may appear in search results and trending, and your profile may be suggested to people with similar interests to you.", "onboarding.profile.display_name": "Display name", "onboarding.profile.display_name_hint": "Your full name or your fun name…", "onboarding.profile.lead": "You can always complete this later in the settings, where even more customisation options are available.", @@ -530,6 +535,7 @@ "privacy.unlisted.short": "Unlisted", "privacy_policy.last_updated": "Last updated {date}", "privacy_policy.title": "Privacy Policy", + "recommended": "Recommended", "refresh": "Refresh", "regeneration_indicator.label": "Loading…", "regeneration_indicator.sublabel": "Your home feed is being prepared!", @@ -600,6 +606,7 @@ "search.quick_action.status_search": "Posts matching {x}", "search.search_or_paste": "Search or paste URL", "search_popout.full_text_search_disabled_message": "Unavailable on {domain}.", + "search_popout.full_text_search_logged_out_message": "Only available when logged in.", "search_popout.language_code": "ISO language code", "search_popout.options": "Search options", "search_popout.quick_actions": "Quick actions", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 537b8d0af..2678d83a5 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -21,6 +21,7 @@ "account.blocked": "Blokita", "account.browse_more_on_origin_server": "Foliumi pli ĉe la originala profilo", "account.cancel_follow_request": "Nuligi peton por sekvado", + "account.copy": "Kopii ligilon al profilo", "account.direct": "Private mencii @{name}", "account.disable_notifications": "Ne plu sciigi min, kiam @{name} mesaĝas", "account.domain_blocked": "Domajno blokita", @@ -191,6 +192,7 @@ "conversation.mark_as_read": "Marki legita", "conversation.open": "Vidi konversacion", "conversation.with": "Kun {names}", + "copy_icon_button.copied": "Kopiis al kliptabulo", "copypaste.copied": "Kopiita", "copypaste.copy_to_clipboard": "Kopii al dosierujo", "directory.federated": "El konata fediverso", @@ -202,7 +204,9 @@ "dismissable_banner.community_timeline": "Jen la plej novaj publikaj afiŝoj de uzantoj, kies kontojn gastigas {domain}.", "dismissable_banner.dismiss": "Eksigi", "dismissable_banner.explore_links": "Tiuj novaĵoj estas aktuale priparolataj de uzantoj en tiu ĉi kaj aliaj serviloj, sur la malcentrigita reto.", + "dismissable_banner.explore_statuses": "Ĉi tioj estas afiŝoj de socia reto kiu populariĝas hodiau.", "dismissable_banner.explore_tags": "Ĉi tiuj kradvostoj populariĝas en ĉi tiu kaj aliaj serviloj en la malcentraliza reto nun.", + "dismissable_banner.public_timeline": "Ĉi tioj estas plej lastaj publikaj afiŝoj de personoj ĉe socia reto kiu personoj ĉe {domain} sekvas.", "embed.instructions": "Enkorpigu ĉi tiun afiŝon en vian retejon per kopio de la suba kodo.", "embed.preview": "Ĝi aperos tiel:", "emoji_button.activity": "Agadoj", @@ -220,6 +224,7 @@ "emoji_button.search_results": "Serĉaj rezultoj", "emoji_button.symbols": "Simboloj", "emoji_button.travel": "Vojaĝoj kaj lokoj", + "empty_column.account_hides_collections": "Ĉi tiu uzanto elektis ne disponebligi ĉi tiu informon", "empty_column.account_suspended": "Konto suspendita", "empty_column.account_timeline": "Neniu afiŝo ĉi tie!", "empty_column.account_unavailable": "Profilo ne disponebla", @@ -229,6 +234,8 @@ "empty_column.direct": "Vi ankoraŭ ne havas privatan mencion. Kiam vi sendos aŭ ricevos iun, tiu aperos ĉi tie.", "empty_column.domain_blocks": "Ankoraŭ neniu domajno estas blokita.", "empty_column.explore_statuses": "Nenio tendencas nun. Rekontrolu poste!", + "empty_column.favourited_statuses": "Vi ankoraŭ ne havas stelumitan afiŝon.", + "empty_column.favourites": "Ankoraŭ neniu stelumis tiun afiŝon.", "empty_column.follow_requests": "Vi ne ankoraŭ havas iun peton de sekvado. Kiam vi ricevos unu, ĝi aperos ĉi tie.", "empty_column.followed_tags": "Vi ankoraŭ ne sekvas iujn kradvortojn. Kiam vi faras, ili aperos ĉi tie.", "empty_column.hashtag": "Ankoraŭ estas nenio per ĉi tiu kradvorto.", @@ -292,19 +299,36 @@ "hashtag.column_settings.tag_mode.any": "Iu ajn", "hashtag.column_settings.tag_mode.none": "Neniu", "hashtag.column_settings.tag_toggle": "Aldoni pliajn etikedojn por ĉi tiu kolumno", + "hashtag.counter_by_accounts": "{count, plural,one {{counter} partoprenanto} other {{counter} partoprenantoj}}", + "hashtag.counter_by_uses": "{count, plural,one {{counter} afiŝo} other {{counter} afiŝoj}}", + "hashtag.counter_by_uses_today": "{count, plural,one {{counter} afiŝo} other {{counter} afiŝoj}} hodiau", "hashtag.follow": "Sekvi la kradvorton", "hashtag.unfollow": "Ne plu sekvi la kradvorton", + "hashtags.and_other": "…kaj {count, plural,other {# pli}}", + "home.actions.go_to_explore": "Vidi kio populariĝas", "home.actions.go_to_suggestions": "Trovi homojn por sekvi", "home.column_settings.basic": "Bazaj agordoj", "home.column_settings.show_reblogs": "Montri diskonigojn", "home.column_settings.show_replies": "Montri respondojn", + "home.explore_prompt.body": "Via hejmafiŝaro havos miksitajn afiŝojn de kradvortoj kiujn vi elektis sekvi, personoj kiujn vi elektis sekvi, kaj afiŝoj kiujn ili suprenigis.", + "home.explore_prompt.title": "Ĉi tio estas via hejma paĝo en Mastodon.", "home.hide_announcements": "Kaŝi la anoncojn", + "home.pending_critical_update.body": "Ĝisdatigu vian servilon de Mastodon kiel eble plej baldau!", + "home.pending_critical_update.link": "Vidi ĝisdatigojn", + "home.pending_critical_update.title": "Kritika sekurĝisdatigo estas disponebla!", "home.show_announcements": "Montri anoncojn", + "interaction_modal.description.favourite": "Per konto ĉe Mastodon, vi povas stelumiti ĉi tiun afiŝon por sciigi la afiŝanton ke vi aprezigas ŝin kaj konservas por la estonteco.", "interaction_modal.description.follow": "Kun konto ĉe Mastodon, vi povos sekvi {name} por vidi ties mesaĝojn en via hejmo.", "interaction_modal.description.reblog": "Kun konto ĉe Mastodon, vi povas diskonigi ĉi tiun afiŝon, por ke viaj propraj sekvantoj vidu ĝin.", "interaction_modal.description.reply": "Kun konto ĉe Mastodon, vi povos respondi al ĉi tiu mesaĝo.", + "interaction_modal.login.action": "Prenu min hejmen", + "interaction_modal.login.prompt": "Domajno de via hejma servilo, ekz. mastodon.social", + "interaction_modal.no_account_yet": "Ĉu ne estas ĉe Mastodon?", "interaction_modal.on_another_server": "En alia servilo", "interaction_modal.on_this_server": "En ĉi tiu servilo", + "interaction_modal.sign_in": "Vi ne estas ensalutita al ĉi tiu servilo.", + "interaction_modal.sign_in_hint": "Gvideto: Tio estas la retejo kie vi registris. Vi ankau povas tajpi vian plenan uzantonomon!", + "interaction_modal.title.favourite": "Stelumi la afiŝon de {name}", "interaction_modal.title.follow": "Sekvi {name}", "interaction_modal.title.reblog": "Akceli la afiŝon de {name}", "interaction_modal.title.reply": "Respondi al la afiŝo de {name}", @@ -320,6 +344,8 @@ "keyboard_shortcuts.direct": "por malfermi la kolumnon pri privataj mencioj", "keyboard_shortcuts.down": "iri suben en la listo", "keyboard_shortcuts.enter": "malfermi mesaĝon", + "keyboard_shortcuts.favourite": "Stelumi afiŝon", + "keyboard_shortcuts.favourites": "Malfermi la liston de la stelumoj", "keyboard_shortcuts.federated": "Malfermi la frataran templinion", "keyboard_shortcuts.heading": "Klavaraj mallongigoj", "keyboard_shortcuts.home": "Malfermi la hejman templinion", @@ -366,6 +392,7 @@ "lists.search": "Serĉi inter la homoj, kiujn vi sekvas", "lists.subheading": "Viaj listoj", "load_pending": "{count,plural, one {# nova elemento} other {# novaj elementoj}}", + "loading_indicator.label": "Ŝargado…", "media_gallery.toggle_visible": "{number, plural, one {Kaŝi la bildon} other {Kaŝi la bildojn}}", "moved_to_account_banner.text": "Via konto {disabledAccount} estas malvalidigita ĉar vi movis ĝin al {movedToAccount}.", "mute_modal.duration": "Daŭro", @@ -382,6 +409,7 @@ "navigation_bar.domain_blocks": "Blokitaj domajnoj", "navigation_bar.edit_profile": "Redakti profilon", "navigation_bar.explore": "Esplori", + "navigation_bar.favourites": "Stelumoj", "navigation_bar.filters": "Silentigitaj vortoj", "navigation_bar.follow_requests": "Petoj de sekvado", "navigation_bar.followed_tags": "Sekvataj kradvortoj", @@ -389,6 +417,7 @@ "navigation_bar.lists": "Listoj", "navigation_bar.logout": "Adiaŭi", "navigation_bar.mutes": "Silentigitaj uzantoj", + "navigation_bar.opened_in_classic_interface": "Afiŝoj, kontoj, kaj aliaj specifaj paĝoj kiuj estas malfermititaj defaulta en la klasika reta interfaco.", "navigation_bar.personal": "Persone", "navigation_bar.pins": "Alpinglitaj mesaĝoj", "navigation_bar.preferences": "Preferoj", @@ -398,6 +427,7 @@ "not_signed_in_indicator.not_signed_in": "Necesas saluti por aliri tiun rimedon.", "notification.admin.report": "{name} raportis {target}", "notification.admin.sign_up": "{name} kreis konton", + "notification.favourite": "{name} stelumis vian afiŝon", "notification.follow": "{name} eksekvis vin", "notification.follow_request": "{name} petis sekvi vin", "notification.mention": "{name} menciis vin", @@ -411,6 +441,7 @@ "notifications.column_settings.admin.report": "Novaj raportoj:", "notifications.column_settings.admin.sign_up": "Novaj registriĝoj:", "notifications.column_settings.alert": "Sciigoj de la retumilo", + "notifications.column_settings.favourite": "Stelumoj:", "notifications.column_settings.filter_bar.advanced": "Montri ĉiujn kategoriojn", "notifications.column_settings.filter_bar.category": "Rapida filtra breto", "notifications.column_settings.filter_bar.show_bar": "Montri la breton de filtrilo", @@ -428,6 +459,7 @@ "notifications.column_settings.update": "Redaktoj:", "notifications.filter.all": "Ĉiuj", "notifications.filter.boosts": "Diskonigoj", + "notifications.filter.favourites": "Stelumoj", "notifications.filter.follows": "Sekvoj", "notifications.filter.mentions": "Mencioj", "notifications.filter.polls": "Balotenketaj rezultoj", @@ -441,14 +473,29 @@ "notifications_permission_banner.enable": "Ŝalti retumilajn sciigojn", "notifications_permission_banner.how_to_control": "Por ricevi sciigojn kiam Mastodon ne estas malfermita, ebligu labortablajn sciigojn. Vi povas regi precize kiuj specoj de interagoj generas labortablajn sciigojn per la supra butono {icon} post kiam ili estas ebligitaj.", "notifications_permission_banner.title": "Neniam preterlasas iun ajn", + "onboarding.action.back": "Prenu min reen", + "onboarding.actions.back": "Prenu min reen", "onboarding.actions.go_to_explore": "See what's trending", "onboarding.actions.go_to_home": "Go to your home feed", "onboarding.compose.template": "Saluton #Mastodon!", "onboarding.follows.empty": "Bedaŭrinde, neniu rezulto estas montrebla nuntempe. Vi povas provi serĉi aŭ foliumi la esploran paĝon por trovi kontojn por sekvi, aŭ retrovi baldaŭ.", "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Popular on Mastodon", + "onboarding.profile.discoverable": "Trovebligi mian profilon", + "onboarding.profile.discoverable_hint": "Kiam vi aliĝi al trovebleco ĉe Mastodon, viaj afiŝoj eble aperos en serĉaj rezultoj kaj populariĝoj, kaj via profilo eble estas sugestota al personoj kun similaj intereseoj al vi.", + "onboarding.profile.display_name": "Publika nomo", + "onboarding.profile.display_name_hint": "Via plena nomo aŭ via kromnomo…", + "onboarding.profile.lead": "Vi ĉiam povas plenigi ĉi tion poste en la agordoj, kie eĉ pli da personecigagordoj estas disponeblaj.", + "onboarding.profile.note": "Sinprezento", + "onboarding.profile.note_hint": "Vi povas @mencii aliajn homojn aŭ #kradvortojn…", "onboarding.profile.save_and_continue": "Konservi kaj daŭrigi", + "onboarding.profile.title": "Profila fikso", + "onboarding.profile.upload_avatar": "Alŝuti profilbildon", + "onboarding.profile.upload_header": "Alŝuti profilkapbildon", + "onboarding.share.lead": "Sciigi personojn pri kiel ili povas trovi vin ĉe Mastodon!", "onboarding.share.message": "Mi estas {username} en #Mastodon! Sekvu min ĉe {url}", + "onboarding.share.next_steps": "Eblaj malantauaj paŝoj:", + "onboarding.share.title": "Disvastigi vian profilon", "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", "onboarding.start.skip": "Want to skip right ahead?", "onboarding.start.title": "Vi atingas ĝin!", @@ -460,6 +507,9 @@ "onboarding.steps.setup_profile.title": "Customize your profile", "onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!", "onboarding.steps.share_profile.title": "Share your profile", + "onboarding.tips.2fa": "<strong>Ĉu vi scias?</strong> Vi povas sekurigi vian konton per efektivigi dufaktora autentigo en via kontoagordoj.", + "onboarding.tips.accounts_from_other_servers": "<strong>Ĉu vi scias?</strong> Ĉar Mastodon estas sencentra, kelkaj profiloj kiujn vi trovi estas gastigitaj ĉe aliaj serviloj kiuj ne estas via.", + "onboarding.tips.migration": "<strong>Ĉu vi scias?</strong> Se vi sentas ke {domain} ne estas bona servilelekto por vi en la estonteco, vi povas translokiĝi al alia servilo de Mastodon sen malgajni viajn sekvantojn.", "password_confirmation.mismatching": "Pasvorto konfirmo ne kongruas", "picture_in_picture.restore": "Remetu ĝin", "poll.closed": "Finita", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index 5b76cd67c..4606916c1 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -239,7 +239,7 @@ "empty_column.follow_requests": "아직 팔로우 요청이 없습니다. 요청을 받았을 때 여기에 나타납니다.", "empty_column.followed_tags": "아직 아무 해시태그도 팔로우하고 있지 않습니다. 해시태그를 팔로우하면, 여기에 표시됩니다.", "empty_column.hashtag": "이 해시태그는 아직 사용되지 않았습니다.", - "empty_column.home": "당신의 홈 타임라인은 비어있습니다! 더 많은 사람들을 팔로우 하여 채워보세요. {suggestions}", + "empty_column.home": "당신의 홈 타임라인은 비어있습니다! 더 많은 사람을 팔로우하여 채워보세요. {suggestions}", "empty_column.list": "리스트에 아직 아무것도 없습니다. 리스트의 누군가가 게시물을 올리면 여기에 나타납니다.", "empty_column.lists": "아직 리스트가 없습니다. 리스트를 만들면 여기에 나타납니다.", "empty_column.mutes": "아직 아무도 뮤트하지 않았습니다.", diff --git a/app/javascript/mastodon/locales/la.json b/app/javascript/mastodon/locales/la.json index e4bd9365a..3e5747ba8 100644 --- a/app/javascript/mastodon/locales/la.json +++ b/app/javascript/mastodon/locales/la.json @@ -1,6 +1,6 @@ { "about.contact": "Ratio:", - "about.domain_blocks.no_reason_available": "ratio abdere est", + "about.domain_blocks.no_reason_available": "Ratio abdere est", "account.account_note_header": "Annotatio", "account.badges.bot": "Robotum", "account.badges.group": "Congregatio", @@ -49,7 +49,7 @@ "dismissable_banner.explore_links": "These news stories are being talked about by people on this and other servers of the decentralized network right now.", "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", "embed.instructions": "Embed this status on your website by copying the code below.", - "emoji_button.food": "cibus et potus", + "emoji_button.food": "Cibus et potus", "emoji_button.people": "Homines", "emoji_button.search": "Quaerere...", "empty_column.account_timeline": "Hic nulla contributa!", @@ -57,13 +57,13 @@ "empty_column.home": "Your home timeline is empty! Follow more people to fill it up. {suggestions}", "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", "explore.trending_statuses": "Contributa", - "generic.saved": "servavit", + "generic.saved": "Servavit", "hashtag.column_settings.tag_toggle": "Include additional tags in this column", - "keyboard_shortcuts.back": "to navigate back", - "keyboard_shortcuts.blocked": "to open blocked users list", - "keyboard_shortcuts.boost": "to boost", - "keyboard_shortcuts.column": "to focus a status in one of the columns", - "keyboard_shortcuts.compose": "to focus the compose textarea", + "keyboard_shortcuts.back": "Re navigare", + "keyboard_shortcuts.blocked": "Aperire listam usorum obstructorum", + "keyboard_shortcuts.boost": "Inlustrare publicatio", + "keyboard_shortcuts.column": "Columnam dirigere", + "keyboard_shortcuts.compose": "TextArea Compositi Attendere", "keyboard_shortcuts.description": "Descriptio", "keyboard_shortcuts.direct": "to open direct messages column", "keyboard_shortcuts.down": "to move down in the list", diff --git a/app/javascript/mastodon/locales/ne.json b/app/javascript/mastodon/locales/ne.json index 0967ef424..95f8e703c 100644 --- a/app/javascript/mastodon/locales/ne.json +++ b/app/javascript/mastodon/locales/ne.json @@ -1 +1,53 @@ -{} +{ + "about.contact": "सम्पर्क:", + "about.disclaimer": "Mastodon नि:शुल्क, खुला स्रोत सफ्टवेयर, र Mastodon gGmbH को ट्रेडमार्क हो।", + "about.domain_blocks.no_reason_available": "कारण उपलब्ध छैन", + "about.domain_blocks.preamble": "Mastodon ले तपाइँलाई सामान्यतया फेडिभर्समा कुनै पनि अन्य सर्भरका सामग्री हेर्न र प्रयोगकर्ताहरूसँग अन्तरक्रिया गर्न दिन्छ। यी अपवादहरू हुन् जुन यस विशेष सर्भरमा बनाइएका छन्।", + "about.domain_blocks.silenced.title": "सीमित", + "about.domain_blocks.suspended.explanation": "यस सर्भरबाट कुनै पनि डेटा प्रशोधन, भण्डारण वा आदानप्रदान गरिने छैन, जसले यस सर्भरका प्रयोगकर्ताहरूसँग कुनै पनि अन्तरक्रिया वा सञ्चारलाई असम्भव बनाउँछ।", + "about.domain_blocks.suspended.title": "निलम्बित", + "about.not_available": "यो जानकारी यस सर्भरमा उपलब्ध गराइएको छैन।", + "about.powered_by": "{mastodon} द्वारा संचालित विकेन्द्रीकृत सामाजिक मिडिया", + "about.rules": "सर्भर नियमहरू", + "account.add_or_remove_from_list": "सूचीबाट थप्नुहोस् वा हटाउनुहोस्", + "account.badges.group": "समूह", + "account.block": "@{name} लाई ब्लक गर्नुहोस्", + "account.block_domain": "{domain} डोमेनलाई ब्लक गर्नुहोस्", + "account.block_short": "ब्लक", + "account.blocked": "ब्लक गरिएको", + "account.browse_more_on_origin_server": "मूल प्रोफाइलमा थप ब्राउज गर्नुहोस्", + "account.cancel_follow_request": "फलो अनुरोध रद्द गर्नुहोस", + "account.copy": "प्रोफाइलको लिङ्क प्रतिलिपि गर्नुहोस्", + "account.direct": "@{name} लाई निजी रूपमा उल्लेख गर्नुहोस्", + "account.disable_notifications": "@{name} ले पोस्ट गर्दा मलाई सूचित नगर्नुहोस्", + "account.domain_blocked": "डोमेन ब्लक गरिएको छ", + "account.edit_profile": "प्रोफाइल सम्पादन गर्नुहोस्", + "account.enable_notifications": "@{name} ले पोस्ट गर्दा मलाई सूचित गर्नुहोस्", + "account.endorse": "प्रोफाइलमा फिचर गर्नुहोस्", + "account.featured_tags.last_status_never": "कुनै पोस्ट छैन", + "account.follow": "फलो गर्नुहोस", + "account.followers.empty": "यस प्रयोगकर्तालाई अहिलेसम्म कसैले फलो गर्दैन।", + "account.follows.empty": "यो प्रयोगकर्ताले अहिलेसम्म कसैलाई फलो गरेको छैन।", + "account.go_to_profile": "प्रोफाइलमा जानुहोस्", + "account.hide_reblogs": "@{name} को बूस्टहरू लुकाउनुहोस्", + "account.link_verified_on": "यस लिङ्कको स्वामित्व {date} मा जाँच गरिएको थियो", + "account.media": "मिडिया", + "account.mention": "@{name} लाई उल्लेख गर्नुहोस्", + "account.no_bio": "कुनै विवरण प्रदान गरिएको छैन।", + "account.posts": "पोस्टहरू", + "account.requested": "स्वीकृतिको पर्खाइमा। फलो अनुरोध रद्द गर्न क्लिक गर्नुहोस्", + "account.requested_follow": "{name} ले तपाईंलाई फलो गर्न अनुरोध गर्नुभएको छ", + "account.share": "@{name} को प्रोफाइल सेयर गर्नुहोस्", + "account.show_reblogs": "@{name} को बूस्टहरू देखाउनुहोस्", + "account.statuses_counter": "{count, plural, one {{counter} पोस्ट} other {{counter} पोस्टहरू}}", + "account.unblock": "@{name} लाई अनब्लक गर्नुहोस्", + "account.unblock_domain": "{domain} डोमेनलाई अनब्लक गर्नुहोस्", + "account.unblock_short": "अनब्लक गर्नुहोस्", + "account.unendorse": "प्रोफाइलमा फिचर नगर्नुहोस्", + "account.unfollow": "अनफलो गर्नुहोस्", + "account_note.placeholder": "नोट लेख्न क्लिक गर्नुहोस्", + "admin.dashboard.retention.average": "औसत", + "admin.dashboard.retention.cohort_size": "नयाँ प्रयोगकर्ताहरू", + "alert.rate_limited.message": "कृपया {retry_time, time, medium} पछि पुन: प्रयास गर्नुहोस्।", + "alert.unexpected.message": "एउटा अनपेक्षित त्रुटि भयो।" +} diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index c4ce6f8cf..46fcc0116 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -224,6 +224,7 @@ "emoji_button.search_results": "Výsledky hľadania", "emoji_button.symbols": "Symboly", "emoji_button.travel": "Cestovanie a miesta", + "empty_column.account_hides_collections": "Tento užívateľ si zvolil nesprístupniť túto informáciu", "empty_column.account_suspended": "Účet bol pozastavený", "empty_column.account_timeline": "Nie sú tu žiadne príspevky!", "empty_column.account_unavailable": "Profil nedostupný", diff --git a/config/locales/activerecord.hr.yml b/config/locales/activerecord.hr.yml index b095244dd..a3e7d6d49 100644 --- a/config/locales/activerecord.hr.yml +++ b/config/locales/activerecord.hr.yml @@ -6,7 +6,9 @@ hr: expires_at: Krajnji rok options: Opcije user: + agreement: Ugovor o uslugama email: E-mail adresa + locale: Lokalitet password: Lozinka user/account: username: Korisničko ime @@ -18,3 +20,16 @@ hr: attributes: username: invalid: mora sadržavati samo slova, brojeve i _ + reserved: je rezervisano + admin/webhook: + attributes: + url: + invalid: nije validan URL + doorkeeper/application: + attributes: + website: + invalid: nije validan URL + import: + attributes: + data: + malformed: je neispravan diff --git a/config/locales/activerecord.ru.yml b/config/locales/activerecord.ru.yml index 14f9f61f6..92d85af4d 100644 --- a/config/locales/activerecord.ru.yml +++ b/config/locales/activerecord.ru.yml @@ -36,7 +36,7 @@ ru: status: attributes: reblog: - taken: поста уже существует + taken: пост уже существует user: attributes: email: diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 987788a7a..a6e74c483 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -534,6 +534,7 @@ en-GB: total_reported: Reports about them total_storage: Media attachments totals_time_period_hint_html: The totals displayed below include data for all time. + unknown_instance: There is currently no record of this domain on this server. invites: deactivate_all: Deactivate all filter: @@ -610,6 +611,7 @@ en-GB: created_at: Reported delete_and_resolve: Delete posts forwarded: Forwarded + forwarded_replies_explanation: This report is from a remote user and about remote content. It has been forwarded to you because the reported content is in reply to one of your users. forwarded_to: Forwarded to %{domain} mark_as_resolved: Mark as resolved mark_as_sensitive: Mark as sensitive @@ -1038,6 +1040,14 @@ en-GB: hint_html: Just one more thing! We need to confirm you're a human (this is so we can keep the spam out!). Solve the CAPTCHA below and click "Continue". title: Security check confirmations: + awaiting_review: Your e-mail address is confirmed! The %{domain} staff is now reviewing your registration. You will receive an e-mail if they approve your account! + awaiting_review_title: Your registration is being reviewed + clicking_this_link: clicking this link + login_link: log in + proceed_to_login_html: You can now proceed to %{login_link}. + redirect_to_app_html: You should have been redirected to the <strong>%{app_name}</strong> app. If that did not happen, try %{clicking_this_link} or manually return to the app. + registration_complete: Your registration on %{domain} is now complete! + welcome_title: Welcome, %{name}! wrong_email_hint: If that e-mail address is not correct, you can change it in account settings. delete_account: Delete account delete_account_html: If you wish to delete your account, you can <a href="%{path}">proceed here</a>. You will be asked for confirmation. @@ -1099,6 +1109,7 @@ en-GB: functional: Your account is fully operational. pending: Your application is pending review by our staff. This may take some time. You will receive an e-mail if your application is approved. redirecting_to: Your account is inactive because it is currently redirecting to %{acct}. + self_destruct: As %{domain} is closing down, you will only get limited access to your account. view_strikes: View past strikes against your account too_fast: Form submitted too fast, try again. use_security_key: Use security key @@ -1356,6 +1367,7 @@ en-GB: '86400': 1 day expires_in_prompt: Never generate: Generate invite link + invalid: This invite is not valid invited_by: 'You were invited by:' max_uses: one: 1 use @@ -1568,6 +1580,9 @@ en-GB: over_daily_limit: You have exceeded the limit of %{limit} scheduled posts for today over_total_limit: You have exceeded the limit of %{limit} scheduled posts too_soon: The scheduled date must be in the future + self_destruct: + lead_html: Unfortunately, <strong>%{domain}</strong> is permanently closing down. If you had an account there, you will not be able to continue using it, but you can still request a backup of your data. + title: This server is closing down sessions: activity: Last activity browser: Browser @@ -1736,6 +1751,7 @@ en-GB: default: "%b %d, %Y, %H:%M" month: "%b %Y" time: "%H:%M" + with_time_zone: "%b %d, %Y, %H:%M %Z" translation: errors: quota_exceeded: The server-wide usage quota for the translation service has been exceeded. diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 63779e5bd..caf253c69 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -656,6 +656,10 @@ sk: rules_check: action: Spravuj serverové pravidlá message_html: Neurčil/a si žiadne serverové pravidlá. + software_version_critical_check: + action: Pozri dostupné aktualizácie + software_version_patch_check: + action: Pozri dostupné aktualizácie upload_check_privacy_error: action: Pozri tu pre viac informácií upload_check_privacy_error_object_storage: From 4ad2e87c48f8ebdeeb6eab56dc195b9e28f7a5d2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 09:45:30 +0100 Subject: [PATCH 253/255] Update dependency debug to v1.9.0 (#28315) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 738bc7b8b..4b39692d0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -220,9 +220,9 @@ GEM database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) date (3.3.4) - debug (1.8.0) - irb (>= 1.5.0) - reline (>= 0.3.1) + debug (1.9.0) + irb (~> 1.10) + reline (>= 0.3.8) debug_inspector (1.1.0) devise (4.9.3) bcrypt (~> 3.0) From b5a1013ae36a0ab495aa727a397b9fc9f4340a2c Mon Sep 17 00:00:00 2001 From: Matt Jankowski <matt@jankowski.online> Date: Mon, 11 Dec 2023 05:23:45 -0500 Subject: [PATCH 254/255] Combine `CLI::...` spec example subjects (#28285) --- spec/lib/mastodon/cli/accounts_spec.rb | 263 ++++++++---------------- spec/lib/mastodon/cli/ip_blocks_spec.rb | 89 ++++---- spec/lib/mastodon/cli/settings_spec.rb | 37 ++-- 3 files changed, 138 insertions(+), 251 deletions(-) diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index 06860c2ff..563f6e877 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -34,23 +34,21 @@ describe Mastodon::CLI::Accounts do let(:action) { :create } shared_examples 'a new user with given email address and username' do - it 'creates a new user with the specified email address' do - subject - - expect(User.find_by(email: options[:email])).to be_present - end - - it 'creates a new local account with the specified username' do - subject - - expect(Account.find_local('tootctl_username')).to be_present - end - - it 'returns "OK" and newly generated password' do + it 'creates user and accounts from options and displays success message' do allow(SecureRandom).to receive(:hex).and_return('test_password') expect { subject } - .to output_results("OK\nNew password: test_password") + .to output_results('OK', 'New password: test_password') + expect(user_from_options).to be_present + expect(account_from_options).to be_present + end + + def user_from_options + User.find_by(email: options[:email]) + end + + def account_from_options + Account.find_local('tootctl_username') end end @@ -199,14 +197,9 @@ describe Mastodon::CLI::Accounts do let(:arguments) { [user.account.username] } context 'when no option is provided' do - it 'returns a successful message' do + it 'returns a successful message and preserves user' do expect { subject } .to output_results('OK') - end - - it 'does not modify the user' do - subject - expect(user).to eq(user.reload) end end @@ -400,15 +393,10 @@ describe Mastodon::CLI::Accounts do context 'with --dry-run option' do let(:options) { { dry_run: true } } - it 'does not delete the specified user' do - subject - - expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false) - end - - it 'outputs a successful message in dry run mode' do + it 'outputs a successful message in dry run mode and does not delete the user' do expect { subject } .to output_results('OK (DRY RUN)') + expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false) end end @@ -435,15 +423,12 @@ describe Mastodon::CLI::Accounts do context 'with --dry-run option' do let(:options) { { email: account.user.email, dry_run: true } } - it 'does not delete the user' do - subject - - expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false) - end - - it 'outputs a successful message in dry run mode' do + it 'outputs a successful message in dry run mode and does not delete the user' do expect { subject } .to output_results('OK (DRY RUN)') + expect(delete_account_service) + .to_not have_received(:call) + .with(account, reserve_email: false) end end @@ -482,20 +467,19 @@ describe Mastodon::CLI::Accounts do context 'when the number is positive' do let(:options) { { number: 2 } } - it 'approves the earliest n pending registrations' do + it 'approves the earliest n pending registrations but not the remaining ones' do subject - n_earliest_pending_registrations = User.order(created_at: :asc).first(options[:number]) - expect(n_earliest_pending_registrations.all?(&:approved?)).to be(true) + expect(pending_registrations.all?(&:approved?)).to be(false) end - it 'does not approve the remaining pending registrations' do - subject + def n_earliest_pending_registrations + User.order(created_at: :asc).first(options[:number]) + end - pending_registrations = User.order(created_at: :asc).last(total_users - options[:number]) - - expect(pending_registrations.all?(&:approved?)).to be(false) + def pending_registrations + User.order(created_at: :asc).last(total_users - options[:number]) end end @@ -512,15 +496,10 @@ describe Mastodon::CLI::Accounts do context 'when the given number is greater than the number of users' do let(:options) { { number: total_users * 2 } } - it 'approves all users' do - subject - - expect(User.pluck(:approved).all?(true)).to be(true) - end - - it 'does not raise any error' do + it 'approves all users and does not raise any error' do expect { subject } .to_not raise_error + expect(User.pluck(:approved).all?(true)).to be(true) end end end @@ -575,18 +554,13 @@ describe Mastodon::CLI::Accounts do stub_parallelize_with_progress! end - it 'makes all local accounts follow the target account' do - subject - + it 'displays a successful message and makes all local accounts follow the target account' do + expect { subject } + .to output_results("OK, followed target from #{Account.local.count} accounts") expect(follow_service).to have_received(:call).with(follower_bob, target_account, any_args).once expect(follow_service).to have_received(:call).with(follower_rony, target_account, any_args).once expect(follow_service).to have_received(:call).with(follower_charles, target_account, any_args).once end - - it 'displays a successful message' do - expect { subject } - .to output_results("OK, followed target from #{Account.local.count} accounts") - end end end @@ -618,18 +592,13 @@ describe Mastodon::CLI::Accounts do stub_parallelize_with_progress! end - it 'makes all local accounts unfollow the target account' do - subject - + it 'displays a successful message and makes all local accounts unfollow the target account' do + expect { subject } + .to output_results('OK, unfollowed target from 3 accounts') expect(unfollow_service).to have_received(:call).with(follower_chris, target_account).once expect(unfollow_service).to have_received(:call).with(follower_rambo, target_account).once expect(unfollow_service).to have_received(:call).with(follower_ana, target_account).once end - - it 'displays a successful message' do - expect { subject } - .to output_results('OK, unfollowed target from 3 accounts') - end end end @@ -651,22 +620,17 @@ describe Mastodon::CLI::Accounts do let(:user) { account.user } let(:arguments) { [account.username] } - it 'creates a new backup for the specified user' do - expect { subject }.to change { user.backups.count }.by(1) - end - - it 'creates a backup job' do - allow(BackupWorker).to receive(:perform_async) - - subject - latest_backup = user.backups.last + before { allow(BackupWorker).to receive(:perform_async) } + it 'creates a new backup and backup job for the specified user and outputs success message' do + expect { subject } + .to change { user.backups.count }.by(1) + .and output_results('OK') expect(BackupWorker).to have_received(:perform_async).with(latest_backup.id).once end - it 'displays a successful message' do - expect { subject } - .to output_results('OK') + def latest_backup + user.backups.last end end end @@ -963,15 +927,15 @@ describe Mastodon::CLI::Accounts do expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_in).with(anything, account.id, anything).once end + end - context 'when the given username is not found' do - let(:arguments) { ['non_existent_username'] } + context 'when the given username is not found' do + let(:arguments) { ['non_existent_username'] } - it 'exits with an error message when the specified username is not found' do - expect { subject } - .to output_results('No such account') - .and raise_error(SystemExit) - end + it 'exits with an error message when the specified username is not found' do + expect { subject } + .to output_results('No such account') + .and raise_error(SystemExit) end end @@ -1071,15 +1035,10 @@ describe Mastodon::CLI::Accounts do allow(from_account).to receive(:destroy) end - it 'merges "from_account" into "to_account"' do + it 'merges `from_account` into `to_account` and deletes `from_account`' do subject expect(to_account).to have_received(:merge_with!).with(from_account).once - end - - it 'deletes "from_account"' do - subject - expect(from_account).to have_received(:destroy).once end end @@ -1099,15 +1058,10 @@ describe Mastodon::CLI::Accounts do allow(from_account).to receive(:destroy) end - it 'merges "from_account" into "to_account"' do + it 'merges "from_account" into "to_account" and deletes from_account' do subject expect(to_account).to have_received(:merge_with!).with(from_account).once - end - - it 'deletes "from_account"' do - subject - expect(from_account).to have_received(:destroy) end end @@ -1134,28 +1088,23 @@ describe Mastodon::CLI::Accounts do stub_request(:head, 'https://example.net/users/tales').to_return(status: 200) end - it 'deletes all inactive remote accounts that longer exist in the origin server' do - subject - + def expect_delete_inactive_remote_accounts expect(delete_account_service).to have_received(:call).with(bob, reserve_username: false).once expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once end - it 'does not delete any active remote account that still exists in the origin server' do - subject - + def expect_not_delete_active_accounts expect(delete_account_service).to_not have_received(:call).with(tom, reserve_username: false) expect(delete_account_service).to_not have_received(:call).with(ana, reserve_username: false) expect(delete_account_service).to_not have_received(:call).with(tales, reserve_username: false) end - it 'touches inactive remote accounts that have not been deleted' do - expect { subject }.to(change { tales.reload.updated_at }) - end - - it 'displays the summary correctly' do + it 'touches inactive remote accounts that have not been deleted and summarizes activity' do expect { subject } - .to output_results('Visited 5 accounts, removed 2') + .to change { tales.reload.updated_at } + .and output_results('Visited 5 accounts, removed 2') + expect_delete_inactive_remote_accounts + expect_not_delete_active_accounts end end @@ -1168,16 +1117,15 @@ describe Mastodon::CLI::Accounts do stub_request(:head, 'https://example.net/users/tales').to_return(status: 404) end - it 'deletes inactive remote accounts that longer exist in the specified domain' do - subject - + def expect_delete_inactive_remote_accounts expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once expect(delete_account_service).to have_received(:call).with(tales, reserve_username: false).once end - it 'displays the summary correctly' do + it 'displays the summary correctly and deletes inactive remote accounts' do expect { subject } .to output_results('Visited 2 accounts, removed 2') + expect_delete_inactive_remote_accounts end end @@ -1189,15 +1137,14 @@ describe Mastodon::CLI::Accounts do stub_request(:head, 'https://example.net/users/gon').to_return(status: 200) end - it 'skips accounts from the unavailable domain' do - subject - + def expect_skip_accounts_from_unavailable_domain expect(delete_account_service).to_not have_received(:call).with(tales, reserve_username: false) end - it 'displays the summary correctly' do + it 'displays the summary correctly and skip accounts from unavailable domains' do expect { subject } .to output_results("Visited 5 accounts, removed 0\nThe following domains were not available during the check:\n example.net") + expect_skip_accounts_from_unavailable_domain end end @@ -1268,25 +1215,14 @@ describe Mastodon::CLI::Accounts do before do accounts.each { |account| target_account.follow!(account) } - end - - it 'resets all "following" relationships from the target account' do - subject - - expect(target_account.reload.following).to be_empty - end - - it 'calls BootstrapTimelineWorker once to rebuild the timeline' do allow(BootstrapTimelineWorker).to receive(:perform_async) - - subject - - expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once end - it 'displays a successful message' do + it 'resets following relationships and displays a successful message and rebuilds timeline' do expect { subject } .to output_results("Processed #{total_relationships} relationships") + expect(target_account.reload.following).to be_empty + expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once end end @@ -1297,15 +1233,10 @@ describe Mastodon::CLI::Accounts do accounts.each { |account| account.follow!(target_account) } end - it 'resets all "followers" relationships from the target account' do - subject - - expect(target_account.reload.followers).to be_empty - end - - it 'displays a successful message' do + it 'resets followers relationships and displays a successful message' do expect { subject } .to output_results("Processed #{total_relationships} relationships") + expect(target_account.reload.followers).to be_empty end end @@ -1315,31 +1246,15 @@ describe Mastodon::CLI::Accounts do before do accounts.first(2).each { |account| account.follow!(target_account) } accounts.last(1).each { |account| target_account.follow!(account) } - end - - it 'resets all "followers" relationships from the target account' do - subject - - expect(target_account.reload.followers).to be_empty - end - - it 'resets all "following" relationships from the target account' do - subject - - expect(target_account.reload.following).to be_empty - end - - it 'calls BootstrapTimelineWorker once to rebuild the timeline' do allow(BootstrapTimelineWorker).to receive(:perform_async) - - subject - - expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once end - it 'displays a successful message' do + it 'resets followers and following and displays a successful message and rebuilds timeline' do expect { subject } .to output_results("Processed #{total_relationships} relationships") + expect(target_account.reload.followers).to be_empty + expect(target_account.reload.following).to be_empty + expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once end end end @@ -1360,57 +1275,51 @@ describe Mastodon::CLI::Accounts do stub_parallelize_with_progress! end - it 'prunes all remote accounts with no interactions with local users' do - subject - + def expect_prune_remote_accounts_without_interaction prunable_account_ids = prunable_accounts.pluck(:id) expect(Account.where(id: prunable_account_ids).count).to eq(0) end - it 'displays a successful message' do + it 'displays a successful message and handles accounts correctly' do expect { subject } .to output_results("OK, pruned #{prunable_accounts.size} accounts") + expect_prune_remote_accounts_without_interaction + expect_not_prune_local_accounts + expect_not_prune_bot_accounts + expect_not_prune_group_accounts + expect_not_prune_mentioned_accounts end - it 'does not prune local accounts' do - subject - + def expect_not_prune_local_accounts expect(Account.exists?(id: local_account.id)).to be(true) end - it 'does not prune bot accounts' do - subject - + def expect_not_prune_bot_accounts expect(Account.exists?(id: bot_account.id)).to be(true) end - it 'does not prune group accounts' do - subject - + def expect_not_prune_group_accounts expect(Account.exists?(id: group_account.id)).to be(true) end - it 'does not prune accounts that have been mentioned' do - subject - + def expect_not_prune_mentioned_accounts expect(Account.exists?(id: mentioned_account.id)).to be true end context 'with --dry-run option' do let(:options) { { dry_run: true } } - it 'does not prune any account' do - subject - + def expect_no_account_prunes prunable_account_ids = prunable_accounts.pluck(:id) expect(Account.where(id: prunable_account_ids).count).to eq(prunable_accounts.size) end - it 'displays a successful message with (DRY RUN)' do + it 'displays a successful message with (DRY RUN) and doesnt prune anything' do expect { subject } .to output_results("OK, pruned #{prunable_accounts.size} accounts (DRY RUN)") + expect_no_account_prunes end end end diff --git a/spec/lib/mastodon/cli/ip_blocks_spec.rb b/spec/lib/mastodon/cli/ip_blocks_spec.rb index dc967a69c..1d6c47268 100644 --- a/spec/lib/mastodon/cli/ip_blocks_spec.rb +++ b/spec/lib/mastodon/cli/ip_blocks_spec.rb @@ -33,26 +33,25 @@ describe Mastodon::CLI::IpBlocks do let(:arguments) { ip_list } shared_examples 'ip address blocking' do - it 'blocks all specified IP addresses' do - subject - - blocked_ip_addresses = IpBlock.where(ip: ip_list).pluck(:ip) - expected_ip_addresses = ip_list.map { |ip| IPAddr.new(ip) } - - expect(blocked_ip_addresses).to match_array(expected_ip_addresses) + def blocked_ip_addresses + IpBlock.where(ip: ip_list).pluck(:ip) end - it 'sets the severity for all blocked IP addresses' do - subject - - blocked_ips_severity = IpBlock.where(ip: ip_list).pluck(:severity).all?(options[:severity]) - - expect(blocked_ips_severity).to be(true) + def expected_ip_addresses + ip_list.map { |ip| IPAddr.new(ip) } end - it 'displays a success message with a summary' do + def blocked_ips_severity + IpBlock.where(ip: ip_list).pluck(:severity).all?(options[:severity]) + end + + it 'blocks and sets severity for ip address and displays summary' do expect { subject } .to output_results("Added #{ip_list.size}, skipped 0, failed 0") + expect(blocked_ip_addresses) + .to match_array(expected_ip_addresses) + expect(blocked_ips_severity) + .to be(true) end end @@ -64,17 +63,13 @@ describe Mastodon::CLI::IpBlocks do let!(:blocked_ip) { IpBlock.create(ip: ip_list.last, severity: options[:severity]) } let(:arguments) { ip_list } - it 'skips the already blocked IP address' do - allow(IpBlock).to receive(:new).and_call_original + before { allow(IpBlock).to receive(:new).and_call_original } - subject - - expect(IpBlock).to_not have_received(:new).with(ip: ip_list.last) - end - - it 'displays the correct summary' do + it 'skips already block ip and displays the correct summary' do expect { subject } .to output_results("#{ip_list.last} is already blocked\nAdded #{ip_list.size - 1}, skipped 1, failed 0") + + expect(IpBlock).to_not have_received(:new).with(ip: ip_list.last) end context 'with --force option' do @@ -179,15 +174,10 @@ describe Mastodon::CLI::IpBlocks do ip_list.each { |ip| IpBlock.create(ip: ip, severity: :no_access) } end - it 'removes exact IP blocks' do - subject - - expect(IpBlock.where(ip: ip_list)).to_not exist - end - - it 'displays success message with a summary' do + it 'removes exact ip blocks and displays success message with a summary' do expect { subject } .to output_results("Removed #{ip_list.size}, skipped 0") + expect(IpBlock.where(ip: ip_list)).to_not exist end end @@ -198,16 +188,19 @@ describe Mastodon::CLI::IpBlocks do let(:arguments) { ['192.168.0.5', '10.0.1.50'] } let(:options) { { force: true } } - it 'removes blocks for IP ranges that cover given IP(s)' do + it 'removes blocks for IP ranges that cover given IP(s) and keeps other ranges' do subject - expect(IpBlock.where(id: [first_ip_range_block.id, second_ip_range_block.id])).to_not exist + expect(covered_ranges).to_not exist + expect(other_ranges).to exist end - it 'does not remove other IP ranges' do - subject + def covered_ranges + IpBlock.where(id: [first_ip_range_block.id, second_ip_range_block.id]) + end - expect(IpBlock.where(id: third_ip_range_block.id)).to exist + def other_ranges + IpBlock.where(id: third_ip_range_block.id) end end @@ -215,14 +208,12 @@ describe Mastodon::CLI::IpBlocks do let(:unblocked_ip) { '192.0.2.1' } let(:arguments) { [unblocked_ip] } - it 'skips the IP address' do + it 'skips the IP address and displays summary' do expect { subject } - .to output_results("#{unblocked_ip} is not yet blocked") - end - - it 'displays the summary correctly' do - expect { subject } - .to output_results('Removed 0, skipped 1') + .to output_results( + "#{unblocked_ip} is not yet blocked", + 'Removed 0, skipped 1' + ) end end @@ -230,14 +221,12 @@ describe Mastodon::CLI::IpBlocks do let(:invalid_ip) { '320.15.175.0' } let(:arguments) { [invalid_ip] } - it 'skips the invalid IP address' do + it 'skips the invalid IP address and displays summary' do expect { subject } - .to output_results("#{invalid_ip} is invalid") - end - - it 'displays the summary correctly' do - expect { subject } - .to output_results('Removed 0, skipped 1') + .to output_results( + "#{invalid_ip} is invalid", + 'Removed 0, skipped 1' + ) end end @@ -265,7 +254,7 @@ describe Mastodon::CLI::IpBlocks do .to output_results("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}") end - it 'does not export bloked IPs with different severities' do + it 'does not export blocked IPs with different severities' do expect { subject } .to_not output_results("#{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}") end @@ -279,7 +268,7 @@ describe Mastodon::CLI::IpBlocks do .to output_results("deny #{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};\ndeny #{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix};") end - it 'does not export bloked IPs with different severities' do + it 'does not export blocked IPs with different severities' do expect { subject } .to_not output_results("deny #{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};") end diff --git a/spec/lib/mastodon/cli/settings_spec.rb b/spec/lib/mastodon/cli/settings_spec.rb index 02d1042c5..568ee0039 100644 --- a/spec/lib/mastodon/cli/settings_spec.rb +++ b/spec/lib/mastodon/cli/settings_spec.rb @@ -20,37 +20,29 @@ describe Mastodon::CLI::Settings do describe '#open' do let(:action) { :open } - it 'changes "registrations_mode" to "open"' do - expect { subject }.to change(Setting, :registrations_mode).from(nil).to('open') - end - - it 'displays success message' do + it 'changes "registrations_mode" to "open" and displays success' do expect { subject } - .to output_results('OK') + .to change(Setting, :registrations_mode).from(nil).to('open') + .and output_results('OK') end end describe '#approved' do let(:action) { :approved } - it 'changes "registrations_mode" to "approved"' do - expect { subject }.to change(Setting, :registrations_mode).from(nil).to('approved') - end - - it 'displays success message' do + it 'changes "registrations_mode" to "approved" and displays success' do expect { subject } - .to output_results('OK') + .to change(Setting, :registrations_mode).from(nil).to('approved') + .and output_results('OK') end context 'with --require-reason' do let(:options) { { require_reason: true } } - it 'changes "registrations_mode" to "approved"' do - expect { subject }.to change(Setting, :registrations_mode).from(nil).to('approved') - end - - it 'sets "require_invite_text" to "true"' do - expect { subject }.to change(Setting, :require_invite_text).from(false).to(true) + it 'changes registrations_mode and require_invite_text' do + expect { subject } + .to change(Setting, :registrations_mode).from(nil).to('approved') + .and change(Setting, :require_invite_text).from(false).to(true) end end end @@ -58,13 +50,10 @@ describe Mastodon::CLI::Settings do describe '#close' do let(:action) { :close } - it 'changes "registrations_mode" to "none"' do - expect { subject }.to change(Setting, :registrations_mode).from(nil).to('none') - end - - it 'displays success message' do + it 'changes "registrations_mode" to "none" and displays success' do expect { subject } - .to output_results('OK') + .to change(Setting, :registrations_mode).from(nil).to('none') + .and output_results('OK') end end end From f3864db4090b8cec212fb99c3dabccfb6a6c7642 Mon Sep 17 00:00:00 2001 From: Claire <claire.github-309c@sitedethib.com> Date: Mon, 11 Dec 2023 15:23:30 +0100 Subject: [PATCH 255/255] Fix notification sounds (#28316) --- app/javascript/mastodon/actions/notifications_typed.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/actions/notifications_typed.ts b/app/javascript/mastodon/actions/notifications_typed.ts index 7e51fa51e..176362f4b 100644 --- a/app/javascript/mastodon/actions/notifications_typed.ts +++ b/app/javascript/mastodon/actions/notifications_typed.ts @@ -18,6 +18,6 @@ export const notificationsUpdate = createAction( playSound: boolean; }) => ({ payload: args, - meta: { playSound: playSound ? { sound: 'boop' } : undefined }, + meta: { sound: playSound ? 'boop' : undefined }, }), );