From 492e25da0651195873e0c2e9632a7f183ea6b2ef Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:56:52 +0100 Subject: [PATCH 01/63] Update dependency webmock to v3.20.0 (#29120) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index b76f449b26..d60def5222 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -182,7 +182,8 @@ GEM cose (1.3.0) cbor (~> 0.5.9) openssl-signature_algorithm (~> 1.0) - crack (0.4.5) + crack (0.4.6) + bigdecimal rexml crass (1.0.6) css_parser (1.14.0) @@ -314,7 +315,7 @@ GEM rainbow rubocop (>= 1.0) sysexits (~> 1.1) - hashdiff (1.0.1) + hashdiff (1.1.0) hashie (5.0.0) hcaptcha (7.1.0) json @@ -792,7 +793,7 @@ GEM webfinger (1.2.0) activesupport httpclient (>= 2.4) - webmock (3.19.1) + webmock (3.20.0) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) From da50217b8899f36137c5405423a41b8520dfdfb2 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 7 Feb 2024 05:59:32 -0500 Subject: [PATCH 02/63] Combine repeated requests in `admin/accounts` controller spec (#29119) --- .../admin/accounts_controller_spec.rb | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/spec/controllers/admin/accounts_controller_spec.rb b/spec/controllers/admin/accounts_controller_spec.rb index ef3053b6b3..b90bb414b0 100644 --- a/spec/controllers/admin/accounts_controller_spec.rb +++ b/spec/controllers/admin/accounts_controller_spec.rb @@ -9,18 +9,8 @@ RSpec.describe Admin::AccountsController do describe 'GET #index' do let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - - around do |example| - default_per_page = Account.default_per_page - Account.paginates_per 1 - example.run - Account.paginates_per default_per_page - end - - it 'filters with parameters' do - account_filter = instance_double(AccountFilter, results: Account.all) - allow(AccountFilter).to receive(:new).and_return(account_filter) - params = { + let(:params) do + { origin: 'local', by_domain: 'domain', status: 'active', @@ -29,25 +19,35 @@ RSpec.describe Admin::AccountsController do email: 'local-part@domain', ip: '0.0.0.42', } - - get :index, params: params - - expect(AccountFilter).to have_received(:new).with(hash_including(params)) end - it 'paginates accounts' do + around do |example| + default_per_page = Account.default_per_page + Account.paginates_per 1 + example.run + Account.paginates_per default_per_page + end + + before do Fabricate(:account) - get :index, params: { page: 2 } - - accounts = assigns(:accounts) - expect(accounts.count).to eq 1 - expect(accounts.klass).to be Account + account_filter = instance_double(AccountFilter, results: Account.all) + allow(AccountFilter).to receive(:new).and_return(account_filter) end - it 'returns http success' do - get :index - expect(response).to have_http_status(200) + it 'returns success and paginates and filters with parameters' do + get :index, params: params.merge(page: 2) + + expect(response) + .to have_http_status(200) + expect(assigns(:accounts)) + .to have_attributes( + count: eq(1), + klass: be(Account) + ) + expect(AccountFilter) + .to have_received(:new) + .with(hash_including(params)) end end From eeabf9af72bf27dbc7e997b73737ac3bf1122813 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 7 Feb 2024 12:52:38 +0100 Subject: [PATCH 03/63] Fix compatibility with Redis <6.2 (#29123) --- app/controllers/auth/sessions_controller.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb index 962b78de65..6ed7b2baac 100644 --- a/app/controllers/auth/sessions_controller.rb +++ b/app/controllers/auth/sessions_controller.rb @@ -183,7 +183,9 @@ class Auth::SessionsController < Devise::SessionsController ) # Only send a notification email every hour at most - return if redis.set("2fa_failure_notification:#{user.id}", '1', ex: 1.hour, get: true).present? + return if redis.get("2fa_failure_notification:#{user.id}").present? + + redis.set("2fa_failure_notification:#{user.id}", '1', ex: 1.hour) UserMailer.failed_2fa(user, request.remote_ip, request.user_agent, Time.now.utc).deliver_later! end From 2912829411867d221c13b35f37ab6aa0aac2edd7 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 7 Feb 2024 13:09:43 +0100 Subject: [PATCH 04/63] Add support for specifying custom CA cert for Elasticsearch (#29122) --- config/initializers/chewy.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/initializers/chewy.rb b/config/initializers/chewy.rb index 076f383324..0fb311dbb3 100644 --- a/config/initializers/chewy.rb +++ b/config/initializers/chewy.rb @@ -7,6 +7,9 @@ user = ENV.fetch('ES_USER', nil).presence password = ENV.fetch('ES_PASS', nil).presence fallback_prefix = ENV.fetch('REDIS_NAMESPACE', nil).presence prefix = ENV.fetch('ES_PREFIX') { fallback_prefix } +ca_file = ENV.fetch('ES_CA_CERT', nil).presence + +transport_options = { ssl: { ca_file: ca_file } } if ca_file.present? Chewy.settings = { host: "#{host}:#{port}", @@ -18,6 +21,7 @@ Chewy.settings = { index: { number_of_replicas: ['single_node_cluster', nil].include?(ENV['ES_PRESET'].presence) ? 0 : 1, }, + transport_options: transport_options, } # We use our own async strategy even outside the request-response From 17052714a28e3b30c5d2053d8dbea4a352c4199b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 13:38:37 +0100 Subject: [PATCH 05/63] New Crowdin Translations (automated) (#29121) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/tok.json | 167 +++++++++++++++++++++++ config/locales/activerecord.tok.yml | 6 + config/locales/devise.tok.yml | 1 + config/locales/doorkeeper.tok.yml | 1 + config/locales/simple_form.tok.yml | 14 ++ config/locales/tok.yml | 1 + 6 files changed, 190 insertions(+) create mode 100644 app/javascript/mastodon/locales/tok.json create mode 100644 config/locales/activerecord.tok.yml create mode 100644 config/locales/devise.tok.yml create mode 100644 config/locales/doorkeeper.tok.yml create mode 100644 config/locales/simple_form.tok.yml create mode 100644 config/locales/tok.yml diff --git a/app/javascript/mastodon/locales/tok.json b/app/javascript/mastodon/locales/tok.json new file mode 100644 index 0000000000..a0227969dd --- /dev/null +++ b/app/javascript/mastodon/locales/tok.json @@ -0,0 +1,167 @@ +{ + "about.contact": "toki:", + "about.domain_blocks.no_reason_available": "mi sona ala e tan", + "about.not_available": "lon kulupu ni la sina ken alasa ala e sona ni.", + "about.rules": "lawa kulupu", + "account.account_note_header": "sona awen", + "account.block": "o weka e @{name}", + "account.block_domain": "o weka e ma {domain}", + "account.block_short": "o weka e jan", + "account.blocked": "jan ni li weka", + "account.browse_more_on_origin_server": "sina tawa ma tan pi jan ni la sina ken lukin e mute", + "account.cancel_follow_request": "o pini wile kute", + "account.copy": "o pali same e linja pi lipu jan", + "account.direct": "len la o mu e @{name}", + "account.disable_notifications": "@{name} li toki la o toki ala e toki ona tawa mi", + "account.domain_blocked": "ma ni li weka tawa sina", + "account.edit_profile": "o ante e lipu mi", + "account.enable_notifications": "@{name} li toki la o toki e toki ona tawa mi", + "account.endorse": "lipu jan la o suli e ni", + "account.featured_tags.last_status_at": "sitelen pini pi jan ni li lon tenpo {date}", + "account.featured_tags.last_status_never": "toki ala li lon", + "account.follow": "o kute", + "account.follow_back": "jan ni li kute e sina. o kute", + "account.followers": "jan kute", + "account.followers.empty": "jan ala li kute e jan ni", + "account.following": "sina kute e jan ni", + "account.follows.empty": "jan ni li kute e jan ala", + "account.go_to_profile": "o tawa lipu jan", + "account.hide_reblogs": "o lukin ala e pana toki tan @{name}", + "account.languages": "sina wile lukin e sitelen pi toki seme", + "account.locked_info": "sina wile kute e jan ni la ona o toki e ken", + "account.mention": "o toki e jan @{name}", + "account.moved_to": "lipu jan sin pi jan {name} li ni:", + "account.mute": "o kute ala e @{name}", + "account.mute_notifications_short": "o kute ala e mu tan jan ni", + "account.mute_short": "o kute ala", + "account.muted": "sina kute ala e jan ni", + "account.no_bio": "lipu li weka", + "account.posts": "toki suli", + "account.posts_with_replies": "toki ale", + "account.report": "jan @{name} la o toki e lawa", + "account.requested": "jan ni o ken e kute sina. sina pini wile kute la o luka e ni", + "account.requested_follow": "{name} li wile kute e sina", + "account.show_reblogs": "o lukin e pana toki tan @{name}", + "account.unblock_short": "o pini weka", + "account.unfollow": "o pini kute", + "account.unmute": "o ken lukin e sitelen tan @{name}", + "account.unmute_notifications_short": "o kute e mu tan jan ni", + "account.unmute_short": "o ken kute e jan ni", + "alert.unexpected.message": "pakala li lon", + "alert.unexpected.title": "pakala", + "announcement.announcement": "toki suli", + "audio.hide": "o len e kalama", + "bundle_column_error.error.title": "pakala!", + "bundle_column_error.network.title": "pakala la ilo sina li toki ala tawa ilo ante", + "bundle_column_error.retry": "o ni sin", + "bundle_column_error.routing.body": "ilo li sona ala e lipu wile. sina pana ala pana e nasin pona tawa lipu?", + "bundle_column_error.routing.title": "pakala nanpa 404", + "bundle_modal_error.message": "ilo li wile kama e ijo ni, taso pakala li lon.", + "bundle_modal_error.retry": "o ni sin", + "column.mutes": "sina wile ala kute e jan ni", + "compose.language.change": "o ante e nasin toki", + "compose.language.search": "o alasa e nasin toki...", + "compose.saved.body": "ilo li awen e ijo pana sina.", + "compose_form.direct_message_warning_learn_more": "o kama sona e ijo ante", + "compose_form.placeholder": "o toki", + "compose_form.poll.option_placeholder": "ken nanpa {number}", + "compose_form.poll.switch_to_multiple": "o ante e nasin pana. pana mute o ken", + "compose_form.poll.switch_to_single": "o ante e nasin pana. pana wan taso o lon", + "compose_form.publish": "o toki", + "compose_form.publish_form": "o open toki sin", + "compose_form.reply": "o toki lon ijo ni", + "compose_form.save_changes": "o sin e ni", + "compose_form.spoiler.marked": "o weka e toki pi ijo ike ken", + "confirmations.cancel_follow_request.confirm": "o weka e wile sina", + "confirmations.cancel_follow_request.message": "sina awen ala awen wile weka e wile kute sina lon {name}?", + "confirmations.delete.confirm": "o pakala", + "confirmations.delete.message": "sina wile ala wile pakala e toki ni", + "confirmations.delete_list.confirm": "o pakala", + "confirmations.delete_list.message": "sina wile ala wile pakala e lipu ni", + "confirmations.discard_edit_media.confirm": "o weka", + "confirmations.edit.confirm": "o ante", + "confirmations.logout.confirm": "o weka", + "confirmations.logout.message": "sina wile ala wile weka", + "confirmations.mute.confirm": "sina wile ala kute e jan ni", + "confirmations.mute.message": "sina awen ala awen wile kute ala e {name}?", + "confirmations.redraft.confirm": "o pakala o pali sin e toki", + "conversation.mark_as_read": "ni o sin ala", + "conversation.open": "o lukin e toki", + "conversation.with": "lon {names}", + "directory.new_arrivals": "jan pi kama sin", + "dismissable_banner.dismiss": "o weka", + "emoji_button.flags": "len ma", + "emoji_button.food": "moku", + "emoji_button.label": "o pana e Emosi", + "emoji_button.nature": "soweli en kasi", + "emoji_button.not_found": "sitelen Emosi ala li lon", + "emoji_button.objects": "ijo", + "emoji_button.people": "jan", + "emoji_button.search": "o alasa", + "emoji_button.search_results": "ijo pi alasa ni", + "emoji_button.symbols": "sitelen", + "emoji_button.travel": "ma en tawa", + "empty_column.account_timeline": "toki ala li lon!", + "empty_column.followed_tags": "sina alasa ala e toki ꞏ sina alasa e toki la toki li lon ni", + "empty_column.hashtag": "ala li lon toki ni", + "empty_column.mutes": "jan ala la sina wile ala kute.", + "explore.search_results": "ijo pi alasa ni", + "explore.suggested_follows": "jan", + "explore.title": "o alasa", + "explore.trending_links": "sin", + "explore.trending_statuses": "toki", + "filter_modal.select_filter.search": "o alasa anu pali", + "firehose.all": "ale", + "firehose.local": "ilo ni", + "firehose.remote": "ilo ante", + "follow_suggestions.view_all": "o lukin e ale", + "footer.privacy_policy": "lawa len", + "footer.source_code": "o lukin e toki ilo", + "footer.status": "lon", + "hashtag.column_settings.tag_mode.all": "ale ni", + "hashtag.column_settings.tag_mode.any": "wan ni", + "hashtag.column_settings.tag_mode.none": "ala ni", + "home.pending_critical_update.link": "o lukin e ijo ilo sin", + "interaction_modal.title.follow": "o kute e {name}", + "keyboard_shortcuts.muted": "sina wile ala kute e jan la o lukin e ona ale", + "lists.edit.submit": "o ante e nimi", + "mute_modal.duration": "tenpo seme", + "mute_modal.indefinite": "tenpo ale", + "navigation_bar.filters": "sina wile ala kute e nimi ni", + "navigation_bar.mutes": "sina wile ala kute e jan ni", + "report.block_explanation": "sina kama lukin ala e toki ona. ona li kama ala ken lukin e toki sina li kama ala ken kute e sina. ona li ken sona e kama ni.", + "report.category.title": "ike seme li lon {type} ni", + "report.mute": "o kute ala e ona", + "report.mute_explanation": "sina kama ala lukin e ijo pana ona. ona li awen ken kute e sina li awen ken lukin e sina li sona ala e weka kute sina e weka lukin sina.", + "search_popout.language_code": "nimi toki kepeken nasin ISO", + "status.edit": "o ante", + "status.edited": "ni li ante lon {date}", + "status.embed": "ni o lon insa pi lipu ante", + "status.history.created": "{name} li pali e ni lon {date}", + "status.history.edited": "{name} li ante lon {date}", + "status.load_more": "o kama e ijo ante", + "status.mute": "o kute ala e @{name}", + "status.mute_conversation": "o kute ala e ijo pi toki ni", + "status.show_less": "o lili e ni", + "status.show_less_all": "o lili e ale", + "status.show_more": "o suli e ni", + "status.show_more_all": "o suli e ale", + "status.show_original": "ijo mama pi ijo ni li seme", + "status.unmute_conversation": "o ken kute e ijo pi toki ni", + "timeline_hint.resources.statuses": "ijo pi tenpo suli", + "units.short.million": "{count}AAA", + "upload_error.limit": "ilo li ken ala e suli pi ijo ni.", + "upload_form.audio_description": "o toki e ijo kute tawa jan pi kute ala, tawa jan pi kute lili", + "upload_form.description": "o toki e ijo lukin tawa jan pi lukin ala, tawa jan pi lukin lili", + "upload_form.edit": "o ante", + "upload_form.video_description": "o toki e ijo kute tawa jan pi kute ala, tawa jan pi kute lili, e ijo lukin tawa jan pi lukin ala, tawa jan pi lukin lili", + "upload_modal.choose_image": "sitelen seme", + "upload_modal.description_placeholder": "mi pu jaki tan soweli", + "upload_modal.detect_text": "ilo o alasa e nimi tan sitelen", + "upload_modal.preparing_ocr": "ilo li open e alasa nimi lon sitelen…", + "upload_progress.label": "ilo li kama jo e ijo sina...", + "upload_progress.processing": "ilo li pali…", + "video.mute": "o kalama ala", + "video.pause": "o lape e ni", + "video.unmute": "o kalama" +} diff --git a/config/locales/activerecord.tok.yml b/config/locales/activerecord.tok.yml new file mode 100644 index 0000000000..5623538ba9 --- /dev/null +++ b/config/locales/activerecord.tok.yml @@ -0,0 +1,6 @@ +--- +tok: + activerecord: + attributes: + poll: + expires_at: pini tenpo diff --git a/config/locales/devise.tok.yml b/config/locales/devise.tok.yml new file mode 100644 index 0000000000..d15ecd21b2 --- /dev/null +++ b/config/locales/devise.tok.yml @@ -0,0 +1 @@ +tok: diff --git a/config/locales/doorkeeper.tok.yml b/config/locales/doorkeeper.tok.yml new file mode 100644 index 0000000000..d15ecd21b2 --- /dev/null +++ b/config/locales/doorkeeper.tok.yml @@ -0,0 +1 @@ +tok: diff --git a/config/locales/simple_form.tok.yml b/config/locales/simple_form.tok.yml new file mode 100644 index 0000000000..9c60144bb5 --- /dev/null +++ b/config/locales/simple_form.tok.yml @@ -0,0 +1,14 @@ +--- +tok: + simple_form: + hints: + account: + display_name: nimi sina ale anu nimi sina musi. + labels: + defaults: + expires_in: ona o moli lon + setting_theme: kule lipu + user_role: + name: nimi + required: + text: ni li ken ala lon ala diff --git a/config/locales/tok.yml b/config/locales/tok.yml new file mode 100644 index 0000000000..d15ecd21b2 --- /dev/null +++ b/config/locales/tok.yml @@ -0,0 +1 @@ +tok: From 7efc33b909da0ec8a75521efab4357280a2f40ff Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 7 Feb 2024 14:35:37 +0100 Subject: [PATCH 06/63] Move HTTP Signature parsing code to its own class (#28932) --- .../activitypub/inboxes_controller.rb | 5 +- .../concerns/signature_verification.rb | 41 +------------- app/lib/signature_parser.rb | 53 +++++++++++++++++++ spec/lib/signature_parser_spec.rb | 34 ++++++++++++ 4 files changed, 91 insertions(+), 42 deletions(-) create mode 100644 app/lib/signature_parser.rb create mode 100644 spec/lib/signature_parser_spec.rb diff --git a/app/controllers/activitypub/inboxes_controller.rb b/app/controllers/activitypub/inboxes_controller.rb index ba85e0a722..e8b0f47cde 100644 --- a/app/controllers/activitypub/inboxes_controller.rb +++ b/app/controllers/activitypub/inboxes_controller.rb @@ -62,11 +62,10 @@ class ActivityPub::InboxesController < ActivityPub::BaseController return if raw_params.blank? || ENV['DISABLE_FOLLOWERS_SYNCHRONIZATION'] == 'true' || signed_request_account.nil? # Re-using the syntax for signature parameters - tree = SignatureParamsParser.new.parse(raw_params) - params = SignatureParamsTransformer.new.apply(tree) + params = SignatureParser.parse(raw_params) ActivityPub::PrepareFollowersSynchronizationService.new.call(signed_request_account, params) - rescue Parslet::ParseFailed + rescue SignatureParser::ParsingError Rails.logger.warn 'Error parsing Collection-Synchronization header' end diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb index 92f1eb5a16..3155866271 100644 --- a/app/controllers/concerns/signature_verification.rb +++ b/app/controllers/concerns/signature_verification.rb @@ -12,39 +12,6 @@ module SignatureVerification class SignatureVerificationError < StandardError; end - class SignatureParamsParser < Parslet::Parser - rule(:token) { match("[0-9a-zA-Z!#$%&'*+.^_`|~-]").repeat(1).as(:token) } - rule(:quoted_string) { str('"') >> (qdtext | quoted_pair).repeat.as(:quoted_string) >> str('"') } - # qdtext and quoted_pair are not exactly according to spec but meh - rule(:qdtext) { match('[^\\\\"]') } - rule(:quoted_pair) { str('\\') >> any } - rule(:bws) { match('\s').repeat } - rule(:param) { (token.as(:key) >> bws >> str('=') >> bws >> (token | quoted_string).as(:value)).as(:param) } - rule(:comma) { bws >> str(',') >> bws } - # Old versions of node-http-signature add an incorrect "Signature " prefix to the header - rule(:buggy_prefix) { str('Signature ') } - rule(:params) { buggy_prefix.maybe >> (param >> (comma >> param).repeat).as(:params) } - root(:params) - end - - class SignatureParamsTransformer < Parslet::Transform - rule(params: subtree(:param)) do - (param.is_a?(Array) ? param : [param]).each_with_object({}) { |(key, value), hash| hash[key] = value } - end - - rule(param: { key: simple(:key), value: simple(:val) }) do - [key, val] - end - - rule(quoted_string: simple(:string)) do - string.to_s - end - - rule(token: simple(:string)) do - string.to_s - end - end - def require_account_signature! render json: signature_verification_failure_reason, status: signature_verification_failure_code unless signed_request_account end @@ -135,12 +102,8 @@ module SignatureVerification end def signature_params - @signature_params ||= begin - raw_signature = request.headers['Signature'] - tree = SignatureParamsParser.new.parse(raw_signature) - SignatureParamsTransformer.new.apply(tree) - end - rescue Parslet::ParseFailed + @signature_params ||= SignatureParser.parse(request.headers['Signature']) + rescue SignatureParser::ParsingError raise SignatureVerificationError, 'Error parsing signature parameters' end diff --git a/app/lib/signature_parser.rb b/app/lib/signature_parser.rb new file mode 100644 index 0000000000..c09ab0c841 --- /dev/null +++ b/app/lib/signature_parser.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +class SignatureParser + class ParsingError < StandardError; end + + # The syntax of this header is defined in: + # https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#section-4 + # See https://datatracker.ietf.org/doc/html/rfc7235#appendix-C + # and https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6 + + # In addition, ignore a `Signature ` string prefix that was added by old versions + # of `node-http-signatures` + + class SignatureParamsParser < Parslet::Parser + rule(:token) { match("[0-9a-zA-Z!#$%&'*+.^_`|~-]").repeat(1).as(:token) } + rule(:quoted_string) { str('"') >> (qdtext | quoted_pair).repeat.as(:quoted_string) >> str('"') } + # qdtext and quoted_pair are not exactly according to spec but meh + rule(:qdtext) { match('[^\\\\"]') } + rule(:quoted_pair) { str('\\') >> any } + rule(:bws) { match('\s').repeat } + rule(:param) { (token.as(:key) >> bws >> str('=') >> bws >> (token | quoted_string).as(:value)).as(:param) } + rule(:comma) { bws >> str(',') >> bws } + # Old versions of node-http-signature add an incorrect "Signature " prefix to the header + rule(:buggy_prefix) { str('Signature ') } + rule(:params) { buggy_prefix.maybe >> (param >> (comma >> param).repeat).as(:params) } + root(:params) + end + + class SignatureParamsTransformer < Parslet::Transform + rule(params: subtree(:param)) do + (param.is_a?(Array) ? param : [param]).each_with_object({}) { |(key, value), hash| hash[key] = value } + end + + rule(param: { key: simple(:key), value: simple(:val) }) do + [key, val] + end + + rule(quoted_string: simple(:string)) do + string.to_s + end + + rule(token: simple(:string)) do + string.to_s + end + end + + def self.parse(raw_signature) + tree = SignatureParamsParser.new.parse(raw_signature) + SignatureParamsTransformer.new.apply(tree) + rescue Parslet::ParseFailed + raise ParsingError + end +end diff --git a/spec/lib/signature_parser_spec.rb b/spec/lib/signature_parser_spec.rb new file mode 100644 index 0000000000..183b486d56 --- /dev/null +++ b/spec/lib/signature_parser_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe SignatureParser do + describe '.parse' do + subject { described_class.parse(header) } + + context 'with Signature headers conforming to draft-cavage-http-signatures-12' do + let(:header) do + # This example signature string deliberately mixes uneven spacing + # and quoting styles to ensure everything is covered + 'keyId = "https://remote.domain/users/bob#main-key",algorithm= rsa-sha256 , headers="host date digest (request-target)",signature="gmhMjgMROGElJU3fpehV2acD5kMHeELi8EFP2UPHOdQ54H0r55AxIpji+J3lPe+N2qSb/4H1KXIh6f0lRu8TGSsu12OQmg5hiO8VA9flcA/mh9Lpk+qwlQZIPRqKP9xUEfqD+Z7ti5wPzDKrWAUK/7FIqWgcT/mlqB1R1MGkpMFc/q4CIs2OSNiWgA4K+Kp21oQxzC2kUuYob04gAZ7cyE/FTia5t08uv6lVYFdRsn4XNPn1MsHgFBwBMRG79ng3SyhoG4PrqBEi5q2IdLq3zfre/M6He3wlCpyO2VJNdGVoTIzeZ0Zz8jUscPV3XtWUchpGclLGSaKaq/JyNZeiYQ=="' # rubocop:disable Layout/LineLength + end + + it 'correctly parses the header' do + expect(subject).to eq({ + 'keyId' => 'https://remote.domain/users/bob#main-key', + 'algorithm' => 'rsa-sha256', + 'headers' => 'host date digest (request-target)', + 'signature' => 'gmhMjgMROGElJU3fpehV2acD5kMHeELi8EFP2UPHOdQ54H0r55AxIpji+J3lPe+N2qSb/4H1KXIh6f0lRu8TGSsu12OQmg5hiO8VA9flcA/mh9Lpk+qwlQZIPRqKP9xUEfqD+Z7ti5wPzDKrWAUK/7FIqWgcT/mlqB1R1MGkpMFc/q4CIs2OSNiWgA4K+Kp21oQxzC2kUuYob04gAZ7cyE/FTia5t08uv6lVYFdRsn4XNPn1MsHgFBwBMRG79ng3SyhoG4PrqBEi5q2IdLq3zfre/M6He3wlCpyO2VJNdGVoTIzeZ0Zz8jUscPV3XtWUchpGclLGSaKaq/JyNZeiYQ==', # rubocop:disable Layout/LineLength + }) + end + end + + context 'with a malformed Signature header' do + let(:header) { 'hello this is malformed!' } + + it 'raises an error' do + expect { subject }.to raise_error(SignatureParser::ParsingError) + end + end + end +end From b2133fee5f365a5be370a08ff61187b5c40c9266 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 7 Feb 2024 08:37:10 -0500 Subject: [PATCH 07/63] Update artifact preservation to use `save_path` value (#29035) --- .github/workflows/test-ruby.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 4275f59420..7fd259ae01 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -224,7 +224,7 @@ jobs: if: failure() with: name: e2e-screenshots - path: tmp/screenshots/ + path: tmp/capybara/ test-search: name: Elastic Search integration testing @@ -328,4 +328,4 @@ jobs: if: failure() with: name: test-search-screenshots - path: tmp/screenshots/ + path: tmp/capybara/ From dbafec88e5abdd1692007450d3f35fc9488afd7b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:10:38 +0100 Subject: [PATCH 08/63] Update dependency @reduxjs/toolkit to v2.1.0 (#28879) 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 75b4c355af..7bfb524907 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2612,11 +2612,11 @@ __metadata: linkType: hard "@reduxjs/toolkit@npm:^2.0.1": - version: 2.0.1 - resolution: "@reduxjs/toolkit@npm:2.0.1" + version: 2.1.0 + resolution: "@reduxjs/toolkit@npm:2.1.0" dependencies: immer: "npm:^10.0.3" - redux: "npm:^5.0.0" + redux: "npm:^5.0.1" redux-thunk: "npm:^3.1.0" reselect: "npm:^5.0.1" peerDependencies: @@ -2627,7 +2627,7 @@ __metadata: optional: true react-redux: optional: true - checksum: 161b9b8e11d9688890ab97b604a4c10c0d41b1369425a5fa821586932db4cd5a391d15799732b3612e6120a6336458ff577ff254219315c05ecd68da5d15fd79 + checksum: 4ea9e9ea8cc2cab1c997127dc332c165cebc55bf8e95812ba4dc40d48dd87d5ee4bf3316b9eab49b5cce056eda6bdcb4b2a7dc3a15f056f64f76134f148f9f10 languageName: node linkType: hard @@ -14068,7 +14068,7 @@ __metadata: languageName: node linkType: hard -"redux@npm:^5.0.0": +"redux@npm:^5.0.1": version: 5.0.1 resolution: "redux@npm:5.0.1" checksum: b10c28357194f38e7d53b760ed5e64faa317cc63de1fb95bc5d9e127fab956392344368c357b8e7a9bedb0c35b111e7efa522210cfdc3b3c75e5074718e9069c From 95da28d201b9a9536331abe1fce6e7e571f3ff4a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 7 Feb 2024 09:53:29 -0500 Subject: [PATCH 09/63] Add common `ThreadingHelper` module for specs (#29116) --- spec/lib/request_pool_spec.rb | 14 ++++----- spec/models/account_spec.rb | 13 ++------ spec/models/concerns/account/counters_spec.rb | 30 +++++-------------- spec/rails_helper.rb | 1 + spec/services/resolve_account_service_spec.rb | 22 +++++--------- spec/support/threading_helpers.rb | 17 +++++++++++ 6 files changed, 40 insertions(+), 57 deletions(-) create mode 100644 spec/support/threading_helpers.rb diff --git a/spec/lib/request_pool_spec.rb b/spec/lib/request_pool_spec.rb index a31d078327..a82eb5a188 100644 --- a/spec/lib/request_pool_spec.rb +++ b/spec/lib/request_pool_spec.rb @@ -33,18 +33,14 @@ describe RequestPool do subject - threads = Array.new(5) do - Thread.new do - subject.with('http://example.com') do |http_client| - http_client.get('/').flush - # Nudge scheduler to yield and exercise the full pool - sleep(0.01) - end + multi_threaded_execution(5) do + subject.with('http://example.com') do |http_client| + http_client.get('/').flush + # Nudge scheduler to yield and exercise the full pool + sleep(0.01) end end - threads.map(&:join) - expect(subject.size).to be > 1 end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 7ef5ca94cc..b1dca52dc5 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -1035,19 +1035,10 @@ RSpec.describe Account do it 'increments the count in multi-threaded an environment when account_stat is not yet initialized' do subject - increment_by = 15 - wait_for_start = true - - threads = Array.new(increment_by) do - Thread.new do - true while wait_for_start - described_class.find(subject.id).increment_count!(:followers_count) - end + multi_threaded_execution(15) do + described_class.find(subject.id).increment_count!(:followers_count) end - wait_for_start = false - threads.each(&:join) - expect(subject.reload.followers_count).to eq 15 end end diff --git a/spec/models/concerns/account/counters_spec.rb b/spec/models/concerns/account/counters_spec.rb index 2e1cd700bc..3c063a2fa2 100644 --- a/spec/models/concerns/account/counters_spec.rb +++ b/spec/models/concerns/account/counters_spec.rb @@ -6,6 +6,8 @@ describe Account::Counters do let!(:account) { Fabricate(:account) } describe '#increment_count!' do + let(:increment_by) { 15 } + it 'increments the count' do expect(account.followers_count).to eq 0 account.increment_count!(:followers_count) @@ -13,24 +15,17 @@ describe Account::Counters do end it 'increments the count in multi-threaded an environment' do - increment_by = 15 - wait_for_start = true - - threads = Array.new(increment_by) do - Thread.new do - true while wait_for_start - account.increment_count!(:statuses_count) - end + multi_threaded_execution(increment_by) do + account.increment_count!(:statuses_count) end - wait_for_start = false - threads.each(&:join) - expect(account.statuses_count).to eq increment_by end end describe '#decrement_count!' do + let(:decrement_by) { 10 } + it 'decrements the count' do account.followers_count = 15 account.save! @@ -40,22 +35,13 @@ describe Account::Counters do end it 'decrements the count in multi-threaded an environment' do - decrement_by = 10 - wait_for_start = true - account.statuses_count = 15 account.save! - threads = Array.new(decrement_by) do - Thread.new do - true while wait_for_start - account.decrement_count!(:statuses_count) - end + multi_threaded_execution(decrement_by) do + account.decrement_count!(:statuses_count) end - wait_for_start = false - threads.each(&:join) - expect(account.statuses_count).to eq 5 end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 5125339096..cde5a439db 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -86,6 +86,7 @@ RSpec.configure do |config| config.include ActiveSupport::Testing::TimeHelpers config.include Chewy::Rspec::Helpers config.include Redisable + config.include ThreadingHelpers config.include SignedRequestHelpers, type: :request config.include CommandLineHelpers, type: :cli diff --git a/spec/services/resolve_account_service_spec.rb b/spec/services/resolve_account_service_spec.rb index 1c4c3b4016..b82e5b3865 100644 --- a/spec/services/resolve_account_service_spec.rb +++ b/spec/services/resolve_account_service_spec.rb @@ -219,27 +219,19 @@ RSpec.describe ResolveAccountService, type: :service do end it 'processes one remote account at a time using locks' do - wait_for_start = true fail_occurred = false return_values = Concurrent::Array.new - threads = Array.new(5) do - Thread.new do - true while wait_for_start - - begin - return_values << described_class.new.call('foo@ap.example.com') - rescue ActiveRecord::RecordNotUnique - fail_occurred = true - ensure - RedisConfiguration.pool.checkin if Thread.current[:redis] - end + multi_threaded_execution(5) do + begin + return_values << described_class.new.call('foo@ap.example.com') + rescue ActiveRecord::RecordNotUnique + fail_occurred = true + ensure + RedisConfiguration.pool.checkin if Thread.current[:redis] end end - wait_for_start = false - threads.each(&:join) - expect(fail_occurred).to be false expect(return_values).to_not include(nil) end diff --git a/spec/support/threading_helpers.rb b/spec/support/threading_helpers.rb new file mode 100644 index 0000000000..edf45822ca --- /dev/null +++ b/spec/support/threading_helpers.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module ThreadingHelpers + def multi_threaded_execution(thread_count) + wait_for_start = true + + threads = Array.new(thread_count) do + Thread.new do + true while wait_for_start + yield + end + end + + wait_for_start = false + threads.each(&:join) + end +end From 79b4b94f3a3ec0ee7d81acf152e66b802e250b39 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 7 Feb 2024 09:54:40 -0500 Subject: [PATCH 10/63] Configure `CountAsOne` value for `RSpec/ExampleLength` cop (#29115) --- .rubocop.yml | 5 +++++ .rubocop_todo.yml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.rubocop.yml b/.rubocop.yml index 330c40de1b..a8310489ea 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -134,6 +134,11 @@ Rails/UnusedIgnoredColumns: Rails/NegateInclude: Enabled: false +# Reason: Enforce default limit, but allow some elements to span lines +# https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecexamplelength +RSpec/ExampleLength: + CountAsOne: ['array', 'heredoc', 'method_call'] + # Reason: Deprecated cop, will be removed in 3.0, replaced by SpecFilePathFormat # https://docs.rubocop.org/rubocop-rspec/cops_rspec.html#rspecfilepath RSpec/FilePath: diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 09e9fd73d8..11ac570836 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -36,7 +36,7 @@ Metrics/PerceivedComplexity: # Configuration parameters: CountAsOne. RSpec/ExampleLength: - Max: 22 + Max: 20 # Override default of 5 RSpec/MultipleExpectations: Max: 7 From eff447a4554e5285f5869432e1ea9e1ca884a806 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 7 Feb 2024 18:24:42 +0100 Subject: [PATCH 11/63] Rewrite signature verification using regexps and `StringScanner` (#29133) --- app/lib/signature_parser.rb | 57 ++++++++++++------------------- spec/lib/signature_parser_spec.rb | 4 +-- 2 files changed, 24 insertions(+), 37 deletions(-) diff --git a/app/lib/signature_parser.rb b/app/lib/signature_parser.rb index c09ab0c841..7a75080d98 100644 --- a/app/lib/signature_parser.rb +++ b/app/lib/signature_parser.rb @@ -11,43 +11,30 @@ class SignatureParser # In addition, ignore a `Signature ` string prefix that was added by old versions # of `node-http-signatures` - class SignatureParamsParser < Parslet::Parser - rule(:token) { match("[0-9a-zA-Z!#$%&'*+.^_`|~-]").repeat(1).as(:token) } - rule(:quoted_string) { str('"') >> (qdtext | quoted_pair).repeat.as(:quoted_string) >> str('"') } - # qdtext and quoted_pair are not exactly according to spec but meh - rule(:qdtext) { match('[^\\\\"]') } - rule(:quoted_pair) { str('\\') >> any } - rule(:bws) { match('\s').repeat } - rule(:param) { (token.as(:key) >> bws >> str('=') >> bws >> (token | quoted_string).as(:value)).as(:param) } - rule(:comma) { bws >> str(',') >> bws } - # Old versions of node-http-signature add an incorrect "Signature " prefix to the header - rule(:buggy_prefix) { str('Signature ') } - rule(:params) { buggy_prefix.maybe >> (param >> (comma >> param).repeat).as(:params) } - root(:params) - end - - class SignatureParamsTransformer < Parslet::Transform - rule(params: subtree(:param)) do - (param.is_a?(Array) ? param : [param]).each_with_object({}) { |(key, value), hash| hash[key] = value } - end - - rule(param: { key: simple(:key), value: simple(:val) }) do - [key, val] - end - - rule(quoted_string: simple(:string)) do - string.to_s - end - - rule(token: simple(:string)) do - string.to_s - end - end + TOKEN_RE = /[0-9a-zA-Z!#$%&'*+.^_`|~-]+/ + # qdtext and quoted_pair are not exactly according to spec but meh + QUOTED_STRING_RE = /"([^\\"]|(\\.))*"/ + PARAM_RE = /(?#{TOKEN_RE})\s*=\s*((?#{TOKEN_RE})|(?#{QUOTED_STRING_RE}))/ def self.parse(raw_signature) - tree = SignatureParamsParser.new.parse(raw_signature) - SignatureParamsTransformer.new.apply(tree) - rescue Parslet::ParseFailed + # Old versions of node-http-signature add an incorrect "Signature " prefix to the header + raw_signature = raw_signature.delete_prefix('Signature ') + + params = {} + scanner = StringScanner.new(raw_signature) + + # Use `skip` instead of `scan` as we only care about the subgroups + while scanner.skip(PARAM_RE) + # This is not actually correct with regards to quoted pairs, but it's consistent + # with our previous implementation, and good enough in practice. + params[scanner[:key]] = scanner[:value] || scanner[:quoted_value][1...-1] + + scanner.skip(/\s*/) + return params if scanner.eos? + + raise ParsingError unless scanner.skip(/\s*,\s*/) + end + raise ParsingError end end diff --git a/spec/lib/signature_parser_spec.rb b/spec/lib/signature_parser_spec.rb index 183b486d56..08e9bea66c 100644 --- a/spec/lib/signature_parser_spec.rb +++ b/spec/lib/signature_parser_spec.rb @@ -10,12 +10,12 @@ RSpec.describe SignatureParser do let(:header) do # This example signature string deliberately mixes uneven spacing # and quoting styles to ensure everything is covered - 'keyId = "https://remote.domain/users/bob#main-key",algorithm= rsa-sha256 , headers="host date digest (request-target)",signature="gmhMjgMROGElJU3fpehV2acD5kMHeELi8EFP2UPHOdQ54H0r55AxIpji+J3lPe+N2qSb/4H1KXIh6f0lRu8TGSsu12OQmg5hiO8VA9flcA/mh9Lpk+qwlQZIPRqKP9xUEfqD+Z7ti5wPzDKrWAUK/7FIqWgcT/mlqB1R1MGkpMFc/q4CIs2OSNiWgA4K+Kp21oQxzC2kUuYob04gAZ7cyE/FTia5t08uv6lVYFdRsn4XNPn1MsHgFBwBMRG79ng3SyhoG4PrqBEi5q2IdLq3zfre/M6He3wlCpyO2VJNdGVoTIzeZ0Zz8jUscPV3XtWUchpGclLGSaKaq/JyNZeiYQ=="' # rubocop:disable Layout/LineLength + 'keyId = "https://remote.domain/users/bob#main-key,",algorithm= rsa-sha256 , headers="host date digest (request-target)",signature="gmhMjgMROGElJU3fpehV2acD5kMHeELi8EFP2UPHOdQ54H0r55AxIpji+J3lPe+N2qSb/4H1KXIh6f0lRu8TGSsu12OQmg5hiO8VA9flcA/mh9Lpk+qwlQZIPRqKP9xUEfqD+Z7ti5wPzDKrWAUK/7FIqWgcT/mlqB1R1MGkpMFc/q4CIs2OSNiWgA4K+Kp21oQxzC2kUuYob04gAZ7cyE/FTia5t08uv6lVYFdRsn4XNPn1MsHgFBwBMRG79ng3SyhoG4PrqBEi5q2IdLq3zfre/M6He3wlCpyO2VJNdGVoTIzeZ0Zz8jUscPV3XtWUchpGclLGSaKaq/JyNZeiYQ=="' # rubocop:disable Layout/LineLength end it 'correctly parses the header' do expect(subject).to eq({ - 'keyId' => 'https://remote.domain/users/bob#main-key', + 'keyId' => 'https://remote.domain/users/bob#main-key,', 'algorithm' => 'rsa-sha256', 'headers' => 'host date digest (request-target)', 'signature' => 'gmhMjgMROGElJU3fpehV2acD5kMHeELi8EFP2UPHOdQ54H0r55AxIpji+J3lPe+N2qSb/4H1KXIh6f0lRu8TGSsu12OQmg5hiO8VA9flcA/mh9Lpk+qwlQZIPRqKP9xUEfqD+Z7ti5wPzDKrWAUK/7FIqWgcT/mlqB1R1MGkpMFc/q4CIs2OSNiWgA4K+Kp21oQxzC2kUuYob04gAZ7cyE/FTia5t08uv6lVYFdRsn4XNPn1MsHgFBwBMRG79ng3SyhoG4PrqBEi5q2IdLq3zfre/M6He3wlCpyO2VJNdGVoTIzeZ0Zz8jUscPV3XtWUchpGclLGSaKaq/JyNZeiYQ==', # rubocop:disable Layout/LineLength From 2a362d62a81a5ec54f15cced02e1d197636d1773 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 Feb 2024 10:43:02 +0100 Subject: [PATCH 12/63] New Crowdin Translations (automated) (#29145) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/sk.json | 5 ++ app/javascript/mastodon/locales/tok.json | 73 ++++++++++++++++++++++-- config/locales/devise.lad.yml | 22 +++---- config/locales/lad.yml | 4 +- config/locales/simple_form.tok.yml | 3 + config/locales/sk.yml | 5 ++ 6 files changed, 95 insertions(+), 17 deletions(-) diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index b91c45bb29..7a05eb4f7e 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -277,6 +277,7 @@ "follow_request.authorize": "Povoľ prístup", "follow_request.reject": "Odmietni", "follow_requests.unlocked_explanation": "Síce Váš učet nie je uzamknutý, ale {domain} tím si myslel že môžete chcieť skontrolovať žiadosti o sledovanie z týchto účtov manuálne.", + "follow_suggestions.curated_suggestion": "Výber zo servera", "follow_suggestions.dismiss": "Znovu nezobrazuj", "follow_suggestions.personalized_suggestion": "Prispôsobené odporúčania", "follow_suggestions.view_all": "Zobraz všetky", @@ -521,8 +522,12 @@ "poll_button.add_poll": "Pridaj anketu", "poll_button.remove_poll": "Odstráň anketu", "privacy.change": "Uprav súkromie príspevku", + "privacy.direct.short": "Konkrétni ľudia", + "privacy.private.long": "Iba tvoji nasledovatelia", "privacy.private.short": "Sledovatelia", + "privacy.public.long": "Ktokoľvek na, aj mimo Mastodonu", "privacy.public.short": "Verejné", + "privacy.unlisted.short": "Verejný v tichosti", "privacy_policy.last_updated": "Posledná úprava {date}", "privacy_policy.title": "Zásady súkromia", "recommended": "Odporúčané", diff --git a/app/javascript/mastodon/locales/tok.json b/app/javascript/mastodon/locales/tok.json index a0227969dd..1c84356238 100644 --- a/app/javascript/mastodon/locales/tok.json +++ b/app/javascript/mastodon/locales/tok.json @@ -1,9 +1,11 @@ { + "about.blocks": "ma lawa", "about.contact": "toki:", "about.domain_blocks.no_reason_available": "mi sona ala e tan", "about.not_available": "lon kulupu ni la sina ken alasa ala e sona ni.", "about.rules": "lawa kulupu", "account.account_note_header": "sona awen", + "account.badges.group": "kulupu", "account.block": "o weka e @{name}", "account.block_domain": "o weka e ma {domain}", "account.block_short": "o weka e jan", @@ -29,6 +31,7 @@ "account.hide_reblogs": "o lukin ala e pana toki tan @{name}", "account.languages": "sina wile lukin e sitelen pi toki seme", "account.locked_info": "sina wile kute e jan ni la ona o toki e ken", + "account.media": "sitelen", "account.mention": "o toki e jan @{name}", "account.moved_to": "lipu jan sin pi jan {name} li ni:", "account.mute": "o kute ala e @{name}", @@ -36,17 +39,25 @@ "account.mute_short": "o kute ala", "account.muted": "sina kute ala e jan ni", "account.no_bio": "lipu li weka", + "account.open_original_page": "o open e lipu open", "account.posts": "toki suli", "account.posts_with_replies": "toki ale", "account.report": "jan @{name} la o toki e lawa", "account.requested": "jan ni o ken e kute sina. sina pini wile kute la o luka e ni", "account.requested_follow": "{name} li wile kute e sina", + "account.share": "o pana e lipu jan @{name}", "account.show_reblogs": "o lukin e pana toki tan @{name}", + "account.unblock": "o weka ala e jan {name}", + "account.unblock_domain": "o weka ala e ma {domain}", "account.unblock_short": "o pini weka", "account.unfollow": "o pini kute", - "account.unmute": "o ken lukin e sitelen tan @{name}", + "account.unmute": "o kute e @{name}", "account.unmute_notifications_short": "o kute e mu tan jan ni", "account.unmute_short": "o ken kute e jan ni", + "admin.dashboard.retention.average": "sama", + "admin.dashboard.retention.cohort": "tenpo mun open", + "admin.dashboard.retention.cohort_size": "jan sin", + "alert.rate_limited.message": "tenpo {retry_time, time, medium} la o pali awen", "alert.unexpected.message": "pakala li lon", "alert.unexpected.title": "pakala", "announcement.announcement": "toki suli", @@ -56,14 +67,21 @@ "bundle_column_error.retry": "o ni sin", "bundle_column_error.routing.body": "ilo li sona ala e lipu wile. sina pana ala pana e nasin pona tawa lipu?", "bundle_column_error.routing.title": "pakala nanpa 404", + "bundle_modal_error.close": "o pini", "bundle_modal_error.message": "ilo li wile kama e ijo ni, taso pakala li lon.", "bundle_modal_error.retry": "o ni sin", + "closed_registrations_modal.find_another_server": "o alasa e ma ante", + "column.blocks": "kulupu pi jan weka", + "column.lists": "lipu pi lipu mute", "column.mutes": "sina wile ala kute e jan ni", + "community.column_settings.local_only": "toki lon ni taso", + "community.column_settings.media_only": "sitelen taso", "compose.language.change": "o ante e nasin toki", "compose.language.search": "o alasa e nasin toki...", + "compose.published.open": "o lukin", "compose.saved.body": "ilo li awen e ijo pana sina.", "compose_form.direct_message_warning_learn_more": "o kama sona e ijo ante", - "compose_form.placeholder": "o toki", + "compose_form.placeholder": "sina toki insa e seme", "compose_form.poll.option_placeholder": "ken nanpa {number}", "compose_form.poll.switch_to_multiple": "o ante e nasin pana. pana mute o ken", "compose_form.poll.switch_to_single": "o ante e nasin pana. pana wan taso o lon", @@ -72,6 +90,8 @@ "compose_form.reply": "o toki lon ijo ni", "compose_form.save_changes": "o sin e ni", "compose_form.spoiler.marked": "o weka e toki pi ijo ike ken", + "confirmations.block.confirm": "o weka.", + "confirmations.block.message": "sina o wile ala wile weka e jan {name}?", "confirmations.cancel_follow_request.confirm": "o weka e wile sina", "confirmations.cancel_follow_request.message": "sina awen ala awen wile weka e wile kute sina lon {name}?", "confirmations.delete.confirm": "o pakala", @@ -79,12 +99,16 @@ "confirmations.delete_list.confirm": "o pakala", "confirmations.delete_list.message": "sina wile ala wile pakala e lipu ni", "confirmations.discard_edit_media.confirm": "o weka", + "confirmations.domain_block.confirm": "o weka.", "confirmations.edit.confirm": "o ante", "confirmations.logout.confirm": "o weka", "confirmations.logout.message": "sina wile ala wile weka", "confirmations.mute.confirm": "sina wile ala kute e jan ni", "confirmations.mute.message": "sina awen ala awen wile kute ala e {name}?", "confirmations.redraft.confirm": "o pakala o pali sin e toki", + "confirmations.unfollow.confirm": "o pini kute", + "confirmations.unfollow.message": "sina o wile ala wile pini kute e jan {name}?", + "conversation.delete": "o weka e toki ni", "conversation.mark_as_read": "ni o sin ala", "conversation.open": "o lukin e toki", "conversation.with": "lon {names}", @@ -102,6 +126,7 @@ "emoji_button.symbols": "sitelen", "emoji_button.travel": "ma en tawa", "empty_column.account_timeline": "toki ala li lon!", + "empty_column.account_unavailable": "ken ala lukin e lipu jan", "empty_column.followed_tags": "sina alasa ala e toki ꞏ sina alasa e toki la toki li lon ni", "empty_column.hashtag": "ala li lon toki ni", "empty_column.mutes": "jan ala la sina wile ala kute.", @@ -110,36 +135,73 @@ "explore.title": "o alasa", "explore.trending_links": "sin", "explore.trending_statuses": "toki", + "filter_modal.select_filter.expired": "tenpo pini", "filter_modal.select_filter.search": "o alasa anu pali", "firehose.all": "ale", "firehose.local": "ilo ni", "firehose.remote": "ilo ante", + "follow_request.authorize": "o sina kama", + "follow_request.reject": "o weka", "follow_suggestions.view_all": "o lukin e ale", "footer.privacy_policy": "lawa len", "footer.source_code": "o lukin e toki ilo", "footer.status": "lon", + "hashtag.column_header.tag_mode.all": "en {additional}", + "hashtag.column_header.tag_mode.any": "anu {additional}", "hashtag.column_settings.tag_mode.all": "ale ni", "hashtag.column_settings.tag_mode.any": "wan ni", "hashtag.column_settings.tag_mode.none": "ala ni", "home.pending_critical_update.link": "o lukin e ijo ilo sin", + "interaction_modal.on_another_server": "lon ma ante", + "interaction_modal.on_this_server": "lon ma ni", "interaction_modal.title.follow": "o kute e {name}", "keyboard_shortcuts.muted": "sina wile ala kute e jan la o lukin e ona ale", + "keyboard_shortcuts.open_media": "o open e sitelen", + "keyboard_shortcuts.toggle_sensitivity": "sitelen la o len anu lukin", + "lightbox.close": "o pini", + "link_preview.author": "{name} li pali e ni", "lists.edit.submit": "o ante e nimi", - "mute_modal.duration": "tenpo seme", + "lists.replies_policy.none": "jan ala", + "mute_modal.duration": "tenpo", "mute_modal.indefinite": "tenpo ale", "navigation_bar.filters": "sina wile ala kute e nimi ni", "navigation_bar.mutes": "sina wile ala kute e jan ni", + "notification.follow": "jan {name} li kama kute e sina", + "notification.follow_request": "{name} li wile kute e sina", + "notification.mention": "jan {name} li toki e sina", + "notifications.column_settings.follow": "jan kute sin", + "notifications.filter.all": "ale", + "onboarding.start.title": "sina o kama pona a!", + "privacy.public.short": "jan ale", + "relative_time.full.just_now": "tenpo ni", + "relative_time.just_now": "tenpo ni", + "relative_time.today": "tenpo suno ni", + "report.block": "o weka e jan", "report.block_explanation": "sina kama lukin ala e toki ona. ona li kama ala ken lukin e toki sina li kama ala ken kute e sina. ona li ken sona e kama ni.", "report.category.title": "ike seme li lon {type} ni", + "report.close": "o pini", "report.mute": "o kute ala e ona", "report.mute_explanation": "sina kama ala lukin e ijo pana ona. ona li awen ken kute e sina li awen ken lukin e sina li sona ala e weka kute sina e weka lukin sina.", + "report.reasons.dislike": "ni li ike tawa mi", + "report.thanks.title": "sina wile ala lukin e ni anu seme?", + "search.placeholder": "o alasa", + "search.quick_action.go_to_account": "o tawa lipu jan {x}", "search_popout.language_code": "nimi toki kepeken nasin ISO", + "search_results.all": "ale", + "search_results.see_all": "ale", + "search_results.statuses": "toki", + "search_results.title": "o alasa e {q}", + "status.block": "o weka e @{name}", + "status.delete": "o weka", "status.edit": "o ante", "status.edited": "ni li ante lon {date}", "status.embed": "ni o lon insa pi lipu ante", "status.history.created": "{name} li pali e ni lon {date}", "status.history.edited": "{name} li ante lon {date}", "status.load_more": "o kama e ijo ante", + "status.media.open": "o open", + "status.media.show": "o lukin", + "status.media_hidden": "sitelen li len", "status.mute": "o kute ala e @{name}", "status.mute_conversation": "o kute ala e ijo pi toki ni", "status.show_less": "o lili e ni", @@ -147,6 +209,7 @@ "status.show_more": "o suli e ni", "status.show_more_all": "o suli e ale", "status.show_original": "ijo mama pi ijo ni li seme", + "status.uncached_media_warning": "lukin lili li weka", "status.unmute_conversation": "o ken kute e ijo pi toki ni", "timeline_hint.resources.statuses": "ijo pi tenpo suli", "units.short.million": "{count}AAA", @@ -155,12 +218,14 @@ "upload_form.description": "o toki e ijo lukin tawa jan pi lukin ala, tawa jan pi lukin lili", "upload_form.edit": "o ante", "upload_form.video_description": "o toki e ijo kute tawa jan pi kute ala, tawa jan pi kute lili, e ijo lukin tawa jan pi lukin ala, tawa jan pi lukin lili", - "upload_modal.choose_image": "sitelen seme", + "upload_modal.choose_image": "o wile e sitelen", "upload_modal.description_placeholder": "mi pu jaki tan soweli", "upload_modal.detect_text": "ilo o alasa e nimi tan sitelen", + "upload_modal.edit_media": "o ante e sitelen", "upload_modal.preparing_ocr": "ilo li open e alasa nimi lon sitelen…", "upload_progress.label": "ilo li kama jo e ijo sina...", "upload_progress.processing": "ilo li pali…", + "username.taken": "jan ante li jo e nimi ni. sina o pali e nimi sin.", "video.mute": "o kalama ala", "video.pause": "o lape e ni", "video.unmute": "o kalama" diff --git a/config/locales/devise.lad.yml b/config/locales/devise.lad.yml index 88099f48c4..d2ce53760c 100644 --- a/config/locales/devise.lad.yml +++ b/config/locales/devise.lad.yml @@ -89,25 +89,25 @@ lad: no_token: No puedes akseder a esta pajina si no vienes dizde una posta elektronika de restablesimyento de kod. Si vienes dizde una posta elektronika de restablesimyento de kod, por favor asigurate de utilizar el URL kompleto embiado. send_instructions: Si tu adreso de posta elektronika existe en muestra baza de datos, risiviras un atadijo de rekuperasyon de kod en tu adreso de posta elektronika en pokos minutos. Por favor, komprova tu kuti de posta spam si no risives akeya posta elektronika. send_paranoid_instructions: Si tu adreso de posta elektronika existe en muestra baza de datos, risiviras un atadijo de rekuperasyon de kod en tu adreso de posta elektronika en pokos minutos. Por favor, komprova tu kuti de posta no deseado si no risives akeya posta elektronika. - updated: Tu kod a sido trokado kon reusho. Tyenes entrado en kuento. - updated_not_active: Tu kod se tiene trokado kon reusho. + updated: Tu kod a sido trokado kon reushita. Tyenes entrado en kuento. + updated_not_active: Tu kod se tiene trokado kon reushita. registrations: - destroyed: Tu kuento a sido efasado kon reusho. Asperamos verte de muevo pronto. + destroyed: Tu kuento a sido efasado kon reushita. Asperamos verte de muevo pronto. signed_up: Bienvenido! Te tienes enrejistrado djustamente. - signed_up_but_inactive: Te tienes enrejistrado kon reusho. Entanto, no se pudio inisyar sesyon porke tu kuento ainda no esta aktivado. - signed_up_but_locked: Te tienes enrejistrado kon reusho. Entanto, no pudites konektarte kon tu kuento porke tu kuento esta blokado. + signed_up_but_inactive: Te tienes enrejistrado kon reushita. Entanto, no se pudio inisyar sesyon porke tu kuento ainda no esta aktivado. + signed_up_but_locked: Te tienes enrejistrado kon reushita. Entanto, no pudites konektarte kon tu kuento porke tu kuento esta blokado. signed_up_but_pending: Un mesaj kon un atadijo de konfirmasyon a sido enviado a tu adreso de posta elektronika. Dempues de klikar en el atadijo, revizaremos tu solisitud. Seras avizado si se acheta. signed_up_but_unconfirmed: Un mesaj kon un atadijo de konfirmasyon a sido enviado a tu adreso de posta elektronika. Por favor, sigue el atadijo para aktivar tu kuento. Por favor, komprova tu kuti de posta spam si no risives akeya posta elektronika. - update_needs_confirmation: Tienes aktualizado tu kuento kon reusho, pero kale verifikar tu muevo adreso de posta elektronika. Por favor, komprova tu posta elektronika i sige el atadijo de konfirmasyon para konfirmar tu muevo adreso de posta elektronika. Por favor, komprova tu kuti de posta spam si no risives akeya posta elektronika. - updated: Tu kuento se aktualizo kon reusho. + update_needs_confirmation: Tienes aktualizado tu kuento kon reushita, pero kale verifikar tu muevo adreso de posta elektronika. Por favor, komprova tu posta elektronika i sige el atadijo de konfirmasyon para konfirmar tu muevo adreso de posta elektronika. Por favor, komprova tu kuti de posta spam si no risives akeya posta elektronika. + updated: Tu kuento se aktualizo kon reushita. sessions: - already_signed_out: Salites del kuento kon reusho. - signed_in: Konektates kon tu kuento kon reusho. - signed_out: Salites del kuento kon reusho. + already_signed_out: Salites del kuento kon reushita. + signed_in: Konektates kon tu kuento kon reushita. + signed_out: Salites del kuento kon reushita. unlocks: send_instructions: En unos minutos risiviras una posta elektronika kon instruksyones para dezblokar tu kuento. Por favor, komprova tu kuti de posta spam si no risives akeya posta elektronika. send_paranoid_instructions: Si tu kuento existe, en unos minutos risiviras una posta elektronika kon instruksyones para dezblokarlo. Por favor, reviza tu kuti de posta spam si no risives akeya posta elektronika. - unlocked: Tu kuento fue dezblokado kon reusho. Por favor, konektate kon tu kuento para kontinuar. + unlocked: Tu kuento fue dezblokado kon reushita. Por favor, konektate kon tu kuento para kontinuar. errors: messages: already_confirmed: ya estaba konfirmado, por favor aprova konektarte kon tu kuento diff --git a/config/locales/lad.yml b/config/locales/lad.yml index d4f772095e..77501e3b32 100644 --- a/config/locales/lad.yml +++ b/config/locales/lad.yml @@ -1146,7 +1146,7 @@ lad: confirm_password: Eskrive tu kod aktual para demostrar tu identita confirm_username: Eskrive tu nombre de utilizador para konfirmar proceed: Efasa kuento - success_msg: Tu kuento fue efasado kon reusho + success_msg: Tu kuento fue efasado kon reushita warning: before: 'Antes de kontinuar, por favor melda kon atensyon las sigientes notas:' caches: El kontenido ke tiene sido magazinado en kashe por otros sirvidores puede persistir @@ -1283,7 +1283,7 @@ lad: one: "%{count} elemento ke koenside con tu bushkeda esta eskojido." other: Todos los %{count} elementos ke koensiden con tu bushkeda estan eskojidos. cancel: Anula - changes_saved_msg: Trokamientos guadrados kon reusho! + changes_saved_msg: Trokamientos guadrados kon reushita! confirm: Konfirma copy: Kopia delete: Efasa diff --git a/config/locales/simple_form.tok.yml b/config/locales/simple_form.tok.yml index 9c60144bb5..1eb7d5be87 100644 --- a/config/locales/simple_form.tok.yml +++ b/config/locales/simple_form.tok.yml @@ -4,6 +4,9 @@ tok: hints: account: display_name: nimi sina ale anu nimi sina musi. + defaults: + setting_display_media_hide_all: tenpo ale la, o weka e sitelen + setting_display_media_show_all: tenpo ale la, o awen e sitelen labels: defaults: expires_in: ona o moli lon diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 5ffbf45bde..f13a15d795 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -260,6 +260,11 @@ sk: suspend_account_html: "%{name} zablokoval/a účet používateľa %{target}" unassigned_report_html: "%{name} odobral/a report od %{target}" unsuspend_account_html: "%{name} spojazdnil/a účet %{target}" + update_announcement_html: "%{name} aktualizoval/a oboznámenie %{target}" + update_custom_emoji_html: "%{name} aktualizoval/a emotikonu %{target}" + update_domain_block_html: "%{name} aktualizoval/a blokovanie domény pre %{target}" + update_ip_block_html: "%{name} zmenil/a pravidlo pre IP %{target}" + update_status_html: "%{name} aktualizoval/a príspevok od %{target}" update_user_role_html: "%{name} zmenil/a rolu pre %{target}" deleted_account: zmazaný účet empty: Žiadne záznamy nenájdené. From 52986f35b87d97b71e99536b01f41f7a77ca5ec6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 Feb 2024 10:49:24 +0100 Subject: [PATCH 13/63] Update dependency postcss to v8.4.35 (#29136) 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 7bfb524907..fb34729048 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13144,13 +13144,13 @@ __metadata: linkType: hard "postcss@npm:^8.2.15, postcss@npm:^8.4.24, postcss@npm:^8.4.33": - version: 8.4.34 - resolution: "postcss@npm:8.4.34" + version: 8.4.35 + resolution: "postcss@npm:8.4.35" dependencies: nanoid: "npm:^3.3.7" picocolors: "npm:^1.0.0" source-map-js: "npm:^1.0.2" - checksum: 4d6f072cdfdc1ced16b4336263d830f8b4397fc47b9b382e02f6448fda9386d881aa9d27fbe0dd124f59c76f3a5da4f360919d25dfc818eca50b48f042af35a8 + checksum: e8dd04e48001eb5857abc9475365bf08f4e508ddf9bc0b8525449a95d190f10d025acebc5b56ac2e94b3c7146790e4ae78989bb9633cb7ee20d1cc9b7dc909b2 languageName: node linkType: hard From 5271131658181bd94eb8a57cc877ef281855e132 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 8 Feb 2024 05:02:53 -0500 Subject: [PATCH 14/63] Extract helper method for repeated form fill in admin/domain_blocks feature spec (#29128) --- spec/features/admin/domain_blocks_spec.rb | 31 +++++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/spec/features/admin/domain_blocks_spec.rb b/spec/features/admin/domain_blocks_spec.rb index 6a1405cdf6..99aa7cf1a7 100644 --- a/spec/features/admin/domain_blocks_spec.rb +++ b/spec/features/admin/domain_blocks_spec.rb @@ -12,9 +12,7 @@ describe 'blocking domains through the moderation interface' do it 'adds a new domain block' do visit new_admin_domain_block_path - fill_in 'domain_block_domain', with: 'example.com' - select I18n.t('admin.domain_blocks.new.severity.silence'), from: 'domain_block_severity' - click_on I18n.t('admin.domain_blocks.new.create') + submit_domain_block('example.com', 'silence') expect(DomainBlock.exists?(domain: 'example.com', severity: 'silence')).to be true expect(DomainBlockWorker).to have_received(:perform_async) @@ -25,9 +23,7 @@ describe 'blocking domains through the moderation interface' do it 'presents a confirmation screen before suspending the domain' do visit new_admin_domain_block_path - fill_in 'domain_block_domain', with: 'example.com' - select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity' - click_on I18n.t('admin.domain_blocks.new.create') + submit_domain_block('example.com', 'suspend') # It doesn't immediately block but presents a confirmation screen expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'example.com')) @@ -47,9 +43,7 @@ describe 'blocking domains through the moderation interface' do visit new_admin_domain_block_path - fill_in 'domain_block_domain', with: 'example.com' - select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity' - click_on I18n.t('admin.domain_blocks.new.create') + submit_domain_block('example.com', 'suspend') # It doesn't immediately block but presents a confirmation screen expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'example.com')) @@ -69,9 +63,7 @@ describe 'blocking domains through the moderation interface' do visit new_admin_domain_block_path - fill_in 'domain_block_domain', with: 'subdomain.example.com' - select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity' - click_on I18n.t('admin.domain_blocks.new.create') + submit_domain_block('subdomain.example.com', 'suspend') # It doesn't immediately block but presents a confirmation screen expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'subdomain.example.com')) @@ -84,8 +76,11 @@ describe 'blocking domains through the moderation interface' do expect(DomainBlockWorker).to have_received(:perform_async) # And leaves the previous block alone - expect(domain_block.reload.severity).to eq 'silence' - expect(domain_block.reload.domain).to eq 'example.com' + expect(domain_block.reload) + .to have_attributes( + severity: eq('silence'), + domain: eq('example.com') + ) end end @@ -109,4 +104,12 @@ describe 'blocking domains through the moderation interface' do expect(domain_block.reload.severity).to eq 'suspend' end end + + private + + def submit_domain_block(domain, severity) + fill_in 'domain_block_domain', with: domain + select I18n.t("admin.domain_blocks.new.severity.#{severity}"), from: 'domain_block_severity' + click_on I18n.t('admin.domain_blocks.new.create') + end end From 15437e4ad9a741eef2d309d5c56a431504d5a45e Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 8 Feb 2024 05:03:04 -0500 Subject: [PATCH 15/63] Add `context` and `before` to lengthy tag manager spec examples (#29129) --- spec/lib/activitypub/tag_manager_spec.rb | 70 ++++++++++++++---------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/spec/lib/activitypub/tag_manager_spec.rb b/spec/lib/activitypub/tag_manager_spec.rb index 55e9b4bb51..05d2609b0d 100644 --- a/spec/lib/activitypub/tag_manager_spec.rb +++ b/spec/lib/activitypub/tag_manager_spec.rb @@ -52,20 +52,27 @@ RSpec.describe ActivityPub::TagManager do expect(subject.to(status)).to include(subject.followers_uri_for(mentioned)) end - it "returns URIs of mentions for direct silenced author's status only if they are followers or requesting to be" do - bob = Fabricate(:account, username: 'bob') - alice = Fabricate(:account, username: 'alice') - foo = Fabricate(:account) - author = Fabricate(:account, username: 'author', silenced: true) - status = Fabricate(:status, visibility: :direct, account: author) - bob.follow!(author) - FollowRequest.create!(account: foo, target_account: author) - status.mentions.create(account: alice) - status.mentions.create(account: bob) - status.mentions.create(account: foo) - expect(subject.to(status)).to include(subject.uri_for(bob)) - expect(subject.to(status)).to include(subject.uri_for(foo)) - expect(subject.to(status)).to_not include(subject.uri_for(alice)) + context 'with followers and requested followers' do + let!(:bob) { Fabricate(:account, username: 'bob') } + let!(:alice) { Fabricate(:account, username: 'alice') } + let!(:foo) { Fabricate(:account) } + let!(:author) { Fabricate(:account, username: 'author', silenced: true) } + let!(:status) { Fabricate(:status, visibility: :direct, account: author) } + + before do + bob.follow!(author) + FollowRequest.create!(account: foo, target_account: author) + status.mentions.create(account: alice) + status.mentions.create(account: bob) + status.mentions.create(account: foo) + end + + it "returns URIs of mentions for direct silenced author's status only if they are followers or requesting to be" do + expect(subject.to(status)) + .to include(subject.uri_for(bob)) + .and include(subject.uri_for(foo)) + .and not_include(subject.uri_for(alice)) + end end end @@ -97,20 +104,27 @@ RSpec.describe ActivityPub::TagManager do expect(subject.cc(status)).to include(subject.uri_for(mentioned)) end - it "returns URIs of mentions for silenced author's non-direct status only if they are followers or requesting to be" do - bob = Fabricate(:account, username: 'bob') - alice = Fabricate(:account, username: 'alice') - foo = Fabricate(:account) - author = Fabricate(:account, username: 'author', silenced: true) - status = Fabricate(:status, visibility: :public, account: author) - bob.follow!(author) - FollowRequest.create!(account: foo, target_account: author) - status.mentions.create(account: alice) - status.mentions.create(account: bob) - status.mentions.create(account: foo) - expect(subject.cc(status)).to include(subject.uri_for(bob)) - expect(subject.cc(status)).to include(subject.uri_for(foo)) - expect(subject.cc(status)).to_not include(subject.uri_for(alice)) + context 'with followers and requested followers' do + let!(:bob) { Fabricate(:account, username: 'bob') } + let!(:alice) { Fabricate(:account, username: 'alice') } + let!(:foo) { Fabricate(:account) } + let!(:author) { Fabricate(:account, username: 'author', silenced: true) } + let!(:status) { Fabricate(:status, visibility: :public, account: author) } + + before do + bob.follow!(author) + FollowRequest.create!(account: foo, target_account: author) + status.mentions.create(account: alice) + status.mentions.create(account: bob) + status.mentions.create(account: foo) + end + + it "returns URIs of mentions for silenced author's non-direct status only if they are followers or requesting to be" do + expect(subject.cc(status)) + .to include(subject.uri_for(bob)) + .and include(subject.uri_for(foo)) + .and not_include(subject.uri_for(alice)) + end end it 'returns poster of reblogged post, if reblog' do From 13840d685c3a19dee6f99d3b74a8bfd3a45cb2ab Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 Feb 2024 11:03:30 +0100 Subject: [PATCH 16/63] Update dependency irb to v1.11.2 (#29135) 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 d60def5222..aa3d95715d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -351,7 +351,7 @@ GEM terminal-table (>= 1.5.1) idn-ruby (0.1.5) io-console (0.7.2) - irb (1.11.1) + irb (1.11.2) rdoc reline (>= 0.4.2) jmespath (1.6.2) From d4db1c497bb25e8a8cb8b0a505d49bb3a99e308c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 Feb 2024 11:03:39 +0100 Subject: [PATCH 17/63] Update dependency pghero to v3.4.1 (#29144) 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 aa3d95715d..152436b47a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -506,7 +506,7 @@ GEM pastel (0.8.0) tty-color (~> 0.5) pg (1.5.4) - pghero (3.4.0) + pghero (3.4.1) activerecord (>= 6) posix-spawn (0.3.15) premailer (1.21.0) From 67ec192d7dbb350511059a858d573daf49ecaf4f Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 8 Feb 2024 12:40:22 +0100 Subject: [PATCH 18/63] Clean up some unused CSS definitions (#29146) --- .../styles/mastodon/components.scss | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index f70fa12a51..427144ed8e 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -4711,43 +4711,6 @@ a.status-card { animation: heartbeat 1.5s ease-in-out infinite both; } -@keyframes shake-bottom { - 0%, - 100% { - transform: rotate(0deg); - transform-origin: 50% 100%; - } - - 10% { - transform: rotate(2deg); - } - - 20%, - 40%, - 60% { - transform: rotate(-4deg); - } - - 30%, - 50%, - 70% { - transform: rotate(4deg); - } - - 80% { - transform: rotate(-2deg); - } - - 90% { - transform: rotate(2deg); - } -} - -.no-reduce-motion .shake-bottom { - transform-origin: 50% 100%; - animation: shake-bottom 0.8s cubic-bezier(0.455, 0.03, 0.515, 0.955) 2s 2 both; -} - .emoji-picker-dropdown__menu { position: relative; margin-top: 5px; @@ -5353,20 +5316,6 @@ a.status-card { } } -.search-results__hashtag { - display: block; - padding: 10px; - color: $secondary-text-color; - text-decoration: none; - - &:hover, - &:active, - &:focus { - color: lighten($secondary-text-color, 4%); - text-decoration: underline; - } -} - .search-results__info { padding: 20px; color: $darker-text-color; From a9e91eb95565a7da74d7c961e56e9c7d6d6b94b1 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 8 Feb 2024 09:26:45 -0500 Subject: [PATCH 19/63] Add common stub setup for resolv dns in email mx validator spec (#29140) --- spec/validators/email_mx_validator_spec.rb | 94 +++++++++++----------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/spec/validators/email_mx_validator_spec.rb b/spec/validators/email_mx_validator_spec.rb index 21b1ad0a11..bc26be8729 100644 --- a/spec/validators/email_mx_validator_spec.rb +++ b/spec/validators/email_mx_validator_spec.rb @@ -5,6 +5,7 @@ require 'rails_helper' describe EmailMxValidator do describe '#validate' do let(:user) { instance_double(User, email: 'foo@example.com', sign_up_ip: '1.2.3.4', errors: instance_double(ActiveModel::Errors, add: nil)) } + let(:resolv_dns_double) { instance_double(Resolv::DNS) } context 'with an e-mail domain that is explicitly allowed' do around do |block| @@ -15,13 +16,7 @@ describe EmailMxValidator do end it 'does not add errors if there are no DNS records' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) + configure_resolver('example.com') subject.validate(user) expect(user.errors).to_not have_received(:add) @@ -29,13 +24,7 @@ describe EmailMxValidator do end it 'adds no error if there are DNS records for the e-mail domain' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([Resolv::DNS::Resource::IN::A.new('192.0.2.42')]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) + configure_resolver('example.com', a: resolv_double_a('192.0.2.42')) subject.validate(user) expect(user.errors).to_not have_received(:add) @@ -58,13 +47,7 @@ describe EmailMxValidator do end it 'adds an error if the email domain name contains empty labels' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getresources).with('example..com', Resolv::DNS::Resource::IN::MX).and_return([]) - allow(resolver).to receive(:getresources).with('example..com', Resolv::DNS::Resource::IN::A).and_return([Resolv::DNS::Resource::IN::A.new('192.0.2.42')]) - allow(resolver).to receive(:getresources).with('example..com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) + configure_resolver('example..com', a: resolv_double_a('192.0.2.42')) user = instance_double(User, email: 'foo@example..com', sign_up_ip: '1.2.3.4', errors: instance_double(ActiveModel::Errors, add: nil)) subject.validate(user) @@ -72,30 +55,15 @@ describe EmailMxValidator do end it 'adds an error if there are no DNS records for the e-mail domain' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) + configure_resolver('example.com') subject.validate(user) expect(user.errors).to have_received(:add) end it 'adds an error if a MX record does not lead to an IP' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getresources) - .with('example.com', Resolv::DNS::Resource::IN::MX) - .and_return([instance_double(Resolv::DNS::Resource::MX, exchange: 'mail.example.com')]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::A).and_return([]) - allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) + configure_resolver('example.com', mx: resolv_double_mx('mail.example.com')) + configure_resolver('mail.example.com') subject.validate(user) expect(user.errors).to have_received(:add) @@ -103,20 +71,48 @@ describe EmailMxValidator do it 'adds an error if the MX record is blacklisted' do EmailDomainBlock.create!(domain: 'mail.example.com') - resolver = instance_double(Resolv::DNS) - allow(resolver).to receive(:getresources) - .with('example.com', Resolv::DNS::Resource::IN::MX) - .and_return([instance_double(Resolv::DNS::Resource::MX, exchange: 'mail.example.com')]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::A).and_return([instance_double(Resolv::DNS::Resource::IN::A, address: '2.3.4.5')]) - allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::AAAA).and_return([instance_double(Resolv::DNS::Resource::IN::AAAA, address: 'fd00::2')]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) + configure_resolver( + 'example.com', + mx: resolv_double_mx('mail.example.com') + ) + configure_resolver( + 'mail.example.com', + a: instance_double(Resolv::DNS::Resource::IN::A, address: '2.3.4.5'), + aaaa: instance_double(Resolv::DNS::Resource::IN::AAAA, address: 'fd00::2') + ) subject.validate(user) expect(user.errors).to have_received(:add) end end + + def configure_resolver(domain, options = {}) + allow(resolv_dns_double) + .to receive(:getresources) + .with(domain, Resolv::DNS::Resource::IN::MX) + .and_return(Array(options[:mx])) + allow(resolv_dns_double) + .to receive(:getresources) + .with(domain, Resolv::DNS::Resource::IN::A) + .and_return(Array(options[:a])) + allow(resolv_dns_double) + .to receive(:getresources) + .with(domain, Resolv::DNS::Resource::IN::AAAA) + .and_return(Array(options[:aaaa])) + allow(resolv_dns_double) + .to receive(:timeouts=) + .and_return(nil) + allow(Resolv::DNS) + .to receive(:open) + .and_yield(resolv_dns_double) + end + + def resolv_double_mx(domain) + instance_double(Resolv::DNS::Resource::MX, exchange: domain) + end + + def resolv_double_a(domain) + Resolv::DNS::Resource::IN::A.new(domain) + end end From ca8fbda5d031b9671447445a83acac96b4fab2fb Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 8 Feb 2024 20:13:44 +0100 Subject: [PATCH 20/63] Add end-to-end test for OCR in media uploads (#29148) --- .../compose/components/upload_button.jsx | 1 + spec/fixtures/files/text.png | Bin 0 -> 16219 bytes spec/system/ocr_spec.rb | 33 ++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 spec/fixtures/files/text.png create mode 100644 spec/system/ocr_spec.rb diff --git a/app/javascript/mastodon/features/compose/components/upload_button.jsx b/app/javascript/mastodon/features/compose/components/upload_button.jsx index 3866f239d7..50c9ad6321 100644 --- a/app/javascript/mastodon/features/compose/components/upload_button.jsx +++ b/app/javascript/mastodon/features/compose/components/upload_button.jsx @@ -65,6 +65,7 @@ class UploadButton extends ImmutablePureComponent { key={resetFileKey} ref={this.setRef} type='file' + name='file-upload-input' multiple accept={acceptContentTypes.toArray().join(',')} onChange={this.handleChange} diff --git a/spec/fixtures/files/text.png b/spec/fixtures/files/text.png new file mode 100644 index 0000000000000000000000000000000000000000..7463b54fd558938e4c59e71f5a90027692c28d7f GIT binary patch literal 16219 zcmeHu^;=bI)GZb&pdOV*;D{hdOE*f2bhBxsTiJA~2$CW#o9+%tX%&_3k`{?gcjuk! zeD^;0Ke#_#o@aYF8`x{D`ObIFF~=Bhppt_04Lou@92}e*GS4JbaBwaW!1wvraN*zf z4-_TvpX)E5q0l%uHye@H1->h)wD2aGqokIjs=b+`i;;sVj*E*6tEHVa+Sur&DXYDM zdHk9XIS$UhI5HAX)m#%+C(N~oG|#SXOp$%0xu)@txP+wS4d+lgt#n*9=HCIzzJc+i z=NPIoa#fqa++Uqiy!l1s_vE==P5Kulw6V z+qm;x{QX@W>m83m(02dAP2u3YrvGS@c;UZqOAM}&{`bw3+ZU0i!NE~__xgW+M0nru zzc+9s|NpQ2KaI<*#WKN@Img95It)MhA!lWmj(z=4-?wj>6|ASf`>p)><{NZw9@2ZX zyIlSAI;_>gpJr+wllM0%RZbdxeJ>U2)e?7emylm3Fuc3JK4nh9YsW>-PCzLT70~kc z;`(fBqzN;NOhiG%O~?eQfh6k>A3jL97QG=#mAUiZf;04;;y2;5)qN$v_3d@i_u5r= z-~35pOGP$S;}op#Hb<0R@kc@eJ>M~%DCjcuKo%!@vc_ro_urqv@@IPOF)Ws6Cx<+2 znpANDPK<&cdj+kH6r$cj^*epC&Slh)V4I6n?DzOyzK)KLCezDyS)X*?WM^hzNHOp} zl;k#aJzlK}+*rKzgrv2#RcwDQ`R9)xJp;L_)nQ>_#3LLsQc}35tM)#|baZqN&nujtb7J#;HwStSKkl4_Ut6# zeun8E_>|g=aHOAWw)4VeSpF-EN8q|~>6CK^VG??#X8&hsI$f%*Mop*3vQo^oZ zsLdUJ>kw+&hB@*VVnG1`>__LO?J;+n%zgxIl9bUn~DIvN{fTMK3e&aj-`0%ji z=6NieK^CWZ*Fr=r{M++0n1twj9gCF~_SpL|jQqarf1egX8z>b3&|nrq z!TTY-i4zCsHNQPD7KYUoW7ZuMtYlW7BeadfM9F-u|oFuQ@X-t1py- zm*Mf_a3UfiWoKue+qczoRs6;$CUTuuM`zd9yD7M>BnI=;%U;>FhXn*&J6kSpWW>D! z37-ye?CjHw-%b_s(sMo7xUX019IB$CqGe~tYHDt-s;^HaOn#c{zPmKLwx+PVJdAB< zXc&O>dQsphZ<81sD?MDKmmU&A5EB_G&d<*u6(28~nVC7eu<#77_ke_i#KFml&feZ$ zztP)kYj>AUT3Se%WYq02; z4>Lm%$UZo5jfskqaC380)76zzP*9kipO>1PoE#`Xajvbe8%!6aLZ(9OiRm6bEFG(| zS2Z%aPee%g&uwM6h1S8rXiqP%T;+7Bx~IOlv$L}%Gxu~1U@Pj?xrR?bS=idzIx9OL z%-5u6V`H=WU2@-ksDP~c%a`AL*-MN=gQ)B9JiRe2I$Cma1eAi#Arp0OscO$IW|uPd_3p&P#ELGvY9cDCt|>PxrG~EV$&d5($@=(-MxSI44-XyTRge9(-Xvj< zkgj_67eB7m5|HBI;Vm3&&M-fG=#T8=wrD2iM~?#A+S(+%y8;4)goJXOmWPmg5*HUg zEbA7Ly?OKIsM)v#5=JE9;5Pd?-W^aK`0~p5Y^AJQ1$JnTYPN!z zfhv5LM$a96H%^e2mGy(EiHVk@Jinlzs-a;DUA$5hEVWLhjnVPmYWhrbSQ&&gJo$0j z6z)~mwQ8*ERD+l0LQm>=f4^#^khVBP4a$1V>O^fUtWREHS3+W9u52u;5EoaJ{|$;? zrza;nEm?z!!X7a^_LChSsD#^KuSoj&`9avay1E8F8%w*x=N|N=idTPTYtrWTITIoy z!2Nmd;p(as`A|N@PCUkRw9!X&tke{Lb-X%qqQOgt1vS62A_vc$4T}zy+{-0R;C&aG}`;25*0e=Ld7>tx0H$au`A@FtgP$+D`yIw$zd%|v$%_1A%TJZ z;lt6Bq+a7VUi+k_io192Y`wQOAIMRb^4VUknzC}Z<#W0_EY%MgwL;zJb#{nV-?tqq zKw)OpV@$9c{&Nnz!ZV=JM40Q%$@-J=!fB^*YGN zwCvA1DfT(d_nhw_i`*K{kh$BrMO(^c^ZTRD@uy@Vw?1~ygO?*efBs~2bA0t`y6OF` zSj9vE(|+s4?qPKklZ<<$q!zsm`~m`7BnFvmixO-oM?JIWNI=gJ4 zQ6IQWdC|v4M_YQ|?7TtRl_YF!F;-cqzCSiH64#w5sL4Z0z*ApDZSW5}DQe}B;TN~< zETgZlFJOpk!r0()^H8UTZ5kO>zkW?B2`wA9+d%iQ$6g5;Yr(J0iw=zGUHPUbe7k3NR;Oqv;kV=8-S%jZ&GPZIQ$w5o$MAU_--$DD=5= z#WrVVXZL@+FaCRFq^w;tOj0m1Awllx)2DqAbh4ya-B_;vzCH`c{gu=GDf3^W#u^Wy zFmai6kfzgr9Yu5Gbk?&wuV}@0*Z=#wL5mY^VW7fV(-PVfCWh10)D++s+h;|Q!*|#B zzTx0Q`R@ZDIU-H%mGRr9Wi%)_coDLni9*1U0Xkwoojgq%?2}R`bY;?ssEU_>Mwj|B zg9%AUvQgw&0Uth?B?>r2yf8L)lHKlz;~dD8C9zx{Ds)b4-!C^sWg)jzzuhJ1{K_|mSF=brwJT9j7TcX% zC37_8ear$)mr(zsH_7eWMqGvgfT^@ob)kb<4;TF$$G`ae`E!dO0k=DT>k`GduT~6e znV8VFJ*G4!(e<~_MpClwE{^fnNNFP7dzTR-ms#9Y4hV}4wl|6Mlmt{ofK3O{L z$Y=Y;)0q16vtu&@+6Y?ZP7F8Fa7)+}2V6v$O8f zD+q0#FD@>Yqp=D+jtfe`#oLfxoW^X-L`G{@6crV>c6MmZ&CMB^nKM>aY&fc71`XMj zBqT0d!@eGrmPXY$K2kj%P5<%pryun4*8cuT2xJTFH0a zfKe1{UQWM7HM%%CWdbZvfdZOSP!OV`s+yaV(=xl70If#fb^40s`Ppgd`}glrZpz#J zilU$0w&&xV^Z*Eid3t*0Ksf4BQeH#)^#Zt3lm1s$Mke*mrK``Osh6VSDtiEsk3ci- zJaf>iveR=wqaVmb+q@b1b;SQOEOotn1%-N&tJbvAs7pLGe^emkOmXGSJYFg0kYcH7i3*K_RPCWoHT~P|T8ughbWV z^$YAddL8QkEC59J_4@sH?aDqrKIH6%I6l*UBn<5AA4N}h`V}$Ke?_rfu;edZ&>*M` zc|m4NU%f?T0+pP2?ilI@RuPXcJv|)-ZK8Jy5JL2D0jfW3r<1HG3atQXXJp=$aQiG2 zK+O$O_Sf(I{FK9}guf&wPf>s1#U|KI*2%z_`2un@4Iu7g6tRb~bD5YSG?LUz%uC$0Y*kqrib4!uy3Oi%>=)>0Hh?q1OH28GCynG{a zID2=(I$kkZL>}5vsm!;x#l>u)WSsu*-@V&_fSq-pJO$|PIQ{*~XoWS2PPIek#&H01 z`_9pFF(-s!vfjfba<54RCWkEO;AFyQP?pjlvYQ_$1tY@3Ztd^wWocJfDL;LB0jaOB zm3~7lU|?hnqNAm~mVMeKxLyK9U~PWhY}5Ob*UWfBt-4r_*r^RIUz1DUzU7fKHMEPxB)Yt*zqCuC+0#EQ*j;5i7x)l zo0S$?d$6s=pFInB=?;*xO4}`mn4N*;&6_tT065IDb(EA07y7fqdPIhyq{c=?X`NCL z|DRZeka0>aq+Q3ykHp8rE2u1n8Oy)%WR6YDvRJQn=40$g!0q-&gxc?C7 zj+%s8fY~iHY%#_4dzhccFy|T#Zq=f(UE_Vl3~BA*52Ohc$rYytwlgag-LDeB6j0-` z&Z>4cP^33z)wDn*=-lyVaq&@LzwQ}$ooYYTP|Drj1Gts~hzIq4N@4eM z`N{BAhu=|QB1Zv_f6?l&v1pg~>>hM{dMwUe4+XwIh=}QnudnYzH?2~W>zWkxfMb}- zjhk=A-`X@)#KXszF&Vfl6JY@@YzslbgF66#I}F?x>53}#EiE5;0k;=@G#=Q|YPgmo zFlPjh4OzUHG+$!WbnqkaZYb6H$%*G^om-jYu%)MGUGF)p9|q(zPxq12-;qNJg$I})rRX`H)(9A8uW&-n8rrYLW9O6oic*m z-QCPE(KD@Gq4kk6=_o3X%pEi7QP5p_?~5{B3g;(#E-NcPYNo7w z8!kJ!FpfWG>PTA%2v63DHW_f2PL$O1=Rv(B0aJpZZ?7P;wpBL^O&YYLeB8i!cWk1| zyNls~*%)r-GXJ&rIgVet_7u1cO#N?Ys2G^(mfbtMl0^*`=sa5^=;|PkH58|sntX}b z^qI@MA)Zz4N6$%(%Uw5Lpn|=U_+HVtyn6MxMnOu--^wq5_#gJ)fqwWTc}1K6XHzZ4 zRA5dRNSD5qz6`^I^um?uQZ0BEt8dz6X7Wb>4!D^%B&!Snm})CTs8e0Od|3&`62kN3 zm>8+7u7U=qWsUSmGN<*)L~?E`leULU1+WHr3c4-}J@=>Yb0tgIDqIWyLmmRuW<&rkafTMBim-ieGg9L~pM2EGfe z4Qd+9DT#;7b&vN_5i0KNv zOV4UA}c#_v1s&l)qNKY``;2rfyy+_sjzN4YxzfLQ^mHWA% zGNd0Bd~sgIWVyNCfyaE3!A}18#k-sQhiozt3;Vsd2~Po>xc<4*+u(JqHoQ2PPqM$c z*?XTiV>C5(p=uPkzFQhg+t|fL8RR=54QOlMxitWrl=aSYHu>L}8N$?mNy|~m#LJzy z3wg}pacsqAPr|C3V%+>8uKu*m4rY?PeJQ9#IglSUm)lN{_en6*?m((NjP*c-lG9G; zG4c}yC|K6!Xfy39V&8919zTAZcg)Pu<6jXVG^~)o_Y`msW?sB~UNel#vhUphqbke> z?;pxU%ge|FS{VU$zp*q?TeVgZX=S@}=kDD{^z_o%$xqV^E?(&wPFc5#?cH&_y-+5)$t$$?|FI>gqzy&LQK>>}z3O&0DV9YGdky z`|eao=eTR>&ksFsVsunBRRTM`of$N@UrP+I zpb0%B3y{K#d-@zEE&mL9vqKCqnkKkcu2@#P(Hs>TC?K3)k#Vp{hBF!amzo+C;EZh= z7J4r;09P3l6ckd_pDKQ}XoyM^zguWKr1u=%W!tAZm6QP(8lZyu@bY+dSHRNaYEHNIM}!82|^V2amzC}ezmTyCU5vfK{War3X_ zpz-YLs{9QKo&hfEuzby8Dj05Zi(KF*om*c?(^FFZ)oXL8IQvjtUF~i%bL*ayqViV& zN?(Q&pG)XgJNT6+1tXMK9_@g7;m>7er&R%-5B_N% zm9WzE>GsGJc9A$wj5M08a|^=0f;wUYh%%^I#$@eEp;SPxDpa^cQJ*BeM(@P4({&$J z5D)%0?GFrk33Sg$>K9fQo@#4jMush5qi_TFG$5r=?R_e+yEdWY4rAOwhD;<?XAL z&81;5b9Hbi?cGi_{rYEmI`v3>K-)X{tNbeiSR$v^=9v`^!yGvY)-?b{%O4}p=^Ts$ zgt!<>fBcXbbkZ)jcnVNPV0OMyf+_(~mFnt*@-zxD3e}~GFxK&c9)v3M_X5R6@uW>t zOY0dFJa&P7F*i!e+>(-yd#hv3X=!N-8`Di4#EC0_JUY)P_>zS$$ZnQK%gbJag_18i$!*H>O`d zovj)6xcGHS@TZjq{(T2;Nyf|q;KZHFk><5b`|zQa#_flF(!aC^+7cro?j$;FfwXNS zml3)KyUMRY;?vA@)BB*A=zMt<@g1GWgf_Vh{s@+b0eA!iw9v-}(XRVzdU)5a^*qwt z%Y|tNVb6YE&!G}>eFBwlMP}8B7nt>s!Mxb!YLYv5?pS<#d&LF-LC26+6tfq@2WrtI z9|(;cZHdn;l&~FO(}GWz4bEv`;u(TkxincXxIR=!;j}g$x2)b|(G3)bUqi^Ua3mCS zCN$qod>kCAal{M2ZP_Q`)Y1xQ9j{R>3)Z|SeV=3&Kw>yZph}Y+@bDF9ZANw&nr;)c z<;2LzE35qvEN1RfUk!~LNpz(^B^b6F| z+0)R_KqYD>S}y~ouQ%nXZ_kBfAJHq_BwGv zChQyJd%MEXHK5!Og!~)8NXOD}F&h$G42LNmr@80(*7J<;UDkWU>EJT-eMY4y6Fo@dO27g8nA_~o+* zD2zM+0*;)+B;fBQNdNceob8KMsqLL{HoE|Qshm=Cu-pY)FKJgLas_hn#DFaZ!c{k6r>}VUgH`Y8)2@f#2a2w%or~j>?x<2D;%xE z3o9Gum>d#6AKez2sm{7_nSdv2|7EQ%1?%K`;O`cYUS=mjA67gX^)M6k$UwB zVbG~{-SrKijVMWneyD07lBSX2~9Cir>bb} z!C$R3&~XUK$Xa3WU}DoQ54Z}=b?YL??2_W|Z<+#UZ0EN`@d7)Sv?TEBi0L%0g;Riy zP0`h3C~a`lH01h3dnI3ET6*PlbyjHGgm2SL=)!s4B2cI!5zMOkLC!e8yK66vLzs`r z7c?Fb`$?gnB#XccmmrimLOZ}%vNw5e5mMXaznP{OE?jQXdIyz%pAZ-U8*=r*9A)2! z3JEQsrL~~Z=trP=o^G|X5#GJq1hBB6PdXT_0Kb4iBSeYg#fey<6Y&;OKcW!Tj<|N>K!YAmy!$8UJ@GcS5xU{Y)06!-3 z7_L-M8*0a|-k_OFD!hmr4!6FyPh*-P+$a>E4k?#6c7BRqSu|YQQtjm6Al7~(G({#N zG%#c|JSxhh(UyXdKYT>Yws*7Fko_7_5m07xXLCPC2h7ZP_MF}XFwoF^&pZ5F33!7& zvz46sIsrjOOUpBP-zzj@;}mJgUGnjL>W<@l-~8hTkm(~^z=O=fCVYuD-%Awn5&**c zvxCAez1G^uY;|;8TrQ?)fw@~k0{Ai_vMlv|ufeU!+iq;1B}>@c?N+P#E!_Mes!*wl zwMpsd>6bs=Wp9SDJ+npuX79C3O);^H(J?W3McF^uBj+Xn#a36#hFFMTyALQAY)5FO_|4bB}T&6+(?=EHb7o{`}CZg0JBbv`r4G41S5Hoe!Z0n z_JuX@cIoflT^`((%VoHIops=0P+2AHxf(R~gV`9#^$4JBxMdAmGi77dhQD#j3;x$& z7vHkj$^Fw0Fn7=ilFHHNWs;za!fs{;bb=ZMCjmMRW~ zi-%LClT1{jvvqIzEP!)_)2!nU_!+hu&vw~Z1-4hAYHN9WH~gyZk9k%do1CmTTx>8b z!Wo84P)cQwRWS!g$H)0a=(7{I=~a~PP&Z-tw#V8yKR7WQpxzBSot&Jk)O^np0_D*d zMs`g->_Tt)T!U0znicSuR?})qN>9$u_8WIwx_kl%3s`h22kz6)MOJqP4PZD&v;l!x z6?y}I$9nt{!iuL{#Lvgq16}hF%r0}lr{xqGsHlj+)G+5h<>l%5jP^<2@x5TRC|7s) zh(`u~NubdFPedlVAyq9f`mnEUlCGlr30nm}UA^ENiVRG<)1HT0rg_&^^_kKjV9KD1 zstpTz9hDdP%D+4oMfcgAcrym0ky)+m$$q& zR;BpM$&lUNNtzztmJVa`a2^ia87hN_Um4L97VL8Y6Mzp{1i! z21X(4&{Y?BLM1fkWrESC5G}}dwZheprg1zrzmh4DGW zA#WK$>+i>-6oIsXRh7rf(FZ}lHp%17vx5E<{U-6X$@;N|TQOv?5*B?KGI_(HpJmQN zZj(_r0+(K38=nV^ao+OEc(rO3x`RI(77%NPb%C_bL&rUfFxfi1@(PH8uK;A!*fwB&@a0P{A1#kn6)y?Y zI_}dmr3IW%}h3{s)Bo%|rk8b%WI*iPfN?K-zf$xG~4=dHKOzxMR`fk+STi1`tR_ zW>+yY@FPqW-$A`^c}lv{)=33h|*wiKS|kS`PY@VkN0ir1Q-v;-sN4(ZM9_tf4wC8j9g z57dWc6cu@`$7r^x7Y4)Ypx28X9yW`frM6cS$LVB%NHI{T!y9?&FYt|nPC!RA?eOgd zlduiVxi)~63xbcBWx(sPT{m9iB)ecO1w-;`L*IY9=BoSNO72l>WWYkxEm5^Xe%w=T z`^f}}U#92t@%Cz>x!P8+04v}9;A29;;dCYcHQ@X$sZjFpQI1!CC3MWy16q{8X_1SW zpN6Va4tpMtg8fTvZDe}-CciRWYn^m)3yD8CbQT?Kz{-O-Uh?Kzw&vRX%!sNaK*$1G zN5QEPB&?3kxGQ{M`pKs}2C70Ee0y2VXE2V}s0$%FUA|s6uJ4*Btj&0 zZx}gHw%2dnVk2o*HSyeq#%hUq|421UZ6PQO2>U_r%OG(gapxpl=8sy06jB>*?d~4- zTnmKR;c>V^^ZW)c|`^AlC zc{=C}>4%C*1vLsFS3@s<8YvP}%H03%`d!*^L#2#9B4*#$-xOeZ`+_; z?OXX~a%N^(Jq$w8GEm+YfM?Pa_5n4Xkcx^`*z=$#ZxNXD*PRLcs=G$tNz`^(mzPi|-T?T??UJ(`=7U-ql(DKGm zcbAX( z30?(RubFpG$$3QIqXRM0mVt~0s`rf^J7GM@EZE3j+1)PwaybZFY z12lc^_DJS-$Jv(K<+D*GvYi#P>%dve>Z??vre&EwVIs-5&q4=uML>)s}X=4XZ*zKFH3*6buu}1C#*&G~CA{ zK0d9Wz`)NIf-%?d@n>kt8qr;g6~p?*KrX4&Uk!OoO0d%_P5rpHI2Bj@NZ|95`)$vky+eoZ0{S!X+)3|1y)kj{-q{4=PW%ngzyeF3@>X zPr+G)n3A8tD%Q7lNB#Z#0>f#3a~Zruw4=Ry5ULpnEbk*q zU%6#}2gcWY=2vI|+VKxE-k@eew%*T)B z2a{W-&)Ige*f&P43)t}#?B9ijmcW(;4wp4u)VimzWnfqsZ_ZqFzyT<_1xZsdI=9kT ziZ%ePzX9l~{rm(gis;#7pb5U~tMS+`GJ-w0g&6i=)Y1Y`pwdbkIMh;$WblO+*Z9B= zuWWmTY>dz>I+;6F^VPLp$Cck8ei>*IQqmR@X03mxfa7{qdy86x3+(S-*`Y;_OiWB< ztTrC}4R(H|xaeg6?%lhn_S64sWF%f6gUTewXn+`5Gz+!qpgNIH0NyJy0=&NkpxUIO z^emXI;iI^iSjc=+bMyQ7G9Mtl)mduw^z_^sy-#PMX0-z`7y|>SgNq|!l|DJ1i|P--)F|!*Z7j64xgN|uJ(adPky|s%%k84aE1ZYW z&TunlXxdAsK}YaMKD{w)i>|KRekzHChzNBm0#2SpnSDhN*AC%e0<%H2!_Nih{{H?O z;6;msVbH?SY=H3B3+Y$gD*6s@Ih1$u4^S4j$<>1w zs@Gy$23RJk*#9n0?P1Y{iVx)b;#5h5zp z5nO-^3l_wbl=2a@k3~gAA;>coR)aLZNI^X8>x}0`0ja$tBHDVq-q_vSivnVIbf_2-W@t`F^~OEEkD%=@^907`fM=!;N-xd+%7`k|>?D~+M5BTJeFruD8}V;| zo!ziv=9CsOHa5bl*}}Y#agvphp#;Mw>R7A7N`17!t5!E#ffDU)_ZejFPb9>|eRXcz za&3*w?NQ+12NRD*wLZ9izBdBey^JqV)_8~F%&;x$kr1>rix0RZY~UiEg8)R=*VWlX zct3k~Z3>JoHfyxXN}q+dJ2=aoSGDz|Ni2KQu1HEtx6`bqG6lgxse)^09A<@lJD0`2 zOd$q_mb|fY|JSc^1VC-Fk!iM*g>xf8;4Ek41q!v_5jZr6n+UM7diuHucn6WU4q7l+ zDHot1{Q=7C2Do2(glz$ebtUk70$+ZO*aqia6;HY?>lTNOt56#RI6hPfDHYKqBf$Kt}NG_UM zuf{Rez~^*u>D$F#`-)D`m?M$;R(q^Hv%anf=ynSvQ%A4Q6vFOYqRuOy#!HOE_4*K3 zAw0p^q{q7DkxdcoPuOyrH*egifbkw2SYhj<6~VA-id9??Nejq@6QD~=gZER~S{j~{ zDXGCKX;;}%ib8yt1@OWuU>c4-+YIwTd^TK^^ zG?LI5l)?p=|Na2B39qkPopwy|@lx01?9z zU?c2Kz5enuxd_@L7~+ub$7OlF2do1i6GYi`h9?!I!Za!*BBGC&4yt~AtauJ9t*P(k zhtzSqi&<@W_JnhCV2VVD97Nce?M;_PYieqC_Q5HYOel`q;HZ3SQ0pu&0_!(s_=uhI+Sk*IX9qh`JdiIx5IPGQbgO~aE)h6Eva{ysdhI)3&37kv+mC;_uLu)g zm6zREB@1{#wqSy6f!TNt?2}aM{n>~saEQ*!7?*(bD;z4A1r1~qGz1-|F(@|K$p0~E z7PZizuUJ@uCU*k6V+$yO>K5JSR^+^Pa&Xx>_{1o%@E3j*U*6u?$$;9o2@s$SSmctW z(>XXc0V?nuoRNwFg*4C2lp@DC0qr&a@q7Y+pSt-30Rcg|`?nV#fY}@^GY?y;DhA;) ze)lm0xOd?QRS8(FdLXu1Vq$Mw(_MsA;NXwdX!)b{p43abi~aADJl6P&eqOsP@!#pM zPoGHBn=7G(AeK_%Y$t%S&lMCjw(Iy$;UqYn=twMbHDZ8@+{t zLqalOtH%vkPIY#M!UXjVyd8=#7-k3cRDENH&)@GOF>^nyeQ{o0TLi#rOHHii{_6|n(J+`m_@GAru$yX-2PrHayqIm>-SjY7 z0rEf&X2C%Y}XQ#(e;AMehjtHlToWg=0m8YIh41;bI zhR3!I7^ThR>G*bh;9nu$jzDiXgZ2a_r*z0b1WUYqdy$cag%0tgE2sbRY3oMFNB{+( zGdx-xv8+pL?d;5ilYUAnDtExJlLh&&1T+Aw4NPPdAl@he^3MS)%K#MDNzgkP?N3V` z92^$FLWp1h?4c7UF$b!1t=})u>DHl;2v@w z4J33WI6wzL27;&t^#BgQWdd^j@8;k*Sn8v~Q?ajbP7uC={%QN~?DA`{*ZlWJ$~8DU qh?~VWeEB}w Date: Fri, 9 Feb 2024 10:55:30 +0100 Subject: [PATCH 21/63] New Crowdin Translations (automated) (#29152) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ia.json | 22 +++ app/javascript/mastodon/locales/sk.json | 9 +- app/javascript/mastodon/locales/tok.json | 177 ++++++++++++++++++----- config/locales/activerecord.tok.yml | 8 + config/locales/doorkeeper.tok.yml | 50 +++++++ config/locales/simple_form.tok.yml | 4 +- config/locales/sk.yml | 2 +- config/locales/tok.yml | 4 + 8 files changed, 230 insertions(+), 46 deletions(-) diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 7b9ab3742b..10328efd0e 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -2,6 +2,8 @@ "about.blocks": "Servitores moderate", "about.contact": "Contacto:", "about.disclaimer": "Mastodon es software libere, de codice aperte, e un marca de Mastodon gGmbH.", + "about.domain_blocks.silenced.title": "Limitate", + "about.domain_blocks.suspended.title": "Suspendite", "about.rules": "Regulas del servitor", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Adder o remover ab listas", @@ -12,6 +14,7 @@ "account.blocked": "Blocate", "account.browse_more_on_origin_server": "Navigar plus sur le profilo original", "account.copy": "Copiar ligamine a profilo", + "account.direct": "Mentionar privatemente a @{name}", "account.disable_notifications": "Stoppar le notificationes quando @{name} publica", "account.domain_blocked": "Dominio blocate", "account.edit_profile": "Modificar profilo", @@ -33,6 +36,7 @@ "account.languages": "Cambiar le linguas subscribite", "account.link_verified_on": "Le proprietate de iste ligamine esseva verificate le {date}", "account.locked_info": "Le stato de confidentialitate de iste conto es definite a blocate. Le proprietario revisa manualmente qui pote sequer lo.", + "account.media": "Multimedia", "account.mention": "Mentionar @{name}", "account.moved_to": "{name} indicava que lor nove conto ora es:", "account.mute": "Silentiar @{name}", @@ -57,6 +61,7 @@ "account.unmute_notifications_short": "Non plus silentiar le notificationes", "account.unmute_short": "Non plus silentiar", "account_note.placeholder": "Clicca pro adder un nota", + "admin.dashboard.retention.average": "Median", "admin.dashboard.retention.cohort_size": "Nove usatores", "admin.impact_report.instance_followers": "Sequitores que nostre usatores poterea perder", "admin.impact_report.instance_follows": "Sequitores que lor usatores poterea perder", @@ -69,6 +74,7 @@ "bundle_column_error.return": "Retornar al initio", "bundle_modal_error.close": "Clauder", "bundle_modal_error.retry": "Tentar novemente", + "closed_registrations_modal.description": "Crear un conto in {domain} actualmente non es possibile, ma considera que tu non besonia un conto specific in {domain} pro usar Mastodon.", "closed_registrations_modal.find_another_server": "Trovar altere servitor", "column.about": "A proposito de", "column.blocks": "Usatores blocate", @@ -105,6 +111,7 @@ "compose_form.poll.option_placeholder": "Option {number}", "compose_form.poll.single": "Seliger un", "compose_form.poll.switch_to_multiple": "Cambiar inquesta pro permitter selectiones multiple", + "compose_form.poll.switch_to_single": "Cambiar inquesta pro permitter selection singule", "compose_form.poll.type": "Stylo", "compose_form.publish": "Publicar", "compose_form.publish_form": "Nove message", @@ -117,6 +124,8 @@ "confirmations.block.block_and_report": "Blocar e signalar", "confirmations.block.confirm": "Blocar", "confirmations.block.message": "Es tu secur que tu vole blocar {name}?", + "confirmations.cancel_follow_request.confirm": "Retirar requesta", + "confirmations.cancel_follow_request.message": "Es tu secur que tu vole retirar tu requesta a sequer a {name}?", "confirmations.delete.confirm": "Deler", "confirmations.delete.message": "Es tu secur que tu vole deler iste message?", "confirmations.delete_list.confirm": "Deler", @@ -320,6 +329,8 @@ "report.placeholder": "Commentos additional", "report.reasons.dislike": "Non me place", "report_notification.categories.other": "Alteres", + "report_notification.open": "Aperir reporto", + "search.no_recent_searches": "Nulle recercas recente", "search.quick_action.go_to_account": "Vader al profilo {x}", "search.quick_action.go_to_hashtag": "Vader al hashtag {x}", "search.quick_action.open_url": "Aperir URL in Mastodon", @@ -333,14 +344,20 @@ "search_results.hashtags": "Hashtags", "search_results.see_all": "Vider toto", "search_results.statuses": "Messages", + "server_banner.active_users": "usatores active", "server_banner.learn_more": "Apprender plus", + "server_banner.server_stats": "Statos del servitor:", "sign_in_banner.create_account": "Crear un conto", "sign_in_banner.sign_in": "Initiar le session", "status.block": "Blocar @{name}", "status.copy": "Copiar ligamine a message", "status.delete": "Deler", + "status.direct": "Mentionar privatemente a @{name}", "status.direct_indicator": "Mention private", "status.edit": "Modificar", + "status.edited": "Modificate le {date}", + "status.edited_x_times": "Modificate {count, plural, one {{count} tempore} other {{count} tempores}}", + "status.favourite": "Adder al favoritos", "status.filter": "Filtrar iste message", "status.hide": "Celar le message", "status.history.created": "create per {name} le {date}", @@ -351,12 +368,17 @@ "status.mute_conversation": "Silentiar conversation", "status.read_more": "Leger plus", "status.share": "Compartir", + "status.show_less": "Monstrar minus", + "status.show_more": "Monstrar plus", "status.translate": "Traducer", "status.translated_from_with": "Traducite ab {lang} usante {provider}", + "status.uncached_media_warning": "Previsualisation non disponibile", + "subscribed_languages.save": "Salveguardar le cambiamentos", "tabs_bar.home": "Initio", "tabs_bar.notifications": "Notificationes", "timeline_hint.resources.statuses": "Messages ancian", "trends.trending_now": "Ora in tendentias", + "upload_button.label": "Adde imagines, un video o un file de audio", "upload_modal.choose_image": "Seliger un imagine", "upload_modal.detect_text": "Deteger texto ab un pictura", "video.close": "Clauder le video", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 7a05eb4f7e..ad7837cab2 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -280,6 +280,7 @@ "follow_suggestions.curated_suggestion": "Výber zo servera", "follow_suggestions.dismiss": "Znovu nezobrazuj", "follow_suggestions.personalized_suggestion": "Prispôsobené odporúčania", + "follow_suggestions.popular_suggestion": "Populárne návrhy", "follow_suggestions.view_all": "Zobraz všetky", "follow_suggestions.who_to_follow": "Koho nasledovať", "followed_tags": "Nasledované haštagy", @@ -355,7 +356,7 @@ "keyboard_shortcuts.muted": "otvor zoznam stíšených užívateľov", "keyboard_shortcuts.my_profile": "otvor svoj profil", "keyboard_shortcuts.notifications": "Otvor panel oznámení", - "keyboard_shortcuts.open_media": "na otvorenie médií", + "keyboard_shortcuts.open_media": "Otvorenie médií", "keyboard_shortcuts.pinned": "otvor zoznam pripnutých príspevkov", "keyboard_shortcuts.profile": "otvor autorov profil", "keyboard_shortcuts.reply": "odpovedať", @@ -364,7 +365,7 @@ "keyboard_shortcuts.spoilers": "to show/hide CW field", "keyboard_shortcuts.start": "otvor panel ''začíname''", "keyboard_shortcuts.toggle_hidden": "ukáž/skry text za CW", - "keyboard_shortcuts.toggle_sensitivity": "pre zobrazenie/skrytie médií", + "keyboard_shortcuts.toggle_sensitivity": "Ukáž/skry médiá", "keyboard_shortcuts.toot": "začni úplne nový príspevok", "keyboard_shortcuts.unfocus": "nesústreď sa na písaciu plochu, alebo hľadanie", "keyboard_shortcuts.up": "posuň sa vyššie v zozname", @@ -493,7 +494,7 @@ "onboarding.share.message": "Na Mastodone som {username}. Príď ma nasledovať na {url}", "onboarding.share.next_steps": "Ďalšie možné kroky:", "onboarding.share.title": "Zdieľaj svoj profil", - "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", + "onboarding.start.lead": "Teraz si súčasťou Mastodonu, unikátnej, decentralizovanej sociálnej platformy, kde ty, nie algoritmus, spravuješ svoj vlastný zážitok. Poďme ťa naštartovať na tomto novom sociálnom pomedzí:", "onboarding.start.skip": "Want to skip right ahead?", "onboarding.start.title": "Zvládli ste to!", "onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.", @@ -705,7 +706,7 @@ "units.short.million": "{count}mil.", "units.short.thousand": "{count}tis.", "upload_area.title": "Pretiahni a pusť pre nahratie", - "upload_button.label": "Pridaj médiálny súbor (JPEG, PNG, GIF, WebM, MP4, MOV)", + "upload_button.label": "Pridaj obrázky, video, alebo zvukový súbor", "upload_error.limit": "Limit pre nahrávanie súborov bol prekročený.", "upload_error.poll": "Nahrávanie súborov pri anketách nieje možné.", "upload_form.audio_description": "Popíš, pre ľudí so stratou sluchu", diff --git a/app/javascript/mastodon/locales/tok.json b/app/javascript/mastodon/locales/tok.json index 1c84356238..7270d52067 100644 --- a/app/javascript/mastodon/locales/tok.json +++ b/app/javascript/mastodon/locales/tok.json @@ -2,16 +2,18 @@ "about.blocks": "ma lawa", "about.contact": "toki:", "about.domain_blocks.no_reason_available": "mi sona ala e tan", + "about.domain_blocks.suspended.title": "weka", "about.not_available": "lon kulupu ni la sina ken alasa ala e sona ni.", "about.rules": "lawa kulupu", "account.account_note_header": "sona awen", + "account.badges.bot": "ilo nanpa li lawa e ni", "account.badges.group": "kulupu", "account.block": "o weka e @{name}", "account.block_domain": "o weka e ma {domain}", - "account.block_short": "o weka e jan", - "account.blocked": "jan ni li weka", + "account.block_short": "o weka e jan tawa mi", + "account.blocked": "jan ni li weka tawa mi", "account.browse_more_on_origin_server": "sina tawa ma tan pi jan ni la sina ken lukin e mute", - "account.cancel_follow_request": "o pini wile kute", + "account.cancel_follow_request": "o pini kute", "account.copy": "o pali same e linja pi lipu jan", "account.direct": "len la o mu e @{name}", "account.disable_notifications": "@{name} li toki la o toki ala e toki ona tawa mi", @@ -34,15 +36,15 @@ "account.media": "sitelen", "account.mention": "o toki e jan @{name}", "account.moved_to": "lipu jan sin pi jan {name} li ni:", - "account.mute": "o kute ala e @{name}", + "account.mute": "o len e @{name}", "account.mute_notifications_short": "o kute ala e mu tan jan ni", "account.mute_short": "o kute ala", - "account.muted": "sina kute ala e jan ni", + "account.muted": "sina len e jan ni", "account.no_bio": "lipu li weka", "account.open_original_page": "o open e lipu open", "account.posts": "toki suli", "account.posts_with_replies": "toki ale", - "account.report": "jan @{name} la o toki e lawa", + "account.report": "jan @{name} la o toki tawa lawa", "account.requested": "jan ni o ken e kute sina. sina pini wile kute la o luka e ni", "account.requested_follow": "{name} li wile kute e sina", "account.share": "o pana e lipu jan @{name}", @@ -51,20 +53,21 @@ "account.unblock_domain": "o weka ala e ma {domain}", "account.unblock_short": "o pini weka", "account.unfollow": "o pini kute", - "account.unmute": "o kute e @{name}", + "account.unmute": "o len ala e @{name}", "account.unmute_notifications_short": "o kute e mu tan jan ni", - "account.unmute_short": "o ken kute e jan ni", + "account.unmute_short": "o len ala", "admin.dashboard.retention.average": "sama", "admin.dashboard.retention.cohort": "tenpo mun open", "admin.dashboard.retention.cohort_size": "jan sin", "alert.rate_limited.message": "tenpo {retry_time, time, medium} la o pali awen", "alert.unexpected.message": "pakala li lon", - "alert.unexpected.title": "pakala", + "alert.unexpected.title": "pakala a!", "announcement.announcement": "toki suli", "audio.hide": "o len e kalama", - "bundle_column_error.error.title": "pakala!", + "bundle_column_error.error.title": "ike a!", "bundle_column_error.network.title": "pakala la ilo sina li toki ala tawa ilo ante", "bundle_column_error.retry": "o ni sin", + "bundle_column_error.return": "o tawa tomo", "bundle_column_error.routing.body": "ilo li sona ala e lipu wile. sina pana ala pana e nasin pona tawa lipu?", "bundle_column_error.routing.title": "pakala nanpa 404", "bundle_modal_error.close": "o pini", @@ -72,64 +75,92 @@ "bundle_modal_error.retry": "o ni sin", "closed_registrations_modal.find_another_server": "o alasa e ma ante", "column.blocks": "kulupu pi jan weka", - "column.lists": "lipu pi lipu mute", - "column.mutes": "sina wile ala kute e jan ni", - "community.column_settings.local_only": "toki lon ni taso", + "column.home": "lipu open", + "column.lists": "kulupu lipu", + "column.mutes": "jan len", + "column.pins": "toki sewi", + "column_header.hide_settings": "o len e lawa", + "column_header.pin": "o sewi", + "column_header.show_settings": "o lukin e lawa", + "column_header.unpin": "o sewi ala", + "community.column_settings.local_only": "toki tan ni taso", "community.column_settings.media_only": "sitelen taso", + "community.column_settings.remote_only": "toki tan ante taso", "compose.language.change": "o ante e nasin toki", "compose.language.search": "o alasa e nasin toki...", + "compose.published.body": "toki li pana.", "compose.published.open": "o lukin", "compose.saved.body": "ilo li awen e ijo pana sina.", "compose_form.direct_message_warning_learn_more": "o kama sona e ijo ante", - "compose_form.placeholder": "sina toki insa e seme", + "compose_form.placeholder": "sina wile toki e seme?", + "compose_form.poll.duration": "tenpo pana", + "compose_form.poll.multiple": "pana mute", "compose_form.poll.option_placeholder": "ken nanpa {number}", + "compose_form.poll.single": "pana pi wan taso", "compose_form.poll.switch_to_multiple": "o ante e nasin pana. pana mute o ken", "compose_form.poll.switch_to_single": "o ante e nasin pana. pana wan taso o lon", + "compose_form.poll.type": "nasin", "compose_form.publish": "o toki", "compose_form.publish_form": "o open toki sin", "compose_form.reply": "o toki lon ijo ni", "compose_form.save_changes": "o sin e ni", "compose_form.spoiler.marked": "o weka e toki pi ijo ike ken", - "confirmations.block.confirm": "o weka.", + "confirmation_modal.cancel": "o pini", + "confirmations.block.confirm": "o weka", "confirmations.block.message": "sina o wile ala wile weka e jan {name}?", "confirmations.cancel_follow_request.confirm": "o weka e wile sina", "confirmations.cancel_follow_request.message": "sina awen ala awen wile weka e wile kute sina lon {name}?", - "confirmations.delete.confirm": "o pakala", - "confirmations.delete.message": "sina wile ala wile pakala e toki ni", - "confirmations.delete_list.confirm": "o pakala", - "confirmations.delete_list.message": "sina wile ala wile pakala e lipu ni", + "confirmations.delete.confirm": "o weka", + "confirmations.delete.message": "sina wile ala wile weka e toki ni?", + "confirmations.delete_list.confirm": "o weka", + "confirmations.delete_list.message": "sina wile ala wile weka e lipu ni?", "confirmations.discard_edit_media.confirm": "o weka", + "confirmations.discard_edit_media.message": "toki sitelen anu lukin lili sitelen la ante pi awen ala li lon. sina wile weka e ante ni?", "confirmations.domain_block.confirm": "o weka.", "confirmations.edit.confirm": "o ante", "confirmations.logout.confirm": "o weka", "confirmations.logout.message": "sina wile ala wile weka", - "confirmations.mute.confirm": "sina wile ala kute e jan ni", + "confirmations.mute.confirm": "o len", "confirmations.mute.message": "sina awen ala awen wile kute ala e {name}?", - "confirmations.redraft.confirm": "o pakala o pali sin e toki", + "confirmations.redraft.confirm": "o weka o pali sin e toki", + "confirmations.redraft.message": "pali sin e toki ni la sina wile ala wile weka e ona? sina ni la suli pi toki ni en wawa pi toki ni li weka. kin la toki lon toki ni li jo e mama ala.", + "confirmations.reply.confirm": "toki lon toki ni", + "confirmations.reply.message": "toki tawa ona li weka e toki pali sina ꞏ sina wile ala wile ni", "confirmations.unfollow.confirm": "o pini kute", "confirmations.unfollow.message": "sina o wile ala wile pini kute e jan {name}?", "conversation.delete": "o weka e toki ni", "conversation.mark_as_read": "ni o sin ala", "conversation.open": "o lukin e toki", "conversation.with": "lon {names}", + "directory.local": "tan {domain} taso", "directory.new_arrivals": "jan pi kama sin", + "directory.recently_active": "jan lon tenpo poka", + "disabled_account_banner.account_settings": "wile pi lipu jan", + "disabled_account_banner.text": "sina ken ala kepeken e lipu jan sina pi nimi {disabledAccount}.", + "dismissable_banner.community_timeline": "ni li toki pi tenpo poka tawa ale tan jan lon ma lawa pi nimi {domain}.", "dismissable_banner.dismiss": "o weka", + "dismissable_banner.explore_links": "ni li toki pi ijo sin ꞏ jan mute li pana e ni lon tenpo suno ni ꞏ sin la jan mute li pana la ni li kama suli", + "embed.preview": "ni li jo e sitelen ni:", + "emoji_button.activity": "musi", "emoji_button.flags": "len ma", "emoji_button.food": "moku", - "emoji_button.label": "o pana e Emosi", + "emoji_button.label": "o pana e sitelen pilin", "emoji_button.nature": "soweli en kasi", - "emoji_button.not_found": "sitelen Emosi ala li lon", + "emoji_button.not_found": "sitelen pilin ala li lon", "emoji_button.objects": "ijo", "emoji_button.people": "jan", - "emoji_button.search": "o alasa", + "emoji_button.search": "o alasa...", "emoji_button.search_results": "ijo pi alasa ni", "emoji_button.symbols": "sitelen", "emoji_button.travel": "ma en tawa", + "empty_column.account_hides_collections": "jan ni li wile len e sona ni", "empty_column.account_timeline": "toki ala li lon!", "empty_column.account_unavailable": "ken ala lukin e lipu jan", + "empty_column.blocks": "jan ala li weka tawa sina.", "empty_column.followed_tags": "sina alasa ala e toki ꞏ sina alasa e toki la toki li lon ni", "empty_column.hashtag": "ala li lon toki ni", - "empty_column.mutes": "jan ala la sina wile ala kute.", + "empty_column.mutes": "jan ala li len tawa sina.", + "errors.unexpected_crash.report_issue": "o toki e pakala tawa lawa", "explore.search_results": "ijo pi alasa ni", "explore.suggested_follows": "jan", "explore.title": "o alasa", @@ -138,52 +169,102 @@ "filter_modal.select_filter.expired": "tenpo pini", "filter_modal.select_filter.search": "o alasa anu pali", "firehose.all": "ale", - "firehose.local": "ilo ni", - "firehose.remote": "ilo ante", - "follow_request.authorize": "o sina kama", - "follow_request.reject": "o weka", + "firehose.local": "kulupu ni", + "firehose.remote": "kulupu ante", + "follow_request.authorize": "o ken", + "follow_request.reject": "o ala", "follow_suggestions.view_all": "o lukin e ale", + "follow_suggestions.who_to_follow": "sina o kute e ni", + "footer.get_app": "o jo e ilo", "footer.privacy_policy": "lawa len", "footer.source_code": "o lukin e toki ilo", "footer.status": "lon", + "generic.saved": "ni li awen", "hashtag.column_header.tag_mode.all": "en {additional}", "hashtag.column_header.tag_mode.any": "anu {additional}", + "hashtag.column_header.tag_mode.none": "en {additional} ala", "hashtag.column_settings.tag_mode.all": "ale ni", "hashtag.column_settings.tag_mode.any": "wan ni", "hashtag.column_settings.tag_mode.none": "ala ni", "home.pending_critical_update.link": "o lukin e ijo ilo sin", "interaction_modal.on_another_server": "lon ma ante", "interaction_modal.on_this_server": "lon ma ni", + "interaction_modal.title.favourite": "o suli e toki {name}", "interaction_modal.title.follow": "o kute e {name}", - "keyboard_shortcuts.muted": "sina wile ala kute e jan la o lukin e ona ale", - "keyboard_shortcuts.open_media": "o open e sitelen", - "keyboard_shortcuts.toggle_sensitivity": "sitelen la o len anu lukin", + "interaction_modal.title.reblog": "o wawa e toki {name}", + "keyboard_shortcuts.blocked": "o lukin e lipu sina pi jan weka", + "keyboard_shortcuts.down": "o tawa anpa lon lipu", + "keyboard_shortcuts.enter": "o lukin e toki", + "keyboard_shortcuts.favourite": "o suli e toki", + "keyboard_shortcuts.favourites": "o lukin e lipu sina pi toki suli", + "keyboard_shortcuts.muted": "o lukin e lipu sina pi jan len", + "keyboard_shortcuts.my_profile": "o lukin e lipu sina", + "keyboard_shortcuts.open_media": "o lukin e sitelen", + "keyboard_shortcuts.pinned": "o lukin pi lipu sina pi toki sewi", + "keyboard_shortcuts.toggle_sensitivity": "o ante e ken lukin", + "keyboard_shortcuts.up": "o tawa sewi lon lipu", "lightbox.close": "o pini", - "link_preview.author": "{name} li pali e ni", + "lightbox.compress": "o lili e sitelen", + "lightbox.expand": "o suli e sitelen", + "lightbox.next": "sinpin", + "lightbox.previous": "monsi", + "link_preview.author": "tan {name}", + "lists.account.add": "o pana tawa kulupu lipu", + "lists.account.remove": "o weka tan kulupu lipu", + "lists.delete": "o weka e kulupu lipu", + "lists.edit": "o ante e kulupu lipu", "lists.edit.submit": "o ante e nimi", + "lists.exclusive": "o len e toki lon lipu open", + "lists.new.create": "o sin e kulupu lipu", + "lists.replies_policy.followed": "jan kute ale", + "lists.replies_policy.list": "jan pi kulupu ni taso", "lists.replies_policy.none": "jan ala", + "lists.subheading": "kulupu lipu sina", + "load_pending": "{count, plural, other {ijo sin #}}", + "loading_indicator.label": "ni li kama…", + "media_gallery.toggle_visible": "{number, plural, other {o len e sitelen}}", "mute_modal.duration": "tenpo", "mute_modal.indefinite": "tenpo ale", - "navigation_bar.filters": "sina wile ala kute e nimi ni", + "navigation_bar.blocks": "jan weka", + "navigation_bar.compose": "o pali e toki sin", + "navigation_bar.favourites": "toki suli", + "navigation_bar.filters": "nimi len", + "navigation_bar.lists": "kulupu lipu", "navigation_bar.mutes": "sina wile ala kute e jan ni", - "notification.follow": "jan {name} li kama kute e sina", + "navigation_bar.pins": "toki sewi", + "navigation_bar.preferences": "wile sina", + "navigation_bar.search": "o alasa", + "notification.admin.sign_up": "{name} li kama", + "notification.favourite": "{name} li suli e toki sina", + "notification.follow": " {name} li kute e sina", "notification.follow_request": "{name} li wile kute e sina", "notification.mention": "jan {name} li toki e sina", + "notification.reblog": "{name} li wawa e toki sina", + "notification.status": "{name} li toki", + "notification.update": "{name} li ante e toki", "notifications.column_settings.follow": "jan kute sin", "notifications.filter.all": "ale", + "onboarding.compose.template": "toki a, #Mastodon o!", "onboarding.start.title": "sina o kama pona a!", - "privacy.public.short": "jan ale", + "poll.total_people": "{count, plural, other {jan #}}", + "privacy.public.short": "tawa ale", "relative_time.full.just_now": "tenpo ni", "relative_time.just_now": "tenpo ni", "relative_time.today": "tenpo suno ni", "report.block": "o weka e jan", "report.block_explanation": "sina kama lukin ala e toki ona. ona li kama ala ken lukin e toki sina li kama ala ken kute e sina. ona li ken sona e kama ni.", "report.category.title": "ike seme li lon {type} ni", + "report.category.title_account": "lipu", + "report.category.title_status": "toki", "report.close": "o pini", "report.mute": "o kute ala e ona", "report.mute_explanation": "sina kama ala lukin e ijo pana ona. ona li awen ken kute e sina li awen ken lukin e sina li sona ala e weka kute sina e weka lukin sina.", "report.reasons.dislike": "ni li ike tawa mi", + "report.reasons.legal": "ni li ike tawa lawa", + "report.reasons.other": "ni li ike tan ante", + "report.reasons.spam": "ni li ike tan toki mute", "report.thanks.title": "sina wile ala lukin e ni anu seme?", + "report.unfollow": "o pini kute e {name}", "search.placeholder": "o alasa", "search.quick_action.go_to_account": "o tawa lipu jan {x}", "search_popout.language_code": "nimi toki kepeken nasin ISO", @@ -196,27 +277,40 @@ "status.edit": "o ante", "status.edited": "ni li ante lon {date}", "status.embed": "ni o lon insa pi lipu ante", + "status.favourite": "o suli", + "status.hide": "o len", "status.history.created": "{name} li pali e ni lon {date}", "status.history.edited": "{name} li ante lon {date}", "status.load_more": "o kama e ijo ante", "status.media.open": "o open", "status.media.show": "o lukin", "status.media_hidden": "sitelen li len", - "status.mute": "o kute ala e @{name}", + "status.mute": "o len e @{name}", "status.mute_conversation": "o kute ala e ijo pi toki ni", + "status.pin": "o sewi lon lipu sina", + "status.pinned": "toki sewi", + "status.reblog": "o wawa", + "status.share": "o pana tawa ante", "status.show_less": "o lili e ni", "status.show_less_all": "o lili e ale", "status.show_more": "o suli e ni", "status.show_more_all": "o suli e ale", - "status.show_original": "ijo mama pi ijo ni li seme", + "status.show_original": "o lukin e mama", + "status.translate": "o ante pi nasin toki", + "status.translated_from_with": "toki li ante tan {lang} kepeken {provider}", "status.uncached_media_warning": "lukin lili li weka", "status.unmute_conversation": "o ken kute e ijo pi toki ni", + "status.unpin": "o sewi ala lon lipu sina", + "subscribed_languages.save": "o awen e ante", + "tabs_bar.home": "lipu open", "timeline_hint.resources.statuses": "ijo pi tenpo suli", "units.short.million": "{count}AAA", + "upload_button.label": "o pana e sitelen anu kalama", "upload_error.limit": "ilo li ken ala e suli pi ijo ni.", "upload_form.audio_description": "o toki e ijo kute tawa jan pi kute ala, tawa jan pi kute lili", "upload_form.description": "o toki e ijo lukin tawa jan pi lukin ala, tawa jan pi lukin lili", "upload_form.edit": "o ante", + "upload_form.thumbnail": "o ante e sitelen lili", "upload_form.video_description": "o toki e ijo kute tawa jan pi kute ala, tawa jan pi kute lili, e ijo lukin tawa jan pi lukin ala, tawa jan pi lukin lili", "upload_modal.choose_image": "o wile e sitelen", "upload_modal.description_placeholder": "mi pu jaki tan soweli", @@ -225,7 +319,12 @@ "upload_modal.preparing_ocr": "ilo li open e alasa nimi lon sitelen…", "upload_progress.label": "ilo li kama jo e ijo sina...", "upload_progress.processing": "ilo li pali…", - "username.taken": "jan ante li jo e nimi ni. sina o pali e nimi sin.", + "username.taken": "jan ante li kepeken e nimi ni. sina o kepeken e nimi sin", + "video.close": "o weka e ni", + "video.download": "o jo e ni", + "video.exit_fullscreen": "o weka tan sitelen suli", + "video.expand": "o suli e ni", + "video.hide": "o len e sitelen", "video.mute": "o kalama ala", "video.pause": "o lape e ni", "video.unmute": "o kalama" diff --git a/config/locales/activerecord.tok.yml b/config/locales/activerecord.tok.yml index 5623538ba9..9862a7f953 100644 --- a/config/locales/activerecord.tok.yml +++ b/config/locales/activerecord.tok.yml @@ -4,3 +4,11 @@ tok: attributes: poll: expires_at: pini tenpo + user/account: + username: nimi jan + errors: + models: + account: + attributes: + username: + reserved: jan ante li jo e nimi ni diff --git a/config/locales/doorkeeper.tok.yml b/config/locales/doorkeeper.tok.yml index d15ecd21b2..6aef4fb34b 100644 --- a/config/locales/doorkeeper.tok.yml +++ b/config/locales/doorkeeper.tok.yml @@ -1 +1,51 @@ +--- tok: + doorkeeper: + applications: + buttons: + cancel: o pini + destroy: o weka + edit: o ante + submit: o awen + confirmations: + destroy: ni li pona ala pona? + edit: + title: o ante e ilo nanpa + form: + error: 'pakala a! o lukin e ni: lipu sina li jo ala jo e pakala.' + index: + delete: o weka + empty: sina li jo e ilo nanpa ala. + name: nimi + new: o pali e ilo nanpa sin + title: ilo nanpa sina + new: + title: o pali e ilo nanpa sin + show: + title: ilo nanpa pi nimi %{name} + authorizations: + error: + title: pakala li lon. + authorized_applications: + confirmations: + revoke: ni li pona ala pona? + index: + scopes: ken + errors: + messages: + invalid_request: + missing_param: o pana e sona "%{value}". + flash: + applications: + create: + notice: sina pali e ilo nanpa. + destroy: + notice: sina weka e ilo nanpa. + update: + notice: sina ante e ilo nanpa. + authorized_applications: + destroy: + notice: sina weka e ilo nanpa tawa sina. + grouped_scopes: + access: + read: lukin taso diff --git a/config/locales/simple_form.tok.yml b/config/locales/simple_form.tok.yml index 1eb7d5be87..37b0ee765a 100644 --- a/config/locales/simple_form.tok.yml +++ b/config/locales/simple_form.tok.yml @@ -5,8 +5,8 @@ tok: account: display_name: nimi sina ale anu nimi sina musi. defaults: - setting_display_media_hide_all: tenpo ale la, o weka e sitelen - setting_display_media_show_all: tenpo ale la, o awen e sitelen + setting_display_media_hide_all: sitelen ale li len + setting_display_media_show_all: sitelen ale li len ala labels: defaults: expires_in: ona o moli lon diff --git a/config/locales/sk.yml b/config/locales/sk.yml index f13a15d795..88617967ff 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -88,7 +88,7 @@ sk: remote: Federované title: Umiestnenie login_status: Stav prihlásenia - media_attachments: Prílohy + media_attachments: Mediálne prílohy memorialize: Zmeň na "Navždy budeme spomínať" memorialized: Spomienka na memorialized_msg: Úspešne zmenené %{username} na spomienkové konto diff --git a/config/locales/tok.yml b/config/locales/tok.yml index d15ecd21b2..9f962d2b53 100644 --- a/config/locales/tok.yml +++ b/config/locales/tok.yml @@ -1 +1,5 @@ +--- tok: + admin: + accounts: + are_you_sure: ni li pona ala pona? From 8125dae5a84e3115be6f487b337ac942c70a81f0 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 12 Feb 2024 10:54:06 +0100 Subject: [PATCH 22/63] Rename `ES_CA_CERT` to `ES_CA_FILE` for consistency (#29147) --- config/initializers/chewy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/chewy.rb b/config/initializers/chewy.rb index 0fb311dbb3..0d9fc75e99 100644 --- a/config/initializers/chewy.rb +++ b/config/initializers/chewy.rb @@ -7,7 +7,7 @@ user = ENV.fetch('ES_USER', nil).presence password = ENV.fetch('ES_PASS', nil).presence fallback_prefix = ENV.fetch('REDIS_NAMESPACE', nil).presence prefix = ENV.fetch('ES_PREFIX') { fallback_prefix } -ca_file = ENV.fetch('ES_CA_CERT', nil).presence +ca_file = ENV.fetch('ES_CA_FILE', nil).presence transport_options = { ssl: { ca_file: ca_file } } if ca_file.present? From 6482948547beb35ecd5ad583a49e2c47c35cb0dd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 09:59:05 +0000 Subject: [PATCH 23/63] New Crowdin Translations (automated) (#29156) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/be.json | 4 ++-- app/javascript/mastodon/locales/bg.json | 12 ++++++------ app/javascript/mastodon/locales/ca.json | 2 +- app/javascript/mastodon/locales/de.json | 12 ++++++------ app/javascript/mastodon/locales/ia.json | 8 ++++++++ app/javascript/mastodon/locales/sv.json | 1 + app/javascript/mastodon/locales/tok.json | 6 ++++-- config/locales/ca.yml | 2 +- config/locales/devise.ia.yml | 2 ++ config/locales/devise.ro.yml | 9 +++++++++ config/locales/doorkeeper.ia.yml | 1 + config/locales/ia.yml | 3 +++ config/locales/simple_form.bg.yml | 2 +- config/locales/simple_form.ia.yml | 1 + config/locales/simple_form.zh-TW.yml | 4 ++-- config/locales/sk.yml | 4 +++- 16 files changed, 51 insertions(+), 22 deletions(-) diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index daff6563e8..7e21703b4a 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -152,8 +152,8 @@ "compose_form.poll.switch_to_multiple": "Змяніце апытанне, каб дазволіць некалькі варыянтаў адказу", "compose_form.poll.switch_to_single": "Змяніце апытанне, каб дазволіць адзіны варыянт адказу", "compose_form.poll.type": "Стыль", - "compose_form.publish": "Допіс", - "compose_form.publish_form": "Апублікаваць", + "compose_form.publish": "Даслаць", + "compose_form.publish_form": "Новы допіс", "compose_form.reply": "Адказаць", "compose_form.save_changes": "Абнавіць", "compose_form.spoiler.marked": "Выдаліць папярэджанне аб змесціве", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 99c0f8b102..95572a7932 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -3,7 +3,7 @@ "about.contact": "За контакти:", "about.disclaimer": "Mastodon е безплатен софтуер с отворен изходен код и търговска марка на Mastodon gGmbH.", "about.domain_blocks.no_reason_available": "Няма налична причина", - "about.domain_blocks.preamble": "Mastodon обикновено позволява да разглеждате съдържание и да взаимодействате с други потребители от всякакви сървъри във Федивърс. Има изключения, направени конкретно за този сървър.", + "about.domain_blocks.preamble": "Mastodon обикновено позволява да разглеждате съдържание и да взаимодействате с други потребители от всякакви сървъри във Федивселената. Има изключения, направени конкретно за този сървър.", "about.domain_blocks.silenced.explanation": "Обикновено няма да виждате профили и съдържание, освен ако изрично не го потърсите или се включете в него, следвайки го.", "about.domain_blocks.silenced.title": "Ограничено", "about.domain_blocks.suspended.explanation": "Никакви данни от този сървър няма да се обработват, съхраняват или обменят, правещи невъзможно всяко взаимодействие или комуникация с потребители от тези сървъри.", @@ -110,7 +110,7 @@ "column.about": "Относно", "column.blocks": "Блокирани потребители", "column.bookmarks": "Отметки", - "column.community": "Локална часова ос", + "column.community": "Локален инфопоток", "column.direct": "Частни споменавания", "column.directory": "Разглеждане на профили", "column.domain_blocks": "Блокирани домейни", @@ -228,7 +228,7 @@ "empty_column.account_unavailable": "Профилът не е наличен", "empty_column.blocks": "Още не сте блокирали никакви потребители.", "empty_column.bookmarked_statuses": "Още не сте отметнали публикации. Отметвайки някоя, то тя ще се покаже тук.", - "empty_column.community": "Местната часова ос е празна. Напишете нещо обществено, за да завъртите нещата!", + "empty_column.community": "Локалният инфопоток е празен. Публикувайте нещо, за да започнете!", "empty_column.direct": "Още нямате никакви частни споменавания. Тук ще се показват, изпращайки или получавайки едно.", "empty_column.domain_blocks": "Още няма блокирани домейни.", "empty_column.explore_statuses": "Няма нищо налагащо се в момента. Проверете пак по-късно!", @@ -348,10 +348,10 @@ "keyboard_shortcuts.favourites": "Отваряне на списъка с любими", "keyboard_shortcuts.federated": "Отваряне на федерирания инфопоток", "keyboard_shortcuts.heading": "Клавишни съчетания", - "keyboard_shortcuts.home": "Отваряне на началната часова ос", + "keyboard_shortcuts.home": "Отваряне на личния инфопоток", "keyboard_shortcuts.hotkey": "Бърз клавиш", "keyboard_shortcuts.legend": "Показване на тази легенда", - "keyboard_shortcuts.local": "Отваряне на местна часова ос", + "keyboard_shortcuts.local": "Отваряне на локалния инфопоток", "keyboard_shortcuts.mention": "Споменаване на автора", "keyboard_shortcuts.muted": "Отваряне на списъка със заглушени потребители", "keyboard_shortcuts.my_profile": "Отваряне на профила ви", @@ -402,7 +402,7 @@ "navigation_bar.advanced_interface": "Отваряне в разширен уебинтерфейс", "navigation_bar.blocks": "Блокирани потребители", "navigation_bar.bookmarks": "Отметки", - "navigation_bar.community_timeline": "Локална часова ос", + "navigation_bar.community_timeline": "Локален инфопоток", "navigation_bar.compose": "Съставяне на нова публикация", "navigation_bar.direct": "Частни споменавания", "navigation_bar.discover": "Откриване", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 0ae471e023..42de594cdc 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -532,7 +532,7 @@ "privacy.public.short": "Públic", "privacy.unlisted.additional": "Es comporta igual que públic, excepte que la publicació no apareixerà als canals en directe o etiquetes, l'explora o a la cerca de Mastodon, fins i tot si ho heu activat a nivell de compte.", "privacy.unlisted.long": "Menys fanfàrries algorísmiques", - "privacy.unlisted.short": "Públic tranquil", + "privacy.unlisted.short": "Públic silenciós", "privacy_policy.last_updated": "Darrera actualització {date}", "privacy_policy.title": "Política de Privacitat", "recommended": "Recomanat", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index cb90252c7f..f29d016b07 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -146,12 +146,12 @@ "compose_form.lock_disclaimer.lock": "geschützt", "compose_form.placeholder": "Was gibt’s Neues?", "compose_form.poll.duration": "Umfragedauer", - "compose_form.poll.multiple": "Mehrfachauswahl", - "compose_form.poll.option_placeholder": "{number}. Auswahlmöglichkeit", + "compose_form.poll.multiple": "Mul­ti­ple-Choice", + "compose_form.poll.option_placeholder": "Option {number}", "compose_form.poll.single": "Einfachauswahl", "compose_form.poll.switch_to_multiple": "Mehrfachauswahl erlauben", "compose_form.poll.switch_to_single": "Nur Einfachauswahl erlauben", - "compose_form.poll.type": "Art", + "compose_form.poll.type": "Stil", "compose_form.publish": "Veröffentlichen", "compose_form.publish_form": "Neuer Beitrag", "compose_form.reply": "Antworten", @@ -277,9 +277,9 @@ "follow_request.authorize": "Genehmigen", "follow_request.reject": "Ablehnen", "follow_requests.unlocked_explanation": "Auch wenn dein Konto öffentlich bzw. nicht geschützt ist, haben die Moderator*innen von {domain} gedacht, dass du diesen Follower lieber manuell bestätigen solltest.", - "follow_suggestions.curated_suggestion": "Vom Server empfohlen", + "follow_suggestions.curated_suggestion": "Auswahl des Herausgebers", "follow_suggestions.dismiss": "Nicht mehr anzeigen", - "follow_suggestions.personalized_suggestion": "Personalisierte Empfehlung", + "follow_suggestions.personalized_suggestion": "Persönliche Empfehlung", "follow_suggestions.popular_suggestion": "Beliebte Empfehlung", "follow_suggestions.view_all": "Alle anzeigen", "follow_suggestions.who_to_follow": "Empfohlene Profile", @@ -528,7 +528,7 @@ "privacy.direct.short": "Bestimmte Profile", "privacy.private.long": "Nur deine Follower", "privacy.private.short": "Follower", - "privacy.public.long": "Alle auf und außerhalb von Mastodon", + "privacy.public.long": "Alle in und außerhalb von Mastodon", "privacy.public.short": "Öffentlich", "privacy.unlisted.additional": "Das Verhalten ist wie bei „Öffentlich“, jedoch erscheint dieser Beitrag nicht in „Live-Feeds“, „Erkunden“, Hashtags oder über die Mastodon-Suchfunktion – selbst wenn du das in den Einstellungen aktiviert hast.", "privacy.unlisted.long": "Weniger im Algorithmus berücksichtigt", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 10328efd0e..0796662851 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -2,8 +2,10 @@ "about.blocks": "Servitores moderate", "about.contact": "Contacto:", "about.disclaimer": "Mastodon es software libere, de codice aperte, e un marca de Mastodon gGmbH.", + "about.domain_blocks.no_reason_available": "Ration non disponibile", "about.domain_blocks.silenced.title": "Limitate", "about.domain_blocks.suspended.title": "Suspendite", + "about.not_available": "Iste information non faceva disponibile in iste servitor.", "about.rules": "Regulas del servitor", "account.account_note_header": "Nota", "account.add_or_remove_from_list": "Adder o remover ab listas", @@ -153,6 +155,7 @@ "disabled_account_banner.account_settings": "Parametros de conto", "disabled_account_banner.text": "Tu conto {disabledAccount} es actualmente disactivate.", "dismissable_banner.dismiss": "Dimitter", + "embed.preview": "Hic es como il parera:", "emoji_button.activity": "Activitate", "emoji_button.clear": "Rader", "emoji_button.custom": "Personalisate", @@ -171,6 +174,11 @@ "empty_column.account_timeline": "Nulle messages hic!", "empty_column.account_unavailable": "Profilo non disponibile", "empty_column.blocks": "Tu non ha blocate alcun usator ancora.", + "empty_column.domain_blocks": "Il non ha dominios blocate ancora.", + "empty_column.explore_statuses": "Nihil es in tendentias ora mesme. Retorna postea!", + "empty_column.favourited_statuses": "Tu non ha necun messages favorite ancora. Quando tu marca un como favorito, ille essera monstrate hic.", + "empty_column.followed_tags": "Tu ancora non ha sequite necun hashtags. Quando tu lo face, illes essera monstrate hic.", + "empty_column.hashtag": "Ancora non il ha nihil in iste hashtag.", "errors.unexpected_crash.report_issue": "Signalar un defecto", "explore.search_results": "Resultatos de recerca", "explore.suggested_follows": "Personas", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index f9356fd279..4a15c60ed8 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -148,6 +148,7 @@ "compose_form.poll.duration": "Varaktighet för omröstning", "compose_form.poll.multiple": "Flera val", "compose_form.poll.option_placeholder": "Alternativ {number}", + "compose_form.poll.single": "Välj en", "compose_form.poll.switch_to_multiple": "Ändra enkät för att tillåta flera val", "compose_form.poll.switch_to_single": "Ändra enkät för att tillåta ett enda val", "compose_form.poll.type": "Stil", diff --git a/app/javascript/mastodon/locales/tok.json b/app/javascript/mastodon/locales/tok.json index 7270d52067..ba45f84453 100644 --- a/app/javascript/mastodon/locales/tok.json +++ b/app/javascript/mastodon/locales/tok.json @@ -11,12 +11,12 @@ "account.block": "o weka e @{name}", "account.block_domain": "o weka e ma {domain}", "account.block_short": "o weka e jan tawa mi", - "account.blocked": "jan ni li weka tawa mi", + "account.blocked": "jan li weka tawa mi", "account.browse_more_on_origin_server": "sina tawa ma tan pi jan ni la sina ken lukin e mute", "account.cancel_follow_request": "o pini kute", "account.copy": "o pali same e linja pi lipu jan", "account.direct": "len la o mu e @{name}", - "account.disable_notifications": "@{name} li toki la o toki ala e toki ona tawa mi", + "account.disable_notifications": "@{name} li toki la o mu ala e mi", "account.domain_blocked": "ma ni li weka tawa sina", "account.edit_profile": "o ante e lipu mi", "account.enable_notifications": "@{name} li toki la o toki e toki ona tawa mi", @@ -92,6 +92,7 @@ "compose.published.open": "o lukin", "compose.saved.body": "ilo li awen e ijo pana sina.", "compose_form.direct_message_warning_learn_more": "o kama sona e ijo ante", + "compose_form.encryption_warning": "toki li len ala lon ilo Masoton ꞏ o pana ala e sona suli len lon ilo Masoton", "compose_form.placeholder": "sina wile toki e seme?", "compose_form.poll.duration": "tenpo pana", "compose_form.poll.multiple": "pana mute", @@ -117,6 +118,7 @@ "confirmations.discard_edit_media.confirm": "o weka", "confirmations.discard_edit_media.message": "toki sitelen anu lukin lili sitelen la ante pi awen ala li lon. sina wile weka e ante ni?", "confirmations.domain_block.confirm": "o weka.", + "confirmations.domain_block.message": "sina wile ala a wile a len e ma {domain} ꞏ ken suli la len jan taso li pona ꞏ len pi ma ni la sina ken ala lukin e ijo pi ma ni lon lipu toki ale anu lukin toki ꞏ len ni la jan kute sina pi ma ni li weka", "confirmations.edit.confirm": "o ante", "confirmations.logout.confirm": "o weka", "confirmations.logout.message": "sina wile ala wile weka", diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 58f6e26374..f79d63a459 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -1548,7 +1548,7 @@ ca: unrecognized_emoji: no és un emoji reconegut redirects: prompt: Si confieu en aquest enllaç, feu-hi clic per a continuar. - title: Esteu sortint de %{instance}. + title: Deixeu %{instance}. relationships: activity: Activitat del compte confirm_follow_selected_followers: Segur que vols seguir els seguidors seleccionats? diff --git a/config/locales/devise.ia.yml b/config/locales/devise.ia.yml index c07e75feff..4b4d1f441b 100644 --- a/config/locales/devise.ia.yml +++ b/config/locales/devise.ia.yml @@ -39,6 +39,8 @@ ia: webauthn_enabled: title: Claves de securitate activate registrations: + destroyed: A revider! Tu conto esseva cancellate con successo. Nos spera vider te novemente tosto. + signed_up_but_pending: Un message con un ligamine de confirmation esseva inviate a tu conto de email. Post que tu clicca le ligamine, nos revidera tu application. Tu essera notificate si illo es approbate. updated: Tu conto ha essite actualisate con successo. unlocks: unlocked: Tu conto ha essite disblocate con successo. Initia session a continuar. diff --git a/config/locales/devise.ro.yml b/config/locales/devise.ro.yml index 1a6a3ecd77..868bb4b3a1 100644 --- a/config/locales/devise.ro.yml +++ b/config/locales/devise.ro.yml @@ -47,14 +47,19 @@ ro: subject: Instrucțiuni pentru resetarea parolei title: Resetare parolă two_factor_disabled: + explanation: Conectarea este acum posibilă folosind doar adresa de e-mail și parola. subject: Autentificare cu doi factori dezactivată + subtitle: Autentificarea cu doi factori pentru contul dvs. a fost dezactivată. title: 2FA dezactivat two_factor_enabled: + explanation: Pentru autentificare va fi necesar un token generat de aplicația TOTP asociată. subject: Autentificare în doi pași activată + subtitle: Autentificarea cu doi factori a fost activată pentru contul dvs. title: 2FA activat two_factor_recovery_codes_changed: explanation: Codurile anterioare de recuperare au fost invalidate și unele noi generate. subject: Recuperare în doi factori + subtitle: Codurile de recuperare anterioare au fost invalidate și s-au generat altele noi. title: Coduri de recuperare 2FA modificate unlock_instructions: subject: Instrucțiuni de deblocare @@ -68,9 +73,13 @@ ro: subject: 'Mastodon: Cheie de securitate ștearsă' title: Una dintre cheile tale de securitate a fost ștearsă webauthn_disabled: + explanation: Autentificarea cu chei de securitate a fost dezactivată pentru contul dvs. + extra: Conectarea este acum posibilă folosind doar token-ul generat de aplicația TOTP asociată. subject: 'Mastodon: Autentificarea cu chei de securitate dezactivată' title: Chei de securitate dezactivate webauthn_enabled: + explanation: Autentificarea cu cheie de securitate a fost activată pentru contul dvs. + extra: Cheia ta de securitate poate fi acum folosită pentru conectare. subject: 'Mastodon: Autentificarea cheii de securitate activată' title: Chei de securitate activate omniauth_callbacks: diff --git a/config/locales/doorkeeper.ia.yml b/config/locales/doorkeeper.ia.yml index e7e6f03cdb..443342b404 100644 --- a/config/locales/doorkeeper.ia.yml +++ b/config/locales/doorkeeper.ia.yml @@ -34,6 +34,7 @@ ia: confirmations: revoke: Es tu secur? index: + last_used_at: Ultime uso in %{date} never_used: Nunquam usate scopes: Permissiones title: Tu applicationes autorisate diff --git a/config/locales/ia.yml b/config/locales/ia.yml index bf7da9a314..a85af012f3 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -236,6 +236,8 @@ ia: migrations: errors: not_found: non poterea esser trovate + preferences: + public_timelines: Chronologias public statuses_cleanup: min_age: '1209600': 2 septimanas @@ -254,6 +256,7 @@ ia: disable: Disactivar 2FA user_mailer: welcome: + final_step: 'Comencia a publicar! Mesmo sin sequitores, tu messages public poterea esser reguardate per alteres, per exemplo in le chronologia local o in hashtags. Tu poterea voler introducer te con le hashtag #introductiones.' subject: Benvenite in Mastodon webauthn_credentials: delete: Deler diff --git a/config/locales/simple_form.bg.yml b/config/locales/simple_form.bg.yml index 68e45ef47b..a4637a6810 100644 --- a/config/locales/simple_form.bg.yml +++ b/config/locales/simple_form.bg.yml @@ -261,7 +261,7 @@ bg: status_page_url: URL адрес на страница със състоянието theme: Стандартна тема thumbnail: Образче на сървъра - timeline_preview: Позволяване на неупълномощен достъп до публични часови оси + timeline_preview: Позволяване на неудостоверен достъп до публични инфопотоци trendable_by_default: Без преглед на налагащото се trends: Включване на налагащи се trends_as_landing_page: Употреба на налагащото се като целева страница diff --git a/config/locales/simple_form.ia.yml b/config/locales/simple_form.ia.yml index 552abb2550..af198d932a 100644 --- a/config/locales/simple_form.ia.yml +++ b/config/locales/simple_form.ia.yml @@ -26,6 +26,7 @@ ia: username: Nomine de usator username_or_email: Nomine de usator o e-mail form_admin_settings: + bootstrap_timeline_accounts: Recommenda sempre iste contos a nove usatores custom_css: CSS personalisate profile_directory: Activar directorio de profilos site_contact_email: Adresse de e-mail de contacto diff --git a/config/locales/simple_form.zh-TW.yml b/config/locales/simple_form.zh-TW.yml index a31ad5eb11..696fd5fed9 100644 --- a/config/locales/simple_form.zh-TW.yml +++ b/config/locales/simple_form.zh-TW.yml @@ -200,12 +200,12 @@ zh-TW: password: 密碼 phrase: 關鍵字或片語 setting_advanced_layout: 啟用進階網頁介面 - setting_aggregate_reblogs: 時間軸中的群組轉嘟 + setting_aggregate_reblogs: 於時間軸中不重複顯示轉嘟 setting_always_send_emails: 總是發送電子郵件通知 setting_auto_play_gif: 自動播放 GIF 動畫 setting_boost_modal: 轉嘟前先詢問我 setting_default_language: 嘟文語言 - setting_default_privacy: 嘟文可見範圍 + setting_default_privacy: 嘟文隱私設定 setting_default_sensitive: 總是將媒體標記為敏感內容 setting_delete_modal: 刪除嘟文前先詢問我 setting_disable_swiping: 停用滑動手勢 diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 88617967ff..520b64f886 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -251,14 +251,16 @@ sk: enable_user_html: "%{name} povolil/a prihlásenie pre používateľa %{target}" memorialize_account_html: "%{name} zmenil/a účet %{target} na pamätnú stránku" reject_appeal_html: "%{name} zamietol/la námietku moderovacieho rozhodnutia od %{target}" + remove_avatar_user_html: "%{name} vymazal/a %{target}/ov/in avatar" reopen_report_html: "%{name} znovu otvoril/a nahlásenie %{target}" resend_user_html: "%{name} znovu odoslal/a potvrdzovací email pre %{target}" reset_password_user_html: "%{name} resetoval/a heslo používateľa %{target}" resolve_report_html: "%{name} vyriešil/a nahlásenie %{target}" - sensitive_account_html: "%{name} označil médium od %{target} za chúlostivé" + sensitive_account_html: "%{name} označil/a médium od %{target} za chúlostivé" silence_account_html: "%{name} obmedzil/a účet %{target}" suspend_account_html: "%{name} zablokoval/a účet používateľa %{target}" unassigned_report_html: "%{name} odobral/a report od %{target}" + unsensitive_account_html: "%{name} odznačil/a médium od %{target} ako chúlostivé" unsuspend_account_html: "%{name} spojazdnil/a účet %{target}" update_announcement_html: "%{name} aktualizoval/a oboznámenie %{target}" update_custom_emoji_html: "%{name} aktualizoval/a emotikonu %{target}" From 58918844a90b9a3f5bd39d3ed525f7bcbe02ef32 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 11:20:54 +0100 Subject: [PATCH 24/63] Update peter-evans/create-pull-request action to v6 (#29167) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/crowdin-download.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crowdin-download.yml b/.github/workflows/crowdin-download.yml index d3988d2f1a..a676ff12fc 100644 --- a/.github/workflows/crowdin-download.yml +++ b/.github/workflows/crowdin-download.yml @@ -52,7 +52,7 @@ jobs: # Create or update the pull request - name: Create Pull Request - uses: peter-evans/create-pull-request@v5.0.2 + uses: peter-evans/create-pull-request@v6.0.0 with: commit-message: 'New Crowdin translations' title: 'New Crowdin Translations (automated)' From cf0d6bef8b62acd8f4594f56e9096817149a6135 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 11:21:17 +0100 Subject: [PATCH 25/63] Update eslint (non-major) (#29166) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 122 +++++++++++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/yarn.lock b/yarn.lock index fb34729048..351fd31ab4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1697,14 +1697,14 @@ __metadata: languageName: node linkType: hard -"@es-joy/jsdoccomment@npm:~0.41.0": - version: 0.41.0 - resolution: "@es-joy/jsdoccomment@npm:0.41.0" +"@es-joy/jsdoccomment@npm:~0.42.0": + version: 0.42.0 + resolution: "@es-joy/jsdoccomment@npm:0.42.0" dependencies: comment-parser: "npm:1.4.1" esquery: "npm:^1.5.0" jsdoc-type-pratt-parser: "npm:~4.0.0" - checksum: 1fa27531eba32e4699664da53a0865aeeda1f7e83ac156fe53b7a6b09d2f3816baa94a34845ff019c10289b09572bda5519ec917e3e241088975477fa880f72d + checksum: a8122762d2df3c6501a9c459e2822315a23c0078c4aeb0b40fb3c84b99e21a78e85e67f962d6b5dde5eb751792a1c67c6a170b619573db7151098a19950abe35 languageName: node linkType: hard @@ -3663,14 +3663,14 @@ __metadata: linkType: hard "@typescript-eslint/eslint-plugin@npm:^6.0.0": - version: 6.20.0 - resolution: "@typescript-eslint/eslint-plugin@npm:6.20.0" + version: 6.21.0 + resolution: "@typescript-eslint/eslint-plugin@npm:6.21.0" dependencies: "@eslint-community/regexpp": "npm:^4.5.1" - "@typescript-eslint/scope-manager": "npm:6.20.0" - "@typescript-eslint/type-utils": "npm:6.20.0" - "@typescript-eslint/utils": "npm:6.20.0" - "@typescript-eslint/visitor-keys": "npm:6.20.0" + "@typescript-eslint/scope-manager": "npm:6.21.0" + "@typescript-eslint/type-utils": "npm:6.21.0" + "@typescript-eslint/utils": "npm:6.21.0" + "@typescript-eslint/visitor-keys": "npm:6.21.0" debug: "npm:^4.3.4" graphemer: "npm:^1.4.0" ignore: "npm:^5.2.4" @@ -3683,44 +3683,44 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 5020faac39be476de056342f58f2bf68bb788f230e2fa4a2e27ceab8a5187dc450beba7333b0aa741a43aeaff45a117558132953f9390b5eca4c2cc004fde716 + checksum: f911a79ee64d642f814a3b6cdb0d324b5f45d9ef955c5033e78903f626b7239b4aa773e464a38c3e667519066169d983538f2bf8e5d00228af587c9d438fb344 languageName: node linkType: hard "@typescript-eslint/parser@npm:^6.17.0": - version: 6.20.0 - resolution: "@typescript-eslint/parser@npm:6.20.0" + version: 6.21.0 + resolution: "@typescript-eslint/parser@npm:6.21.0" dependencies: - "@typescript-eslint/scope-manager": "npm:6.20.0" - "@typescript-eslint/types": "npm:6.20.0" - "@typescript-eslint/typescript-estree": "npm:6.20.0" - "@typescript-eslint/visitor-keys": "npm:6.20.0" + "@typescript-eslint/scope-manager": "npm:6.21.0" + "@typescript-eslint/types": "npm:6.21.0" + "@typescript-eslint/typescript-estree": "npm:6.21.0" + "@typescript-eslint/visitor-keys": "npm:6.21.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: d84ad5e2282b1096c80dedb903c83ecc31eaf7be1aafcb14c18d9ec2d4a319f2fd1e5a9038b944d9f42c36c1c57add5e4292d4026ca7d3d5441d41286700d402 + checksum: a8f99820679decd0d115c0af61903fb1de3b1b5bec412dc72b67670bf636de77ab07f2a68ee65d6da7976039bbf636907f9d5ca546db3f0b98a31ffbc225bc7d languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:6.20.0": - version: 6.20.0 - resolution: "@typescript-eslint/scope-manager@npm:6.20.0" +"@typescript-eslint/scope-manager@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/scope-manager@npm:6.21.0" dependencies: - "@typescript-eslint/types": "npm:6.20.0" - "@typescript-eslint/visitor-keys": "npm:6.20.0" - checksum: f6768ed2dcd2d1771d55ed567ff392a6569ffd683a26500067509dd41769f8838c43686460fe7337144f324fd063df33f5d5646d44e5df4998ceffb3ad1fb790 + "@typescript-eslint/types": "npm:6.21.0" + "@typescript-eslint/visitor-keys": "npm:6.21.0" + checksum: eaf868938d811cbbea33e97e44ba7050d2b6892202cea6a9622c486b85ab1cf801979edf78036179a8ba4ac26f1dfdf7fcc83a68c1ff66be0b3a8e9a9989b526 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:6.20.0": - version: 6.20.0 - resolution: "@typescript-eslint/type-utils@npm:6.20.0" +"@typescript-eslint/type-utils@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/type-utils@npm:6.21.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:6.20.0" - "@typescript-eslint/utils": "npm:6.20.0" + "@typescript-eslint/typescript-estree": "npm:6.21.0" + "@typescript-eslint/utils": "npm:6.21.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.0.1" peerDependencies: @@ -3728,23 +3728,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 8f622fbb14268f1d00b2948f995b570f0ef82be02c12be41d90385290a56ea0dbd34d855d6a5aff100b57f3bdd300ff0c300f16c78f12d6064f7ae6e34fd71bf + checksum: 7409c97d1c4a4386b488962739c4f1b5b04dc60cf51f8cd88e6b12541f84d84c6b8b67e491a147a2c95f9ec486539bf4519fb9d418411aef6537b9c156468117 languageName: node linkType: hard -"@typescript-eslint/types@npm:6.20.0": - version: 6.20.0 - resolution: "@typescript-eslint/types@npm:6.20.0" - checksum: 37589003b0e06f83c1945e3748e91af85918cfd997766894642a08e6f355f611cfe11df4e7632dda96e3a9b3441406283fe834ab0906cf81ea97fd43ca2aebe3 +"@typescript-eslint/types@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/types@npm:6.21.0" + checksum: 020631d3223bbcff8a0da3efbdf058220a8f48a3de221563996ad1dcc30d6c08dadc3f7608cc08830d21c0d565efd2db19b557b9528921c78aabb605eef2d74d languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:6.20.0": - version: 6.20.0 - resolution: "@typescript-eslint/typescript-estree@npm:6.20.0" +"@typescript-eslint/typescript-estree@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/typescript-estree@npm:6.21.0" dependencies: - "@typescript-eslint/types": "npm:6.20.0" - "@typescript-eslint/visitor-keys": "npm:6.20.0" + "@typescript-eslint/types": "npm:6.21.0" + "@typescript-eslint/visitor-keys": "npm:6.21.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -3754,34 +3754,34 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 551f13445a303882d9fc0fbe14ef8507eb8414253fd87a5f13d2e324b5280b626421a238b8ec038e628bc80128dc06c057757f668738e82e64d5b39a9083c27d + checksum: af1438c60f080045ebb330155a8c9bb90db345d5069cdd5d01b67de502abb7449d6c75500519df829f913a6b3f490ade3e8215279b6bdc63d0fb0ae61034df5f languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.20.0, @typescript-eslint/utils@npm:^6.18.1": - version: 6.20.0 - resolution: "@typescript-eslint/utils@npm:6.20.0" +"@typescript-eslint/utils@npm:6.21.0, @typescript-eslint/utils@npm:^6.18.1": + version: 6.21.0 + resolution: "@typescript-eslint/utils@npm:6.21.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.20.0" - "@typescript-eslint/types": "npm:6.20.0" - "@typescript-eslint/typescript-estree": "npm:6.20.0" + "@typescript-eslint/scope-manager": "npm:6.21.0" + "@typescript-eslint/types": "npm:6.21.0" + "@typescript-eslint/typescript-estree": "npm:6.21.0" semver: "npm:^7.5.4" peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: 0a8ede3d80a365b52ae96d88e4a9f6e6abf3569c6b60ff9f42ff900cd843ae7c5493cd95f8f2029d90bb0acbf31030980206af98e581d760d6d41e0f80e9fb86 + checksum: ab2df3833b2582d4e5467a484d08942b4f2f7208f8e09d67de510008eb8001a9b7460f2f9ba11c12086fd3cdcac0c626761c7995c2c6b5657d5fa6b82030a32d languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:6.20.0": - version: 6.20.0 - resolution: "@typescript-eslint/visitor-keys@npm:6.20.0" +"@typescript-eslint/visitor-keys@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/visitor-keys@npm:6.21.0" dependencies: - "@typescript-eslint/types": "npm:6.20.0" + "@typescript-eslint/types": "npm:6.21.0" eslint-visitor-keys: "npm:^3.4.1" - checksum: 852d938f2e5d57200cf62733b42e73a369f797b097d17e8fd3fffd0f7315c3b9e1863eed60bb8d57d6535a3b7f1980f645f96ec6d513950f182bfa8107b33fab + checksum: 7395f69739cfa1cb83c1fb2fad30afa2a814756367302fb4facd5893eff66abc807e8d8f63eba94ed3b0fe0c1c996ac9a1680bcbf0f83717acedc3f2bb724fbf languageName: node linkType: hard @@ -7347,21 +7347,21 @@ __metadata: linkType: hard "eslint-plugin-jsdoc@npm:^48.0.0": - version: 48.0.4 - resolution: "eslint-plugin-jsdoc@npm:48.0.4" + version: 48.0.6 + resolution: "eslint-plugin-jsdoc@npm:48.0.6" dependencies: - "@es-joy/jsdoccomment": "npm:~0.41.0" + "@es-joy/jsdoccomment": "npm:~0.42.0" are-docs-informative: "npm:^0.0.2" comment-parser: "npm:1.4.1" debug: "npm:^4.3.4" escape-string-regexp: "npm:^4.0.0" esquery: "npm:^1.5.0" is-builtin-module: "npm:^3.2.1" - semver: "npm:^7.5.4" + semver: "npm:^7.6.0" spdx-expression-parse: "npm:^4.0.0" peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - checksum: c73063d26ca70d37ea00eea9750d1f889e5bfda64ca46dbfc6bf4842b892551c320368220cb46acc9d3d96a89fd5391486650284b82dc722f700e3b5df5c78db + checksum: 7762793fb2a738d248144346e85b8c7ec2f975be1a24d45984a5d24da03723b76c66ead1b8064d60b18be09a9a9835320036a39fef917a1b6c83b916729d70dd languageName: node linkType: hard @@ -14721,14 +14721,14 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4": - version: 7.5.4 - resolution: "semver@npm:7.5.4" +"semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0": + version: 7.6.0 + resolution: "semver@npm:7.6.0" dependencies: lru-cache: "npm:^6.0.0" bin: semver: bin/semver.js - checksum: 5160b06975a38b11c1ab55950cb5b8a23db78df88275d3d8a42ccf1f29e55112ac995b3a26a522c36e3b5f76b0445f1eef70d696b8c7862a2b4303d7b0e7609e + checksum: fbfe717094ace0aa8d6332d7ef5ce727259815bd8d8815700853f4faf23aacbd7192522f0dc5af6df52ef4fa85a355ebd2f5d39f554bd028200d6cf481ab9b53 languageName: node linkType: hard From 819ede190e1edeab1c42f41d53895e2bf784406d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 12 Feb 2024 11:39:31 +0100 Subject: [PATCH 26/63] Update dependency dotenv to v16.4.2 (#29157) 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 351fd31ab4..d76af5d9ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6844,9 +6844,9 @@ __metadata: linkType: hard "dotenv@npm:^16.0.3": - version: 16.4.1 - resolution: "dotenv@npm:16.4.1" - checksum: ef3d95f48f38146df0881a4b58447ae437d2da3f6d645074b84de4e64ef64ba75fc357c5ed66b3c2b813b5369fdeb6a4777d6ade2d50e54eed6aa06dddc98bc4 + version: 16.4.2 + resolution: "dotenv@npm:16.4.2" + checksum: 04373a742f565896de1ab3eadcd15c1543b6d1fc37bb7ab2faa2286a0b3fd432aa02c6fd330ede758432f36865f0fb128afa2e5991e0a789b9011e720ba4a876 languageName: node linkType: hard From b244e5cb81bc49c54194cd340408b0b27c0802db Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 08:56:46 +0100 Subject: [PATCH 27/63] Update dependency sidekiq-unique-jobs to v7.1.33 (#29175) 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 152436b47a..00ca4663a8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -707,7 +707,7 @@ GEM rufus-scheduler (~> 3.2) sidekiq (>= 6, < 8) tilt (>= 1.4.0) - sidekiq-unique-jobs (7.1.31) + sidekiq-unique-jobs (7.1.33) brpoplpush-redis_script (> 0.1.1, <= 2.0.0) concurrent-ruby (~> 1.0, >= 1.0.5) redis (< 5.0) From e25d9dfb25f9e412a5dabe1e27675130a285b0d3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 09:02:55 +0100 Subject: [PATCH 28/63] Update dependency dotenv to v16.4.3 (#29174) 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 d76af5d9ef..6088034d9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6844,9 +6844,9 @@ __metadata: linkType: hard "dotenv@npm:^16.0.3": - version: 16.4.2 - resolution: "dotenv@npm:16.4.2" - checksum: 04373a742f565896de1ab3eadcd15c1543b6d1fc37bb7ab2faa2286a0b3fd432aa02c6fd330ede758432f36865f0fb128afa2e5991e0a789b9011e720ba4a876 + version: 16.4.3 + resolution: "dotenv@npm:16.4.3" + checksum: c6a572b2dab5d71accb7064c90b38dfd4068c2487be859a0f053460fcaa685a7718e78db51d643b32e0736b318988c31f8c45cb4ab99cd620278f537177cb0ab languageName: node linkType: hard From 5de1ce23c3debb019f926b297e19a7c37e229871 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 10:08:55 +0100 Subject: [PATCH 29/63] New Crowdin Translations (automated) (#29182) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/bg.json | 2 +- app/javascript/mastodon/locales/es.json | 2 ++ app/javascript/mastodon/locales/ro.json | 30 ++++++++++++++++++++++++ app/javascript/mastodon/locales/tok.json | 13 ++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 95572a7932..5a6fa175e8 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -524,7 +524,7 @@ "poll_button.add_poll": "Анкетиране", "poll_button.remove_poll": "Премахване на анкета", "privacy.change": "Промяна на поверителността на публикация", - "privacy.direct.long": "Всеки споменат в публикацията", + "privacy.direct.long": "Споменатите в публикацията", "privacy.direct.short": "Определени хора", "privacy.private.long": "Само последователите ви", "privacy.private.short": "Последователи", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index d5e8f4239e..3e4f36ba5a 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -530,6 +530,8 @@ "privacy.private.short": "Seguidores", "privacy.public.long": "Cualquiera dentro y fuera de Mastodon", "privacy.public.short": "Público", + "privacy.unlisted.additional": "Esto se comporta exactamente igual que el público, excepto que la publicación no aparecerá en la cronología en directo o en las etiquetas, la exploración o búsqueda de Mastodon, incluso si está optado por activar la cuenta de usuario.", + "privacy.unlisted.long": "Menos fanfares algorítmicos", "privacy.unlisted.short": "Público tranquilo", "privacy_policy.last_updated": "Actualizado por última vez {date}", "privacy_policy.title": "Política de Privacidad", diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json index d236ba4969..547493af18 100644 --- a/app/javascript/mastodon/locales/ro.json +++ b/app/javascript/mastodon/locales/ro.json @@ -21,6 +21,8 @@ "account.blocked": "Blocat", "account.browse_more_on_origin_server": "Vezi mai multe pe profilul original", "account.cancel_follow_request": "Retrage cererea de urmărire", + "account.copy": "Copiază link-ul profilului", + "account.direct": "Menționează pe @{name} în privat", "account.disable_notifications": "Nu îmi mai trimite notificări când postează @{name}", "account.domain_blocked": "Domeniu blocat", "account.edit_profile": "Modifică profilul", @@ -30,6 +32,7 @@ "account.featured_tags.last_status_never": "Fără postări", "account.featured_tags.title": "Haștagurile recomandate de {name}", "account.follow": "Abonează-te", + "account.follow_back": "Urmăreşte înapoi", "account.followers": "Urmăritori", "account.followers.empty": "Acest utilizator nu are încă urmăritori.", "account.followers_counter": "{count, plural, one {Un abonat} few {{counter} abonați} other {{counter} de abonați}}", @@ -38,6 +41,7 @@ "account.follows.empty": "Momentan acest utilizator nu are niciun abonament.", "account.go_to_profile": "Mergi la profil", "account.hide_reblogs": "Ascunde distribuirile de la @{name}", + "account.in_memoriam": "În Memoriam.", "account.joined_short": "Înscris", "account.languages": "Schimbă limbile abonate", "account.link_verified_on": "Proprietatea acestui link a fost verificată pe {date}", @@ -46,7 +50,10 @@ "account.mention": "Menționează pe @{name}", "account.moved_to": "{name} a indicat că noul său cont este acum:", "account.mute": "Pune pe @{name} pe silențios", + "account.mute_notifications_short": "Amuțește notificările", + "account.mute_short": "Ignoră", "account.muted": "Pus pe silențios", + "account.no_bio": "Nicio descriere furnizată.", "account.open_original_page": "Deschide pagina originală", "account.posts": "Postări", "account.posts_with_replies": "Postări și răspunsuri", @@ -69,6 +76,7 @@ "admin.dashboard.retention.average": "În medie", "admin.dashboard.retention.cohort": "Înregistrări lunar", "admin.dashboard.retention.cohort_size": "Utilizatori noi", + "admin.impact_report.title": "Rezumatul impactului", "alert.rate_limited.message": "Vă rugăm să reîncercați după {retry_time, time, medium}.", "alert.rate_limited.title": "Debit limitat", "alert.unexpected.message": "A apărut o eroare neașteptată.", @@ -98,9 +106,11 @@ "column.blocks": "Utilizatori blocați", "column.bookmarks": "Marcaje", "column.community": "Cronologie locală", + "column.direct": "Mențiuni private", "column.directory": "Explorează profiluri", "column.domain_blocks": "Domenii blocate", "column.favourites": "Favorite", + "column.firehose": "Fluxuri live", "column.follow_requests": "Cereri de abonare", "column.home": "Acasă", "column.lists": "Liste", @@ -131,11 +141,19 @@ "compose_form.lock_disclaimer.lock": "privat", "compose_form.placeholder": "La ce te gândești?", "compose_form.poll.duration": "Durata sondajului", + "compose_form.poll.multiple": "Alegeri multiple", + "compose_form.poll.option_placeholder": "Opțiune {number}", + "compose_form.poll.single": "Alegeți unul", "compose_form.poll.switch_to_multiple": "Modifică sondajul pentru a permite mai multe opțiuni", "compose_form.poll.switch_to_single": "Modifică sondajul pentru a permite o singură opțiune", + "compose_form.poll.type": "Stil", + "compose_form.publish": "Postare", "compose_form.publish_form": "Publică", + "compose_form.reply": "Răspundeți", + "compose_form.save_changes": "Actualizare", "compose_form.spoiler.marked": "Elimină avertismentul privind conținutul", "compose_form.spoiler.unmarked": "Adaugă un avertisment privind conținutul", + "compose_form.spoiler_placeholder": "Atenționare de conținut (opțional)", "confirmation_modal.cancel": "Anulează", "confirmations.block.block_and_report": "Blochează și raportează", "confirmations.block.confirm": "Blochează", @@ -151,6 +169,7 @@ "confirmations.domain_block.confirm": "Blochează întregul domeniu", "confirmations.domain_block.message": "Ești absolut sigur că vrei să blochezi tot domeniul {domain}? În cele mai multe cazuri, raportarea sau blocarea anumitor lucruri este suficientă și de preferat. Nu vei mai vedea niciun conținut din acest domeniu în vreun flux public sau în vreo notificare. Abonații tăi din acest domeniu vor fi eliminați.", "confirmations.edit.confirm": "Modifică", + "confirmations.edit.message": "Editarea acum va suprascrie mesajul pe care îl compuneți în prezent. Sunteți sigur că vreți să continuați?", "confirmations.logout.confirm": "Deconectare", "confirmations.logout.message": "Ești sigur că vrei să te deconectezi?", "confirmations.mute.confirm": "Ignoră", @@ -165,6 +184,7 @@ "conversation.mark_as_read": "Marchează ca citit", "conversation.open": "Vizualizează conversația", "conversation.with": "Cu {names}", + "copy_icon_button.copied": "Copiat în clipboard", "copypaste.copied": "Copiat", "copypaste.copy_to_clipboard": "Copiază în clipboard", "directory.federated": "Din fediversul cunoscut", @@ -240,10 +260,17 @@ "filter_modal.select_filter.title": "Filtrează această postare", "filter_modal.title.status": "Filtrează o postare", "firehose.all": "Toate", + "firehose.local": "Acest Server", "firehose.remote": "Alte servere", "follow_request.authorize": "Acceptă", "follow_request.reject": "Respinge", "follow_requests.unlocked_explanation": "Chiar dacă contul tău nu este blocat, personalul {domain} a considerat că ai putea prefera să consulți manual cererile de abonare de la aceste conturi.", + "follow_suggestions.curated_suggestion": "Alegerile Editorilor", + "follow_suggestions.dismiss": "Nu mai afișa din nou", + "follow_suggestions.personalized_suggestion": "Sugestie personalizată", + "follow_suggestions.popular_suggestion": "Sugestie populară", + "follow_suggestions.view_all": "Vizualizați tot", + "follow_suggestions.who_to_follow": "Pe cine să urmăriți", "followed_tags": "Hastaguri urmărite", "footer.about": "Despre", "footer.directory": "Catalogul de profiluri", @@ -272,12 +299,15 @@ "home.hide_announcements": "Ascunde anunțurile", "home.pending_critical_update.body": "Te rugăm să-ți actualizezi serverul de Mastodon cat mai curând posibil!", "home.pending_critical_update.link": "Vezi noutăți", + "home.pending_critical_update.title": "Actualizare critică de securitate disponibilă!", "home.show_announcements": "Afișează anunțurile", + "interaction_modal.description.favourite": "Cu un cont pe Mastodon, poți adăuga această postare la favorite pentru a-l informa pe autorul ei că o apreciezi și pentru a o salva pentru mai târziu.", "interaction_modal.description.follow": "Cu un cont Mastodon, poți urmări pe {name} pentru a vedea postările sale în cronologia ta principală.", "interaction_modal.description.reblog": "Cu un cont pe Mastodon, poți distribui această postare pentru a le-o arăta și celor abonați ție.", "interaction_modal.description.reply": "Cu un cont pe Mastodon, poți răspunde acestei postări.", "interaction_modal.login.action": "Du-mă acasă", "interaction_modal.login.prompt": "Adresa serverului tău acasă, de ex. mastodon.social", + "interaction_modal.no_account_yet": "Nu ești încă pe Mastodon?", "interaction_modal.on_another_server": "Pe un alt server", "interaction_modal.on_this_server": "Pe acest server", "interaction_modal.title.follow": "Urmărește pe {name}", diff --git a/app/javascript/mastodon/locales/tok.json b/app/javascript/mastodon/locales/tok.json index ba45f84453..85f62f404a 100644 --- a/app/javascript/mastodon/locales/tok.json +++ b/app/javascript/mastodon/locales/tok.json @@ -6,6 +6,7 @@ "about.not_available": "lon kulupu ni la sina ken alasa ala e sona ni.", "about.rules": "lawa kulupu", "account.account_note_header": "sona awen", + "account.add_or_remove_from_list": "o ante e lipu jan", "account.badges.bot": "ilo nanpa li lawa e ni", "account.badges.group": "kulupu", "account.block": "o weka e @{name}", @@ -83,6 +84,7 @@ "column_header.pin": "o sewi", "column_header.show_settings": "o lukin e lawa", "column_header.unpin": "o sewi ala", + "column_subheading.settings": "ken ilo", "community.column_settings.local_only": "toki tan ni taso", "community.column_settings.media_only": "sitelen taso", "community.column_settings.remote_only": "toki tan ante taso", @@ -177,6 +179,8 @@ "follow_request.reject": "o ala", "follow_suggestions.view_all": "o lukin e ale", "follow_suggestions.who_to_follow": "sina o kute e ni", + "footer.about": "sona", + "footer.directory": "lipu jan", "footer.get_app": "o jo e ilo", "footer.privacy_policy": "lawa len", "footer.source_code": "o lukin e toki ilo", @@ -195,6 +199,7 @@ "interaction_modal.title.follow": "o kute e {name}", "interaction_modal.title.reblog": "o wawa e toki {name}", "keyboard_shortcuts.blocked": "o lukin e lipu sina pi jan weka", + "keyboard_shortcuts.boost": "o pana sin e toki", "keyboard_shortcuts.down": "o tawa anpa lon lipu", "keyboard_shortcuts.enter": "o lukin e toki", "keyboard_shortcuts.favourite": "o suli e toki", @@ -204,6 +209,7 @@ "keyboard_shortcuts.open_media": "o lukin e sitelen", "keyboard_shortcuts.pinned": "o lukin pi lipu sina pi toki sewi", "keyboard_shortcuts.toggle_sensitivity": "o ante e ken lukin", + "keyboard_shortcuts.toot": "o toki", "keyboard_shortcuts.up": "o tawa sewi lon lipu", "lightbox.close": "o pini", "lightbox.compress": "o lili e sitelen", @@ -227,6 +233,7 @@ "media_gallery.toggle_visible": "{number, plural, other {o len e sitelen}}", "mute_modal.duration": "tenpo", "mute_modal.indefinite": "tenpo ale", + "navigation_bar.about": "sona", "navigation_bar.blocks": "jan weka", "navigation_bar.compose": "o pali e toki sin", "navigation_bar.favourites": "toki suli", @@ -261,12 +268,14 @@ "report.close": "o pini", "report.mute": "o kute ala e ona", "report.mute_explanation": "sina kama ala lukin e ijo pana ona. ona li awen ken kute e sina li awen ken lukin e sina li sona ala e weka kute sina e weka lukin sina.", + "report.next": "awen", "report.reasons.dislike": "ni li ike tawa mi", "report.reasons.legal": "ni li ike tawa lawa", "report.reasons.other": "ni li ike tan ante", "report.reasons.spam": "ni li ike tan toki mute", "report.thanks.title": "sina wile ala lukin e ni anu seme?", "report.unfollow": "o pini kute e {name}", + "report_notification.categories.legal": "ike tawa nasin lawa", "search.placeholder": "o alasa", "search.quick_action.go_to_account": "o tawa lipu jan {x}", "search_popout.language_code": "nimi toki kepeken nasin ISO", @@ -275,6 +284,7 @@ "search_results.statuses": "toki", "search_results.title": "o alasa e {q}", "status.block": "o weka e @{name}", + "status.cancel_reblog_private": "o pini e pana", "status.delete": "o weka", "status.edit": "o ante", "status.edited": "ni li ante lon {date}", @@ -305,7 +315,10 @@ "status.unpin": "o sewi ala lon lipu sina", "subscribed_languages.save": "o awen e ante", "tabs_bar.home": "lipu open", + "timeline_hint.resources.followers": "jan kute", + "timeline_hint.resources.follows": "jan lukin", "timeline_hint.resources.statuses": "ijo pi tenpo suli", + "trends.trending_now": "jan mute li toki", "units.short.million": "{count}AAA", "upload_button.label": "o pana e sitelen anu kalama", "upload_error.limit": "ilo li ken ala e suli pi ijo ni.", From 476a043fc5339526536cbb1ba64d0ba2230e870c Mon Sep 17 00:00:00 2001 From: Nicolas Hoffmann Date: Tue, 13 Feb 2024 13:58:21 +0100 Subject: [PATCH 30/63] Fix modal container bounds (#29185) --- app/javascript/styles/mastodon/components.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 427144ed8e..af9fc88e7b 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -5343,6 +5343,8 @@ a.status-card { inset-inline-start: 0; width: 100%; height: 100%; + max-width: 100vw; + max-height: 100vh; box-sizing: border-box; display: flex; flex-direction: column; From e8b66a0525f0468fe6588803ec2a15ff186d08ab Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Tue, 13 Feb 2024 18:14:49 +0100 Subject: [PATCH 31/63] Ignore legacy moderator and admin columns on User model (#29188) --- app/models/concerns/user/ldap_authenticable.rb | 10 +++++++++- app/models/concerns/user/pam_authenticable.rb | 1 - app/models/user.rb | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/models/concerns/user/ldap_authenticable.rb b/app/models/concerns/user/ldap_authenticable.rb index d84ff084b2..180df9d310 100644 --- a/app/models/concerns/user/ldap_authenticable.rb +++ b/app/models/concerns/user/ldap_authenticable.rb @@ -25,7 +25,15 @@ module User::LdapAuthenticable resource = joins(:account).find_by(accounts: { username: safe_username }) if resource.blank? - resource = new(email: attributes[Devise.ldap_mail.to_sym].first, agreement: true, account_attributes: { username: safe_username }, admin: false, external: true, confirmed_at: Time.now.utc) + resource = new( + email: attributes[Devise.ldap_mail.to_sym].first, + agreement: true, + account_attributes: { + username: safe_username, + }, + external: true, + confirmed_at: Time.now.utc + ) resource.save! end diff --git a/app/models/concerns/user/pam_authenticable.rb b/app/models/concerns/user/pam_authenticable.rb index a682058cca..30dc7d8aef 100644 --- a/app/models/concerns/user/pam_authenticable.rb +++ b/app/models/concerns/user/pam_authenticable.rb @@ -32,7 +32,6 @@ module User::PamAuthenticable self.email = "#{account.username}@#{find_pam_suffix}" if email.nil? && find_pam_suffix self.confirmed_at = Time.now.utc - self.admin = false self.account = account self.external = true diff --git a/app/models/user.rb b/app/models/user.rb index 70c24336f3..95fdc431ac 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -51,6 +51,8 @@ class User < ApplicationRecord last_sign_in_ip skip_sign_in_token filtered_languages + admin + moderator ) include LanguagesHelper From 46142cdbddd6d3eb5e88386c74b5600abe520c38 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Tue, 13 Feb 2024 19:11:47 +0100 Subject: [PATCH 32/63] Disable administrative doorkeeper routes (#29187) --- config/initializers/doorkeeper.rb | 9 +- .../requests/disabled_oauth_endpoints_spec.rb | 83 +++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 spec/requests/disabled_oauth_endpoints_spec.rb diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index fe3871d2e7..f9d47a205c 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -21,9 +21,14 @@ Doorkeeper.configure do user unless user&.otp_required_for_login? end - # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below. + # Doorkeeper provides some administrative interfaces for managing OAuth + # Applications, allowing creation, edit, and deletion of applications from the + # server. At present, these administrative routes are not integrated into + # Mastodon, and as such, we've disabled them by always return a 403 forbidden + # response for them. This does not affect the ability for users to manage + # their own OAuth Applications. admin_authenticator do - current_user&.admin? || redirect_to(new_user_session_url) + head 403 end # Authorization Code expiration time (default 10 minutes). diff --git a/spec/requests/disabled_oauth_endpoints_spec.rb b/spec/requests/disabled_oauth_endpoints_spec.rb new file mode 100644 index 0000000000..7c2c09f380 --- /dev/null +++ b/spec/requests/disabled_oauth_endpoints_spec.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Disabled OAuth routes' do + # These routes are disabled via the doorkeeper configuration for + # `admin_authenticator`, as these routes should only be accessible by server + # administrators. For now, these routes are not properly designed and + # integrated into Mastodon, so we're disabling them completely + describe 'GET /oauth/applications' do + it 'returns 403 forbidden' do + get oauth_applications_path + + expect(response).to have_http_status(403) + end + end + + describe 'POST /oauth/applications' do + it 'returns 403 forbidden' do + post oauth_applications_path + + expect(response).to have_http_status(403) + end + end + + describe 'GET /oauth/applications/new' do + it 'returns 403 forbidden' do + get new_oauth_application_path + + expect(response).to have_http_status(403) + end + end + + describe 'GET /oauth/applications/:id' do + let(:application) { Fabricate(:application, scopes: 'read') } + + it 'returns 403 forbidden' do + get oauth_application_path(application) + + expect(response).to have_http_status(403) + end + end + + describe 'PATCH /oauth/applications/:id' do + let(:application) { Fabricate(:application, scopes: 'read') } + + it 'returns 403 forbidden' do + patch oauth_application_path(application) + + expect(response).to have_http_status(403) + end + end + + describe 'PUT /oauth/applications/:id' do + let(:application) { Fabricate(:application, scopes: 'read') } + + it 'returns 403 forbidden' do + put oauth_application_path(application) + + expect(response).to have_http_status(403) + end + end + + describe 'DELETE /oauth/applications/:id' do + let(:application) { Fabricate(:application, scopes: 'read') } + + it 'returns 403 forbidden' do + delete oauth_application_path(application) + + expect(response).to have_http_status(403) + end + end + + describe 'GET /oauth/applications/:id/edit' do + let(:application) { Fabricate(:application, scopes: 'read') } + + it 'returns 403 forbidden' do + get edit_oauth_application_path(application) + + expect(response).to have_http_status(403) + end + end +end From 554e2a019e40755fbe6ae02fbf5cfc1862550e20 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 14 Feb 2024 13:12:13 +0100 Subject: [PATCH 33/63] Add `sidekiq_unique_jobs:delete_all_locks` task and disable `sidekiq-unique-jobs` UI by default (#29199) --- config/routes.rb | 2 +- lib/tasks/sidekiq_unique_jobs.rake | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 lib/tasks/sidekiq_unique_jobs.rake diff --git a/config/routes.rb b/config/routes.rb index bb088821fd..51c10a14f6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'sidekiq_unique_jobs/web' +require 'sidekiq_unique_jobs/web' if ENV['ENABLE_SIDEKIQ_UNIQUE_JOBS_UI'] == true require 'sidekiq-scheduler/web' class RedirectWithVary < ActionDispatch::Routing::PathRedirect diff --git a/lib/tasks/sidekiq_unique_jobs.rake b/lib/tasks/sidekiq_unique_jobs.rake new file mode 100644 index 0000000000..bedc8fe4c6 --- /dev/null +++ b/lib/tasks/sidekiq_unique_jobs.rake @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +namespace :sidekiq_unique_jobs do + task delete_all_locks: :environment do + digests = SidekiqUniqueJobs::Digests.new + digests.delete_by_pattern('*', count: digests.count) + + expiring_digests = SidekiqUniqueJobs::ExpiringDigests.new + expiring_digests.delete_by_pattern('*', count: expiring_digests.count) + end +end From 68eaa804c9bafdc5f798e114e9ba00161425dd71 Mon Sep 17 00:00:00 2001 From: Emelia Smith Date: Wed, 14 Feb 2024 15:15:34 +0100 Subject: [PATCH 34/63] Merge pull request from GHSA-7w3c-p9j8-mq3x * Ensure destruction of OAuth Applications notifies streaming Due to doorkeeper using a dependent: delete_all relationship, the destroy of an OAuth Application bypassed the existing AccessTokenExtension callbacks for announcing destructing of access tokens. * Ensure password resets revoke access to Streaming API * Improve performance of deleting OAuth tokens --------- Co-authored-by: Claire --- app/lib/application_extension.rb | 20 ++++++++++++++++++++ app/models/user.rb | 10 ++++++++++ spec/models/user_spec.rb | 7 +++++++ 3 files changed, 37 insertions(+) diff --git a/app/lib/application_extension.rb b/app/lib/application_extension.rb index fb442e2c2d..400c51a023 100644 --- a/app/lib/application_extension.rb +++ b/app/lib/application_extension.rb @@ -4,14 +4,34 @@ module ApplicationExtension extend ActiveSupport::Concern included do + include Redisable + has_many :created_users, class_name: 'User', foreign_key: 'created_by_application_id', inverse_of: :created_by_application validates :name, length: { maximum: 60 } validates :website, url: true, length: { maximum: 2_000 }, if: :website? validates :redirect_uri, length: { maximum: 2_000 } + + # The relationship used between Applications and AccessTokens is using + # dependent: delete_all, which means the ActiveRecord callback in + # AccessTokenExtension is not run, so instead we manually announce to + # streaming that these tokens are being deleted. + before_destroy :push_to_streaming_api, prepend: true end def confirmation_redirect_uri redirect_uri.lines.first.strip end + + def push_to_streaming_api + # TODO: #28793 Combine into a single topic + payload = Oj.dump(event: :kill) + access_tokens.in_batches do |tokens| + redis.pipelined do |pipeline| + tokens.ids.each do |id| + pipeline.publish("timeline:access_token:#{id}", payload) + end + end + end + end end diff --git a/app/models/user.rb b/app/models/user.rb index 95fdc431ac..f706c91eff 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -344,6 +344,16 @@ class User < ApplicationRecord Doorkeeper::AccessToken.by_resource_owner(self).in_batches do |batch| batch.update_all(revoked_at: Time.now.utc) Web::PushSubscription.where(access_token_id: batch).delete_all + + # Revoke each access token for the Streaming API, since `update_all`` + # doesn't trigger ActiveRecord Callbacks: + # TODO: #28793 Combine into a single topic + payload = Oj.dump(event: :kill) + redis.pipelined do |pipeline| + batch.ids.each do |id| + pipeline.publish("timeline:access_token:#{id}", payload) + end + end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 5ac41c0ff1..845335e873 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -420,7 +420,10 @@ RSpec.describe User do let!(:access_token) { Fabricate(:access_token, resource_owner_id: user.id) } let!(:web_push_subscription) { Fabricate(:web_push_subscription, access_token: access_token) } + let(:redis_pipeline_stub) { instance_double(Redis::Namespace, publish: nil) } + before do + allow(redis).to receive(:pipelined).and_yield(redis_pipeline_stub) user.reset_password! end @@ -437,6 +440,10 @@ RSpec.describe User do expect(Doorkeeper::AccessToken.active_for(user).count).to eq 0 end + it 'revokes streaming access for all access tokens' do + expect(redis_pipeline_stub).to have_received(:publish).with("timeline:access_token:#{access_token.id}", Oj.dump(event: :kill)).once + end + it 'removes push subscriptions' do expect(Web::PushSubscription.where(user: user).or(Web::PushSubscription.where(access_token: access_token)).count).to eq 0 expect { web_push_subscription.reload }.to raise_error(ActiveRecord::RecordNotFound) From b31af34c9716338e4a32a62cc812d1ca59e88d15 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 14 Feb 2024 15:16:07 +0100 Subject: [PATCH 35/63] Merge pull request from GHSA-vm39-j3vx-pch3 * Prevent different identities from a same SSO provider from accessing a same account * Lock auth provider changes behind `ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH=true` * Rename methods to avoid confusion between OAuth and OmniAuth --- .../auth/omniauth_callbacks_controller.rb | 2 +- app/models/concerns/user/omniauthable.rb | 52 ++++++++++++++----- app/models/identity.rb | 2 +- spec/models/identity_spec.rb | 6 +-- spec/requests/omniauth_callbacks_spec.rb | 2 +- 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/app/controllers/auth/omniauth_callbacks_controller.rb b/app/controllers/auth/omniauth_callbacks_controller.rb index 707b50ef9e..9b83de945b 100644 --- a/app/controllers/auth/omniauth_callbacks_controller.rb +++ b/app/controllers/auth/omniauth_callbacks_controller.rb @@ -7,7 +7,7 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController def self.provides_callback_for(provider) define_method provider do @provider = provider - @user = User.find_for_oauth(request.env['omniauth.auth'], current_user) + @user = User.find_for_omniauth(request.env['omniauth.auth'], current_user) if @user.persisted? record_login_activity diff --git a/app/models/concerns/user/omniauthable.rb b/app/models/concerns/user/omniauthable.rb index 113bfda230..396a0598f8 100644 --- a/app/models/concerns/user/omniauthable.rb +++ b/app/models/concerns/user/omniauthable.rb @@ -19,17 +19,18 @@ module User::Omniauthable end class_methods do - def find_for_oauth(auth, signed_in_resource = nil) + def find_for_omniauth(auth, signed_in_resource = nil) # EOLE-SSO Patch auth.uid = (auth.uid[0][:uid] || auth.uid[0][:user]) if auth.uid.is_a? Hashie::Array - identity = Identity.find_for_oauth(auth) + identity = Identity.find_for_omniauth(auth) # If a signed_in_resource is provided it always overrides the existing user # to prevent the identity being locked with accidentally created accounts. # Note that this may leave zombie accounts (with no associated identity) which # can be cleaned up at a later date. user = signed_in_resource || identity.user - user ||= create_for_oauth(auth) + user ||= reattach_for_auth(auth) + user ||= create_for_auth(auth) if identity.user.nil? identity.user = user @@ -39,19 +40,35 @@ module User::Omniauthable user end - def create_for_oauth(auth) - # Check if the user exists with provided email. If no email was provided, + private + + def reattach_for_auth(auth) + # If allowed, check if a user exists with the provided email address, + # and return it if they does not have an associated identity with the + # current authentication provider. + + # This can be used to provide a choice of alternative auth providers + # or provide smooth gradual transition between multiple auth providers, + # but this is discouraged because any insecure provider will put *all* + # local users at risk, regardless of which provider they registered with. + + return unless ENV['ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH'] == 'true' + + email, email_is_verified = email_from_auth(auth) + return unless email_is_verified + + user = User.find_by(email: email) + return if user.nil? || Identity.exists?(provider: auth.provider, user_id: user.id) + + user + end + + def create_for_auth(auth) + # Create a user for the given auth params. If no email was provided, # we assign a temporary email and ask the user to verify it on # the next step via Auth::SetupController.show - strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy - assume_verified = strategy&.security&.assume_email_is_verified - email_is_verified = auth.info.verified || auth.info.verified_email || auth.info.email_verified || assume_verified - email = auth.info.verified_email || auth.info.email - - user = User.find_by(email: email) if email_is_verified - - return user unless user.nil? + email, email_is_verified = email_from_auth(auth) user = User.new(user_params_from_auth(email, auth)) @@ -66,7 +83,14 @@ module User::Omniauthable user end - private + def email_from_auth(auth) + strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy + assume_verified = strategy&.security&.assume_email_is_verified + email_is_verified = auth.info.verified || auth.info.verified_email || auth.info.email_verified || assume_verified + email = auth.info.verified_email || auth.info.email + + [email, email_is_verified] + end def user_params_from_auth(email, auth) { diff --git a/app/models/identity.rb b/app/models/identity.rb index c95a68a6f6..77821b78fa 100644 --- a/app/models/identity.rb +++ b/app/models/identity.rb @@ -17,7 +17,7 @@ class Identity < ApplicationRecord validates :uid, presence: true, uniqueness: { scope: :provider } validates :provider, presence: true - def self.find_for_oauth(auth) + def self.find_for_omniauth(auth) find_or_create_by(uid: auth.uid, provider: auth.provider) end end diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb index 7022454443..d5a2ffbc86 100644 --- a/spec/models/identity_spec.rb +++ b/spec/models/identity_spec.rb @@ -3,19 +3,19 @@ require 'rails_helper' RSpec.describe Identity do - describe '.find_for_oauth' do + describe '.find_for_omniauth' do let(:auth) { Fabricate(:identity, user: Fabricate(:user)) } it 'calls .find_or_create_by' do allow(described_class).to receive(:find_or_create_by) - described_class.find_for_oauth(auth) + described_class.find_for_omniauth(auth) expect(described_class).to have_received(:find_or_create_by).with(uid: auth.uid, provider: auth.provider) end it 'returns an instance of Identity' do - expect(described_class.find_for_oauth(auth)).to be_instance_of described_class + expect(described_class.find_for_omniauth(auth)).to be_instance_of described_class end end end diff --git a/spec/requests/omniauth_callbacks_spec.rb b/spec/requests/omniauth_callbacks_spec.rb index 0d37c41140..b478ca1ce6 100644 --- a/spec/requests/omniauth_callbacks_spec.rb +++ b/spec/requests/omniauth_callbacks_spec.rb @@ -96,7 +96,7 @@ describe 'OmniAuth callbacks' do context 'when a user cannot be built' do before do - allow(User).to receive(:find_for_oauth).and_return(User.new) + allow(User).to receive(:find_for_omniauth).and_return(User.new) end it 'redirects to the new user signup page' do From 8e8e0f104fc3a64c9f862eca588a63ddbb8b6865 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 14 Feb 2024 15:20:02 +0100 Subject: [PATCH 36/63] Bump version to v4.3.0-alpha.2 (#29200) --- lib/mastodon/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index dd7c84207e..c2f26aee63 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -17,7 +17,7 @@ module Mastodon end def default_prerelease - 'alpha.1' + 'alpha.2' end def prerelease From bbbbf000849a3eb38f2a1fb58370f7e81ef71f11 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 14 Feb 2024 15:57:49 +0100 Subject: [PATCH 37/63] Fix OmniAuth tests (#29201) --- spec/requests/omniauth_callbacks_spec.rb | 35 ++++++++++++++++++------ 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/spec/requests/omniauth_callbacks_spec.rb b/spec/requests/omniauth_callbacks_spec.rb index b478ca1ce6..1e488b3f43 100644 --- a/spec/requests/omniauth_callbacks_spec.rb +++ b/spec/requests/omniauth_callbacks_spec.rb @@ -39,16 +39,33 @@ describe 'OmniAuth callbacks' do Fabricate(:user, email: 'user@host.example') end - it 'matches the existing user, creates an identity, and redirects to root path' do - expect { subject } - .to not_change(User, :count) - .and change(Identity, :count) - .by(1) - .and change(LoginActivity, :count) - .by(1) + context 'when ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH is set to true' do + around do |example| + ClimateControl.modify ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH: 'true' do + example.run + end + end - expect(Identity.find_by(user: User.last).uid).to eq('123') - expect(response).to redirect_to(root_path) + it 'matches the existing user, creates an identity, and redirects to root path' do + expect { subject } + .to not_change(User, :count) + .and change(Identity, :count) + .by(1) + .and change(LoginActivity, :count) + .by(1) + + expect(Identity.find_by(user: User.last).uid).to eq('123') + expect(response).to redirect_to(root_path) + end + end + + context 'when ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH is not set to true' do + it 'does not match the existing user or create an identity' do + expect { subject } + .to not_change(User, :count) + .and not_change(Identity, :count) + .and not_change(LoginActivity, :count) + end end end From 844aa59bdfe76d8db2253c1a25d2f9b6caead690 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 14 Feb 2024 11:44:27 -0500 Subject: [PATCH 38/63] Doc update about ruby version 3.0+ (#29202) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 267f0ed295..6cf722b355 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Stre - **PostgreSQL** 12+ - **Redis** 4+ -- **Ruby** 2.7+ +- **Ruby** 3.0+ - **Node.js** 16+ The repository includes deployment configurations for **Docker and docker-compose** as well as specific platforms like **Heroku**, **Scalingo**, and **Nanobox**. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). The [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the documentation. From d4d0565b0fd86ca80d2dbf0c7d09a9af5ea4a293 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 14 Feb 2024 22:49:45 +0100 Subject: [PATCH 39/63] Fix user creation failure handling in OAuth paths (#29207) --- app/controllers/auth/omniauth_callbacks_controller.rb | 3 +++ config/locales/devise.en.yml | 1 + spec/requests/omniauth_callbacks_spec.rb | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/controllers/auth/omniauth_callbacks_controller.rb b/app/controllers/auth/omniauth_callbacks_controller.rb index 9b83de945b..9d496220a3 100644 --- a/app/controllers/auth/omniauth_callbacks_controller.rb +++ b/app/controllers/auth/omniauth_callbacks_controller.rb @@ -17,6 +17,9 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController session["devise.#{provider}_data"] = request.env['omniauth.auth'] redirect_to new_user_registration_url end + rescue ActiveRecord::RecordInvalid + flash[:alert] = I18n.t('devise.failure.omniauth_user_creation_failure') if is_navigational_format? + redirect_to new_user_session_url end end diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml index 4439397c8e..61bd33851b 100644 --- a/config/locales/devise.en.yml +++ b/config/locales/devise.en.yml @@ -12,6 +12,7 @@ en: last_attempt: You have one more attempt before your account is locked. locked: Your account is locked. not_found_in_database: Invalid %{authentication_keys} or password. + omniauth_user_creation_failure: Error creating an account for this identity. pending: Your account is still under review. timeout: Your session expired. Please login again to continue. unauthenticated: You need to login or sign up before continuing. diff --git a/spec/requests/omniauth_callbacks_spec.rb b/spec/requests/omniauth_callbacks_spec.rb index 1e488b3f43..095535e485 100644 --- a/spec/requests/omniauth_callbacks_spec.rb +++ b/spec/requests/omniauth_callbacks_spec.rb @@ -60,11 +60,13 @@ describe 'OmniAuth callbacks' do end context 'when ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH is not set to true' do - it 'does not match the existing user or create an identity' do + it 'does not match the existing user or create an identity, and redirects to login page' do expect { subject } .to not_change(User, :count) .and not_change(Identity, :count) .and not_change(LoginActivity, :count) + + expect(response).to redirect_to(new_user_session_url) end end end From fc4f82346440573898c60fcd4af1f033ec724aae Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 02:41:25 -0500 Subject: [PATCH 40/63] Avoid local block var assignment in ap/process_status_update_service spec (#29210) --- .../services/activitypub/process_status_update_service_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/services/activitypub/process_status_update_service_spec.rb b/spec/services/activitypub/process_status_update_service_spec.rb index 53cbaf4cc1..67f2f27276 100644 --- a/spec/services/activitypub/process_status_update_service_spec.rb +++ b/spec/services/activitypub/process_status_update_service_spec.rb @@ -218,7 +218,8 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do end it 'does not update the text, spoiler_text or edited_at' do - expect { subject.call(status, json, json) }.to_not(change { s = status.reload; [s.text, s.spoiler_text, s.edited_at] }) + expect { subject.call(status, json, json) } + .to_not(change { status.reload.attributes.slice('text', 'spoiler_text', 'edited_at').values }) end end From 1df2ffc3eee80ab53de00d076658dd546515a9bd Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 02:42:03 -0500 Subject: [PATCH 41/63] Use `subject` in blacklist email validator spec (#29211) --- spec/validators/blacklisted_email_validator_spec.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/spec/validators/blacklisted_email_validator_spec.rb b/spec/validators/blacklisted_email_validator_spec.rb index 6292f0737e..86760df2e7 100644 --- a/spec/validators/blacklisted_email_validator_spec.rb +++ b/spec/validators/blacklisted_email_validator_spec.rb @@ -4,7 +4,7 @@ require 'rails_helper' RSpec.describe BlacklistedEmailValidator do describe '#validate' do - subject { described_class.new.validate(user); errors } + subject { described_class.new.validate(user) } let(:user) { instance_double(User, email: 'info@mail.com', sign_up_ip: '1.2.3.4', errors: errors) } let(:errors) { instance_double(ActiveModel::Errors, add: nil) } @@ -18,7 +18,8 @@ RSpec.describe BlacklistedEmailValidator do let(:blocked_email) { true } it 'adds error' do - described_class.new.validate(user) + subject + expect(errors).to have_received(:add).with(:email, :blocked).once end end @@ -27,7 +28,8 @@ RSpec.describe BlacklistedEmailValidator do let(:blocked_email) { false } it 'does not add errors' do - described_class.new.validate(user) + subject + expect(errors).to_not have_received(:add) end @@ -39,7 +41,8 @@ RSpec.describe BlacklistedEmailValidator do end it 'adds error' do - described_class.new.validate(user) + subject + expect(errors).to have_received(:add).with(:email, :taken).once end end From ed4939296a2f0ecf5d072c4f04c2733170038fa4 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 02:43:00 -0500 Subject: [PATCH 42/63] Reduce `RSpec/MultipleExpectations` in ap/activity/create spec (#29224) --- spec/lib/activitypub/activity/create_spec.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index e4966cffa3..dec17b916b 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -970,12 +970,15 @@ RSpec.describe ActivityPub::Activity::Create do it 'creates an encrypted message' do encrypted_message = target_device.encrypted_messages.reload.first - expect(encrypted_message).to_not be_nil - expect(encrypted_message.from_device_id).to eq '1234' - expect(encrypted_message.from_account).to eq sender - expect(encrypted_message.type).to eq 1 - expect(encrypted_message.body).to eq 'Foo' - expect(encrypted_message.digest).to eq 'Foo123' + expect(encrypted_message) + .to be_present + .and have_attributes( + from_device_id: eq('1234'), + from_account: eq(sender), + type: eq(1), + body: eq('Foo'), + digest: eq('Foo123') + ) end it 'creates a message franking' do From 1c93d625c6392374ebf014c190166ce98652f539 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 08:51:13 +0100 Subject: [PATCH 43/63] New Crowdin Translations (automated) (#29195) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/bg.json | 12 +- app/javascript/mastodon/locales/ie.json | 13 +++ app/javascript/mastodon/locales/kab.json | 61 ++++++---- app/javascript/mastodon/locales/sk.json | 1 + app/javascript/mastodon/locales/th.json | 4 +- app/javascript/mastodon/locales/tok.json | 10 ++ config/locales/de.yml | 4 +- config/locales/devise.be.yml | 1 + config/locales/devise.ca.yml | 1 + config/locales/devise.da.yml | 1 + config/locales/devise.de.yml | 1 + config/locales/devise.es-AR.yml | 1 + config/locales/devise.eu.yml | 1 + config/locales/devise.fi.yml | 1 + config/locales/devise.fo.yml | 1 + config/locales/devise.fy.yml | 1 + config/locales/devise.gl.yml | 1 + config/locales/devise.he.yml | 1 + config/locales/devise.hu.yml | 1 + config/locales/devise.ie.yml | 1 + config/locales/devise.is.yml | 1 + config/locales/devise.it.yml | 1 + config/locales/devise.kab.yml | 8 +- config/locales/devise.ko.yml | 1 + config/locales/devise.lad.yml | 1 + config/locales/devise.nl.yml | 1 + config/locales/devise.pl.yml | 1 + config/locales/devise.pt-PT.yml | 1 + config/locales/devise.sk.yml | 1 + config/locales/devise.sl.yml | 1 + config/locales/devise.sq.yml | 1 + config/locales/devise.sr-Latn.yml | 1 + config/locales/devise.sr.yml | 1 + config/locales/devise.tr.yml | 1 + config/locales/devise.uk.yml | 1 + config/locales/devise.zh-CN.yml | 1 + config/locales/devise.zh-HK.yml | 1 + config/locales/devise.zh-TW.yml | 1 + config/locales/doorkeeper.kab.yml | 10 +- config/locales/ie.yml | 6 + config/locales/kab.yml | 136 +++++++++++++++-------- config/locales/simple_form.kab.yml | 8 +- config/locales/sq.yml | 4 +- config/locales/th.yml | 2 +- 44 files changed, 211 insertions(+), 98 deletions(-) diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 5a6fa175e8..3e7f6e51b2 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.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} следват.", @@ -231,7 +231,7 @@ "empty_column.community": "Локалният инфопоток е празен. Публикувайте нещо, за да започнете!", "empty_column.direct": "Още нямате никакви частни споменавания. Тук ще се показват, изпращайки или получавайки едно.", "empty_column.domain_blocks": "Още няма блокирани домейни.", - "empty_column.explore_statuses": "Няма нищо налагащо се в момента. Проверете пак по-късно!", + "empty_column.explore_statuses": "Няма тенденции в момента. Проверете пак по-късно!", "empty_column.favourited_statuses": "Още нямате никакви любими публикации. Правейки любима, то тя ще се покаже тук.", "empty_column.favourites": "Още никого не е слагал публикацията в любими. Когато някой го направи, този човек ще се покаже тук.", "empty_column.follow_requests": "Още нямате заявки за последване. Получавайки такава, то тя ще се покаже тук.", @@ -407,7 +407,7 @@ "navigation_bar.direct": "Частни споменавания", "navigation_bar.discover": "Откриване", "navigation_bar.domain_blocks": "Блокирани домейни", - "navigation_bar.explore": "Изследване", + "navigation_bar.explore": "Разглеждане", "navigation_bar.favourites": "Любими", "navigation_bar.filters": "Заглушени думи", "navigation_bar.follow_requests": "Заявки за последване", @@ -474,10 +474,10 @@ "notifications_permission_banner.title": "Никога не пропускате нещо", "onboarding.action.back": "Върнете ме обратно", "onboarding.actions.back": "Върнете ме обратно", - "onboarding.actions.go_to_explore": "Вижте какво изгрява", + "onboarding.actions.go_to_explore": "Виж тенденции", "onboarding.actions.go_to_home": "Към началния ви инфоканал", "onboarding.compose.template": "Здравейте, #Mastodon!", - "onboarding.follows.empty": "За съжаление, в момента не могат да се показват резултати. Може да опитате да употребявате търсене или да прегледате страницата за изследване, за да намерите страница за последване, или да опитате пак по-късно.", + "onboarding.follows.empty": "За съжаление, в момента не могат да бъдат показани резултати. Може да опитате да търсите или да разгледате, за да намерите кого да последвате, или опитайте отново по-късно.", "onboarding.follows.lead": "Може да бъдете куратор на началния си инфоканал. Последвайки повече хора, по-деен и по-интересен ще става. Тези профили може да са добра начална точка, от която винаги по-късно да спрете да следвате!", "onboarding.follows.title": "Популярно в Mastodon", "onboarding.profile.discoverable": "Правене на моя профил откриваем", @@ -530,7 +530,7 @@ "privacy.private.short": "Последователи", "privacy.public.long": "Всеки във и извън Mastodon", "privacy.public.short": "Публично", - "privacy.unlisted.additional": "Това поведение е точно като публичното, с изключение на това, че публикацията няма да се появява в каналите на живо, хаштаговете, проучването или търсенето в Mastodon, дори ако сте се включили в целия акаунт.", + "privacy.unlisted.additional": "Това действие е точно като публичното, с изключение на това, че публикацията няма да се появява в каналите на живо, хаштаговете, разглеждането или търсенето в Mastodon, дори ако сте избрали да се публично видими на ниво акаунт.", "privacy.unlisted.long": "По-малко алгоритмични фанфари", "privacy.unlisted.short": "Тиха публика", "privacy_policy.last_updated": "Последно осъвременяване на {date}", diff --git a/app/javascript/mastodon/locales/ie.json b/app/javascript/mastodon/locales/ie.json index d39aa6cf61..0c21832ed6 100644 --- a/app/javascript/mastodon/locales/ie.json +++ b/app/javascript/mastodon/locales/ie.json @@ -158,6 +158,7 @@ "compose_form.save_changes": "Actualisar", "compose_form.spoiler.marked": "Remover avise pri li contenete", "compose_form.spoiler.unmarked": "Adjunter avise pri li contenete", + "compose_form.spoiler_placeholder": "Advertiment de contenete (optional)", "confirmation_modal.cancel": "Anullar", "confirmations.block.block_and_report": "Bloccar & Raportar", "confirmations.block.confirm": "Bloccar", @@ -276,6 +277,12 @@ "follow_request.authorize": "Autorisar", "follow_request.reject": "Rejecter", "follow_requests.unlocked_explanation": "Benque tu conto ne es cludet, li administratores de {domain} pensat que tu fórsan vell voler tractar seque-petitiones de tis-ci contos manualmen.", + "follow_suggestions.curated_suggestion": "Selection del Servitor", + "follow_suggestions.dismiss": "Ne monstrar plu", + "follow_suggestions.personalized_suggestion": "Personalisat suggestion", + "follow_suggestions.popular_suggestion": "Populari suggestion", + "follow_suggestions.view_all": "Vider omnicos", + "follow_suggestions.who_to_follow": "Persones a sequer", "followed_tags": "Sequet hashtags", "footer.about": "Information", "footer.directory": "Profilarium", @@ -517,11 +524,15 @@ "poll_button.add_poll": "Adjunter un balotation", "poll_button.remove_poll": "Remover balotation", "privacy.change": "Changear li privatie del posta", + "privacy.direct.long": "Omnes mentionat in li posta", "privacy.direct.short": "Specific persones", "privacy.private.long": "Solmen tui sequitores", "privacy.private.short": "Sequitores", "privacy.public.long": "Quicunc in e ex Mastodon", "privacy.public.short": "Public", + "privacy.unlisted.additional": "It acte just quam public, except que li posta ne va aparir in tendentie o hashtags, explorar, o sercha de Mastodon, mem si tu ha optet por les sur tui tot conto.", + "privacy.unlisted.long": "Minu fanfare algoritmic", + "privacy.unlisted.short": "Quiet public", "privacy_policy.last_updated": "Ultimmen actualisat ye {date}", "privacy_policy.title": "Politica pri Privatie", "recommended": "Recomandat", @@ -539,7 +550,9 @@ "relative_time.minutes": "{number}m", "relative_time.seconds": "{number}s", "relative_time.today": "hodie", + "reply_indicator.attachments": "{count, plural, one {# atachament} other {# atachamentes}}", "reply_indicator.cancel": "Anullar", + "reply_indicator.poll": "Balotar", "report.block": "Bloccar", "report.block_explanation": "Tu ne va vider su postas. Li usator ni va posser vider tui postas, ni sequer te, ni va posser saver pri li statu de esser bloccat.", "report.categories.legal": "Legal", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index 7fb617518c..b69e93952b 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -11,11 +11,13 @@ "account.blocked": "Yettusewḥel", "account.browse_more_on_origin_server": "Snirem ugar deg umeɣnu aneẓli", "account.cancel_follow_request": "Withdraw follow request", + "account.copy": "Nɣel assaɣ ɣer umaɣnu", "account.disable_notifications": "Ḥbes ur iyi-d-ttazen ara ilɣa mi ara d-isuffeɣ @{name}", "account.domain_blocked": "Taɣult yeffren", "account.edit_profile": "Ẓreg amaɣnu", "account.enable_notifications": "Azen-iyi-d ilɣa mi ara d-isuffeɣ @{name}", "account.endorse": "Welleh fell-as deg umaɣnu-inek", + "account.featured_tags.last_status_never": "Ulac tisuffaɣ", "account.follow": "Ḍfer", "account.followers": "Imeḍfaren", "account.followers.empty": "Ar tura, ulac yiwen i yeṭṭafaṛen amseqdac-agi.", @@ -65,7 +67,7 @@ "bundle_modal_error.message": "Tella-d kra n tuccḍa mi d-yettali ugbur-agi.", "bundle_modal_error.retry": "Ɛreḍ tikelt-nniḍen", "closed_registrations_modal.find_another_server": "Aff-d aqeddac nniḍen", - "column.about": "Γef", + "column.about": "Ɣef", "column.blocks": "Imiḍanen yettusḥebsen", "column.bookmarks": "Ticraḍ", "column.community": "Tasuddemt tadigant", @@ -77,7 +79,7 @@ "column.lists": "Tibdarin", "column.mutes": "Imiḍanen yettwasgugmen", "column.notifications": "Tilɣa", - "column.pins": "Tijewwaqin yettwasenṭḍen", + "column.pins": "Tisuffaɣ yettwasenṭḍen", "column.public": "Tasuddemt tamatut", "column_back_button.label": "Tuɣalin", "column_header.hide_settings": "Ffer iɣewwaṛen", @@ -88,32 +90,36 @@ "column_header.unpin": "Kkes asenteḍ", "column_subheading.settings": "Iɣewwaṛen", "community.column_settings.local_only": "Adigan kan", - "community.column_settings.media_only": "Allal n teywalt kan", + "community.column_settings.media_only": "Imidyaten kan", "community.column_settings.remote_only": "Anmeggag kan", "compose.language.change": "Beddel tutlayt", "compose.language.search": "Nadi tutlayin …", "compose.published.open": "Ldi", "compose_form.direct_message_warning_learn_more": "Issin ugar", - "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.encryption_warning": "", + "compose_form.hashtag_warning": "", "compose_form.lock_disclaimer": "Amiḍan-ik·im ur yelli ara {locked}. Menwala yezmer ad k·kem-yeḍfeṛ akken ad iẓer acu tbeṭṭuḍ akked yimeḍfaṛen-ik·im.", "compose_form.lock_disclaimer.lock": "yettwacekkel", "compose_form.placeholder": "D acu i itezzin deg wallaɣ?", "compose_form.poll.duration": "Tanzagt n tefrant", + "compose_form.poll.option_placeholder": "Taxtiṛt {number}", "compose_form.poll.single": "Fren yiwen", - "compose_form.publish_form": "Suffeɣ", + "compose_form.publish_form": "Tasuffeɣt tamaynut", + "compose_form.reply": "Err", + "compose_form.save_changes": "Leqqem", "compose_form.spoiler.marked": "Kkes aḍris yettwaffren deffir n walɣu", "compose_form.spoiler.unmarked": "Rnu aḍris yettwaffren deffir n walɣu", "confirmation_modal.cancel": "Sefsex", "confirmations.block.block_and_report": "Sewḥel & sewɛed", "confirmations.block.confirm": "Sewḥel", - "confirmations.block.message": "Tebγiḍ s tidet ad tesḥebseḍ {name}?", + "confirmations.block.message": "Tebɣiḍ s tidet ad tesḥebseḍ {name}?", "confirmations.delete.confirm": "Kkes", "confirmations.delete.message": "Tebɣiḍ s tidet ad tekkseḍ tasuffeɣt-agi?", "confirmations.delete_list.confirm": "Kkes", "confirmations.delete_list.message": "Tebɣiḍ s tidet ad tekkseḍ umuɣ-agi i lebda?", "confirmations.discard_edit_media.confirm": "Sefsex", "confirmations.domain_block.confirm": "Ffer taɣult meṛṛa", + "confirmations.edit.confirm": "Ẓreg", "confirmations.logout.confirm": "Ffeɣ", "confirmations.logout.message": "D tidet tebɣiḍ ad teffɣeḍ?", "confirmations.mute.confirm": "Sgugem", @@ -133,12 +139,13 @@ "directory.local": "Seg {domain} kan", "directory.new_arrivals": "Imaynuten id yewḍen", "directory.recently_active": "Yermed xas melmi kan", - "disabled_account_banner.account_settings": "Iγewwaṛen n umiḍan", + "disabled_account_banner.account_settings": "Iɣewwaṛen n umiḍan", "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": "Ẓẓu addad-agi deg usmel-inek s wenγal n tangalt yellan sdaw-agi.", "embed.preview": "Akka ara d-iban:", "emoji_button.activity": "Aqeddic", + "emoji_button.clear": "Sfeḍ", "emoji_button.custom": "Udmawan", "emoji_button.flags": "Innayen", "emoji_button.food": "Tegwella & Tissit", @@ -153,7 +160,7 @@ "emoji_button.symbols": "Izamulen", "emoji_button.travel": "Imeḍqan d Yinigen", "empty_column.account_suspended": "Amiḍan yettwaḥbas", - "empty_column.account_timeline": "Ulac tijewwaqin dagi!", + "empty_column.account_timeline": "Ulac tisuffaɣ da !", "empty_column.account_unavailable": "Ur nufi ara amaɣnu-ayi", "empty_column.blocks": "Ur tesḥebseḍ ula yiwen n umseqdac ar tura.", "empty_column.bookmarked_statuses": "Ulac tijewwaqin i terniḍ ɣer yismenyifen-ik ar tura. Ticki terniḍ yiwet, ad d-tettwasken da.", @@ -174,7 +181,7 @@ "explore.suggested_follows": "Imdanen", "explore.title": "Snirem", "explore.trending_links": "Isallen", - "explore.trending_statuses": "Tisuffiɣin", + "explore.trending_statuses": "Tisuffaɣ", "explore.trending_tags": "Ihacṭagen", "filter_modal.added.settings_link": "asebter n yiɣewwaṛen", "filter_modal.select_filter.prompt_new": "Taggayt tamaynutt : {name}", @@ -183,8 +190,9 @@ "firehose.local": "Deg uqeddac-ayi", "follow_request.authorize": "Ssireg", "follow_request.reject": "Agi", - "footer.about": "Γef", - "footer.directory": "Akaram n imaγnuten", + "followed_tags": "Ihacṭagen yettwaḍfaren", + "footer.about": "Ɣef", + "footer.directory": "Akaram n imaɣnuten", "footer.get_app": "Awi-d asnas", "footer.invite": "Ɛreḍ-d kra n yimdanen", "footer.keyboard_shortcuts": "Inegzumen n unasiw", @@ -207,6 +215,7 @@ "home.column_settings.show_replies": "Ssken-d tiririyin", "home.hide_announcements": "Ffer ulɣuyen", "home.show_announcements": "Ssken-d ulɣuyen", + "interaction_modal.no_account_yet": "Ulac-ik·ikem deg Maṣṭudun?", "interaction_modal.on_this_server": "Deg uqeddac-ayi", "interaction_modal.title.follow": "Ḍfer {name}", "intervals.full.days": "{number, plural, one {# n wass} other {# n wussan}}", @@ -247,8 +256,8 @@ "lightbox.close": "Mdel", "lightbox.compress": "Ḥemmeẓ tamnaḍt n uskan n tugna", "lightbox.expand": "Simeɣer tamnaḍt n uskan n tugna", - "lightbox.next": "Γer zdat", - "lightbox.previous": "Γer deffir", + "lightbox.next": "Ɣer zdat", + "lightbox.previous": "Ɣer deffir", "link_preview.author": "S-ɣur {name}", "lists.account.add": "Rnu ɣer tebdart", "lists.account.remove": "Kkes seg tebdart", @@ -264,11 +273,12 @@ "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}}", - "media_gallery.toggle_visible": "Ffer {number, plural, one {tugna} other {tugniwin}}", + "loading_indicator.label": "Yessalay-d …", + "media_gallery.toggle_visible": "{number, plural, one {Ffer tugna} other {Ffer tugniwin}}", "mute_modal.duration": "Tanzagt", "mute_modal.hide_notifications": "Tebɣiḍ ad teffreḍ talɣutin n umseqdac-a?", "mute_modal.indefinite": "Ur yettwasbadu ara", - "navigation_bar.about": "Γef", + "navigation_bar.about": "Ɣef", "navigation_bar.blocks": "Imseqdacen yettusḥebsen", "navigation_bar.bookmarks": "Ticraḍ", "navigation_bar.community_timeline": "Tasuddemt tadigant", @@ -284,7 +294,7 @@ "navigation_bar.logout": "Ffeɣ", "navigation_bar.mutes": "Iseqdacen yettwasusmen", "navigation_bar.personal": "Udmawan", - "navigation_bar.pins": "Tijewwiqin yettwasentḍen", + "navigation_bar.pins": "Tisuffaɣ yettwasenṭḍen", "navigation_bar.preferences": "Imenyafen", "navigation_bar.public_timeline": "Tasuddemt tazayezt tamatut", "navigation_bar.search": "Nadi", @@ -311,7 +321,7 @@ "notifications.column_settings.reblog": "Seǧhed:", "notifications.column_settings.show": "Ssken-d tilɣa deg ujgu", "notifications.column_settings.sound": "Rmed imesli", - "notifications.column_settings.status": "Tiẓenẓunin timaynutin:", + "notifications.column_settings.status": "Tisuffaɣ timaynutin :", "notifications.filter.all": "Akk", "notifications.filter.boosts": "Seǧhed", "notifications.filter.favourites": "Imenyafen", @@ -325,11 +335,15 @@ "notifications.permission_denied": "D awezɣi ad yili wermad n yilɣa n tnarit axateṛ turagt tettwagdel.", "notifications_permission_banner.enable": "Rmed talɣutin n tnarit", "notifications_permission_banner.title": "Ur zeggel acemma", + "onboarding.action.back": "Tuɣalin ɣer deffir", + "onboarding.actions.back": "Tuɣalin ɣer deffir", "onboarding.actions.go_to_explore": "See what's trending", "onboarding.actions.go_to_home": "Go to your home feed", "onboarding.compose.template": "Azul a #Mastodon!", "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": "Isem ara d-yettwaskanen", + "onboarding.share.title": "Bḍu amaɣnu-inek·inem", "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.", @@ -365,7 +379,7 @@ "report.block": "Sewḥel", "report.categories.other": "Tiyyaḍ", "report.categories.spam": "Aspam", - "report.category.title_account": "ameγnu", + "report.category.title_account": "ameɣnu", "report.category.title_status": "tasuffeɣt", "report.close": "Immed", "report.forward": "Bren-it ɣeṛ {target}", @@ -383,6 +397,7 @@ "report_notification.open": "Ldi aneqqis", "search.placeholder": "Nadi", "search.search_or_paste": "Nadi neɣ senṭeḍ URL", + "search_popout.user": "amseqdac", "search_results.all": "Akk", "search_results.hashtags": "Ihacṭagen", "search_results.statuses": "Tisuffaɣ", @@ -405,7 +420,7 @@ "status.embed": "Seddu", "status.filtered": "Yettwasizdeg", "status.load_more": "Sali ugar", - "status.media_hidden": "Taɣwalt tettwaffer", + "status.media_hidden": "Amidya yettwaffer", "status.mention": "Bder-d @{name}", "status.more": "Ugar", "status.mute": "Sussem @{name}", @@ -425,7 +440,7 @@ "status.sensitive_warning": "Agbur amḥulfu", "status.share": "Bḍu", "status.show_less": "Ssken-d drus", - "status.show_less_all": "Semẓi akk tisuffγin", + "status.show_less_all": "Semẓi akk tisuffɣin", "status.show_more": "Ssken-d ugar", "status.show_more_all": "Ẓerr ugar lebda", "status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}", @@ -444,7 +459,7 @@ "timeline_hint.remote_resource_not_displayed": "{resource} seg yiqeddacen-nniḍen ur d-ttwaskanent ara.", "timeline_hint.resources.followers": "Imeḍfaṛen", "timeline_hint.resources.follows": "T·Yeṭafaṛ", - "timeline_hint.resources.statuses": "Tijewwaqin tiqdimin", + "timeline_hint.resources.statuses": "Tisuffaɣ tiqdimin", "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} in the past {days, plural, one {day} other {# days}}", "trends.trending_now": "Ayen mucaɛen tura", "ui.beforeunload": "Arewway-ik·im ad iruḥ ma yella tefeɣ-d deg Maṣṭudun.", @@ -465,7 +480,7 @@ "upload_modal.choose_image": "Fren tugna", "upload_modal.description_placeholder": "Aberraɣ arurad ineggez nnig n uqjun amuṭṭis", "upload_modal.detect_text": "Sefru-d aḍris seg tugna", - "upload_modal.edit_media": "Ẓreg taɣwalt", + "upload_modal.edit_media": "Ẓreg amidya", "upload_modal.preparing_ocr": "Aheyyi n OCR…", "upload_modal.preview_label": "Taskant ({ratio})", "upload_progress.label": "Asali iteddu...", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index ad7837cab2..da76e98687 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -523,6 +523,7 @@ "poll_button.add_poll": "Pridaj anketu", "poll_button.remove_poll": "Odstráň anketu", "privacy.change": "Uprav súkromie príspevku", + "privacy.direct.long": "Všetci spomenutí v príspevku", "privacy.direct.short": "Konkrétni ľudia", "privacy.private.long": "Iba tvoji nasledovatelia", "privacy.private.short": "Sledovatelia", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 72ecb11ed1..e0aa072a77 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -279,8 +279,8 @@ "follow_requests.unlocked_explanation": "แม้ว่าไม่มีการล็อคบัญชีของคุณ พนักงานของ {domain} คิดว่าคุณอาจต้องการตรวจทานคำขอติดตามจากบัญชีเหล่านี้ด้วยตนเอง", "follow_suggestions.curated_suggestion": "คัดสรรโดยบรรณาธิการ", "follow_suggestions.dismiss": "ไม่ต้องแสดงอีก", - "follow_suggestions.personalized_suggestion": "คำแนะนำเฉพาะบุคคล", - "follow_suggestions.popular_suggestion": "คำแนะนำยอดนิยม", + "follow_suggestions.personalized_suggestion": "ข้อเสนอแนะเฉพาะบุคคล", + "follow_suggestions.popular_suggestion": "ข้อเสนอแนะยอดนิยม", "follow_suggestions.view_all": "ดูทั้งหมด", "follow_suggestions.who_to_follow": "ติดตามใครดี", "followed_tags": "แฮชแท็กที่ติดตาม", diff --git a/app/javascript/mastodon/locales/tok.json b/app/javascript/mastodon/locales/tok.json index 85f62f404a..4d2cc3d1dc 100644 --- a/app/javascript/mastodon/locales/tok.json +++ b/app/javascript/mastodon/locales/tok.json @@ -2,6 +2,9 @@ "about.blocks": "ma lawa", "about.contact": "toki:", "about.domain_blocks.no_reason_available": "mi sona ala e tan", + "about.domain_blocks.preamble": "ilo Masoton li ken e ni: sina lukin e toki jan pi ma ilo mute. sina ken toki tawa ona lon kulupu ma. taso, ma ni li ken ala e ni tawa ma ni:", + "about.domain_blocks.silenced.explanation": "sina lukin ala e toki e jan tan ma ni. taso, sina wile la, sina ken ni.", + "about.domain_blocks.silenced.title": "ken lili lukin", "about.domain_blocks.suspended.title": "weka", "about.not_available": "lon kulupu ni la sina ken alasa ala e sona ni.", "about.rules": "lawa kulupu", @@ -32,6 +35,7 @@ "account.follows.empty": "jan ni li kute e jan ala", "account.go_to_profile": "o tawa lipu jan", "account.hide_reblogs": "o lukin ala e pana toki tan @{name}", + "account.in_memoriam": "jan ni li moli. pona o tawa ona.", "account.languages": "sina wile lukin e sitelen pi toki seme", "account.locked_info": "sina wile kute e jan ni la ona o toki e ken", "account.media": "sitelen", @@ -53,6 +57,7 @@ "account.unblock": "o weka ala e jan {name}", "account.unblock_domain": "o weka ala e ma {domain}", "account.unblock_short": "o pini weka", + "account.unendorse": "lipu jan la o suli ala e ni", "account.unfollow": "o pini kute", "account.unmute": "o len ala e @{name}", "account.unmute_notifications_short": "o kute e mu tan jan ni", @@ -65,6 +70,9 @@ "alert.unexpected.title": "pakala a!", "announcement.announcement": "toki suli", "audio.hide": "o len e kalama", + "boost_modal.combo": "sina ken luka e nena {combo} tawa ni: sina wile ala luka e nena lon tenpo kama", + "bundle_column_error.copy_stacktrace": "o awen e sona pakala lon ilo sina", + "bundle_column_error.error.body": "ilo li ken ala pana e lipu ni. ni li ken tan pakala ilo.", "bundle_column_error.error.title": "ike a!", "bundle_column_error.network.title": "pakala la ilo sina li toki ala tawa ilo ante", "bundle_column_error.retry": "o ni sin", @@ -75,7 +83,9 @@ "bundle_modal_error.message": "ilo li wile kama e ijo ni, taso pakala li lon.", "bundle_modal_error.retry": "o ni sin", "closed_registrations_modal.find_another_server": "o alasa e ma ante", + "column.about": "sona", "column.blocks": "kulupu pi jan weka", + "column.bookmarks": "awen toki", "column.home": "lipu open", "column.lists": "kulupu lipu", "column.mutes": "jan len", diff --git a/config/locales/de.yml b/config/locales/de.yml index b77f415190..57ce5268a8 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -979,7 +979,7 @@ de: next_steps: Du kannst dem Einspruch zustimmen, um die Moderationsentscheidung rückgängig zu machen, oder ihn ignorieren. subject: "%{username} hat Einspruch gegen eine Moderationsentscheidung auf %{instance} erhoben" new_critical_software_updates: - body: Kritische Updates wurden für Mastodon veröffentlicht – du solltest so schnell wie möglich aktualisieren! + body: ein neues Sicherheitsupdate wurde veröffentlicht. Du solltest Mastodon so schnell wie möglich aktualisieren! subject: Kritische Mastodon-Updates sind für %{instance} verfügbar! new_pending_account: body: Die Details von diesem neuem Konto sind unten. Du kannst die Anfrage akzeptieren oder ablehnen. @@ -1023,7 +1023,7 @@ de: salutation: "%{name}," settings: 'E-Mail-Einstellungen ändern: %{link}' unsubscribe: Abbestellen - view: 'Hier überprüfen:' + view: 'Siehe:' view_profile: Profil anzeigen view_status: Beitrag anschauen applications: diff --git a/config/locales/devise.be.yml b/config/locales/devise.be.yml index 18785d16ab..81f3120a88 100644 --- a/config/locales/devise.be.yml +++ b/config/locales/devise.be.yml @@ -12,6 +12,7 @@ be: last_attempt: У вас ёсць яшчэ адна спроба, перш чым ваш рахунак будзе заблакаваны locked: Ваш уліковы запіс заблакіраваны. not_found_in_database: Няправільны %{authentication_keys} або пароль. + omniauth_user_creation_failure: Памылка пры стварэнні ўліковага запісу для гэтай асобы. pending: Ваш уліковы запіс яшчэ разглядаецца. timeout: Ваш сеанс скончыўся. Каб працягнуць, увайдзіце яшчэ раз. unauthenticated: Вам патрэбна зайсьці альбо зарэгістравацца, каб працягнуць diff --git a/config/locales/devise.ca.yml b/config/locales/devise.ca.yml index 3720d3c5f7..9b4ccccff7 100644 --- a/config/locales/devise.ca.yml +++ b/config/locales/devise.ca.yml @@ -14,6 +14,7 @@ ca: last_attempt: Tens un intent més abans no es bloqui el teu compte. locked: El teu compte s'ha blocat. not_found_in_database: "%{authentication_keys} o contrasenya no són vàlids." + omniauth_user_creation_failure: S'ha produït un error en crear un compte per a aquesta identitat. pending: El teu compte encara està en revisió. timeout: La teva sessió ha expirat. Torna a iniciar-la per a continuar. unauthenticated: Necessites iniciar sessió o registrar-te abans de continuar. diff --git a/config/locales/devise.da.yml b/config/locales/devise.da.yml index daf802cdb7..c472242ba7 100644 --- a/config/locales/devise.da.yml +++ b/config/locales/devise.da.yml @@ -12,6 +12,7 @@ da: last_attempt: Du har ét forsøg mere, før din konto bliver låst. locked: Din konto er låst. not_found_in_database: Ugyldig %{authentication_keys} eller adgangskode. + omniauth_user_creation_failure: Fejl under oprettelse af konto for denne identitet. pending: Din konto er stadig under revision. timeout: Session udløbet. Log ind igen for at fortsætte. unauthenticated: Log ind eller tilmeld dig for at fortsætte. diff --git a/config/locales/devise.de.yml b/config/locales/devise.de.yml index cf05ddc16b..7982f8a743 100644 --- a/config/locales/devise.de.yml +++ b/config/locales/devise.de.yml @@ -12,6 +12,7 @@ de: last_attempt: Du hast nur noch einen Versuch, bevor dein Zugang gesperrt wird. locked: Dein Konto ist gesperrt. not_found_in_database: "%{authentication_keys} oder Passwort ungültig." + omniauth_user_creation_failure: Fehler beim Erstellen eines Kontos für diese Identität. pending: Dein Konto wird weiterhin überprüft. timeout: Deine Sitzung ist abgelaufen. Bitte melde dich erneut an, um fortzufahren. unauthenticated: Du musst dich anmelden oder registrieren, bevor du fortfahren kannst. diff --git a/config/locales/devise.es-AR.yml b/config/locales/devise.es-AR.yml index ca60ee5deb..6249294597 100644 --- a/config/locales/devise.es-AR.yml +++ b/config/locales/devise.es-AR.yml @@ -12,6 +12,7 @@ es-AR: last_attempt: Tenés un intento más antes de que se bloquee tu cuenta. locked: Se bloqueó tu cuenta. not_found_in_database: "%{authentication_keys} o contraseña no válidas." + omniauth_user_creation_failure: Error al crear una cuenta para esta identidad. pending: Tu cuenta todavía está bajo revisión. timeout: Venció tu sesión. Por favor, volvé a iniciar sesión para continuar. unauthenticated: Necesitás iniciar sesión o registrarte antes de continuar. diff --git a/config/locales/devise.eu.yml b/config/locales/devise.eu.yml index 624f9ee93d..3e675659fe 100644 --- a/config/locales/devise.eu.yml +++ b/config/locales/devise.eu.yml @@ -12,6 +12,7 @@ eu: last_attempt: Saiakera bat geratzen zaizu zure kontua giltzapetu aurretik. locked: Zure kontua giltzapetuta dago. not_found_in_database: Baliogabeko %{authentication_keys} edo pasahitza. + omniauth_user_creation_failure: Errorea identitate honen kontu bat sortzean. pending: Zure kontua oraindik berrikusteke dago. timeout: Zure saioa iraungitu da. Hasi saioa berriro jarraitzeko. unauthenticated: Saioa hasi edo izena eman behar duzu jarraitu aurretik. diff --git a/config/locales/devise.fi.yml b/config/locales/devise.fi.yml index 66616d16b1..003d48417b 100644 --- a/config/locales/devise.fi.yml +++ b/config/locales/devise.fi.yml @@ -12,6 +12,7 @@ fi: last_attempt: Sinulla on vielä yksi yritys ennen kuin tilisi lukitaan. locked: Tilisi on lukittu. not_found_in_database: Virheellinen %{authentication_keys} tai salasana. + omniauth_user_creation_failure: Virhe luotaessa tiliä tälle henkilöllisyydelle. pending: Tilisi on vielä tarkistamatta. timeout: Istuntosi on vanhentunut. Jatkaaksesi käyttöä, kirjaudu uudelleen. unauthenticated: Sinun on kirjauduttava tai rekisteröidyttävä ennen kuin voit jatkaa. diff --git a/config/locales/devise.fo.yml b/config/locales/devise.fo.yml index 1f7708bb44..30f83ba0da 100644 --- a/config/locales/devise.fo.yml +++ b/config/locales/devise.fo.yml @@ -12,6 +12,7 @@ fo: last_attempt: Tú kanst royna einaferð afturat áðrenn kontan verður stongd. locked: Kontan hjá tær er læst. not_found_in_database: Ogyldigur %{authentication_keys} ella loyniorð. + omniauth_user_creation_failure: Feilur í sambandi við, at ein konta fyri hendan samleikan bleiv stovnað. pending: Kontan hjá tær verður kannað enn. timeout: Tín innritan er útgingin. Innrita av nýggjum, fyri at hada fram. unauthenticated: Tú mást skriva teg inn aftur fyri at halda fram. diff --git a/config/locales/devise.fy.yml b/config/locales/devise.fy.yml index 05fd7b8071..c8a04a7405 100644 --- a/config/locales/devise.fy.yml +++ b/config/locales/devise.fy.yml @@ -12,6 +12,7 @@ fy: last_attempt: Jo hawwe noch ien besykjen oer eardat jo account blokkearre wurdt. locked: Jo account is blokkearre. not_found_in_database: "%{authentication_keys} of wachtwurd ûnjildich." + omniauth_user_creation_failure: Flater by it oanmeitsjen fan in account foar dizze identiteit. pending: Jo account moat noch hieltyd beoardiele wurde. timeout: Jo sesje is ferrûn. Meld jo opnij oan om troch te gean. unauthenticated: Jo moatte oanmelde of registrearje. diff --git a/config/locales/devise.gl.yml b/config/locales/devise.gl.yml index b9f4a0a005..00b1824808 100644 --- a/config/locales/devise.gl.yml +++ b/config/locales/devise.gl.yml @@ -12,6 +12,7 @@ gl: last_attempt: Tes un intento máis antes de que a túa conta fique bloqueada. locked: A túa conta está bloqueada. not_found_in_database: "%{authentication_keys} ou contrasinal non válidos." + omniauth_user_creation_failure: Erro ao crear unha conta para esta identidade. pending: A túa conta aínda está baixo revisión. timeout: A túa sesión caducou. Accede outra vez para continuar. unauthenticated: Precisas iniciar sesión ou rexistrarte antes de continuar. diff --git a/config/locales/devise.he.yml b/config/locales/devise.he.yml index f2ec3a6716..02e307ae1c 100644 --- a/config/locales/devise.he.yml +++ b/config/locales/devise.he.yml @@ -12,6 +12,7 @@ he: last_attempt: יש לך עוד ניסיון אחד לפני נעילת החשבון. locked: חשבון זה נעול. not_found_in_database: "%{authentication_keys} או סיסמה לא נכונים." + omniauth_user_creation_failure: שגיאה ביצירת חשבון לזהות הזו. pending: חשבונך נמצא עדיין בבדיקה. timeout: פג תוקף השהיה בחשבון. נא להכנס מחדש על מנת להמשיך. unauthenticated: יש להרשם או להכנס לחשבון על מנת להמשיך. diff --git a/config/locales/devise.hu.yml b/config/locales/devise.hu.yml index fea56ab24a..8c9fdf6a50 100644 --- a/config/locales/devise.hu.yml +++ b/config/locales/devise.hu.yml @@ -12,6 +12,7 @@ hu: last_attempt: Már csak egy próbálkozásod maradt, mielőtt a fiókodat zároljuk. locked: A fiókodat zároltuk. not_found_in_database: Helytelen %{authentication_keys} vagy jelszó. + omniauth_user_creation_failure: Hiba történt a fiók létrehozása során ehhez az identitáshoz. pending: A fiókod még engedélyezésre vár. timeout: A munkameneted lejárt. A folytatáshoz jelentkezz be újra. unauthenticated: A folytatás előtt be kell jelentkezned vagy regisztrálnod kell. diff --git a/config/locales/devise.ie.yml b/config/locales/devise.ie.yml index 332c9da456..9c82bd4529 100644 --- a/config/locales/devise.ie.yml +++ b/config/locales/devise.ie.yml @@ -12,6 +12,7 @@ ie: last_attempt: Hay solmen un prova ante que tui conto deveni serrat. locked: Tui conto es serrat. not_found_in_database: Ínvalid %{authentication_keys} o passa-parol. + omniauth_user_creation_failure: Errore in li creation de un conto por ti-ci identitá. pending: Tui conto es ancor sub revision. timeout: Tui session ha expirat. Ples reintrar denov por continuar. unauthenticated: Tu deve intrar o registrar te ante continuar. diff --git a/config/locales/devise.is.yml b/config/locales/devise.is.yml index 12015fa29d..a045bdd80c 100644 --- a/config/locales/devise.is.yml +++ b/config/locales/devise.is.yml @@ -12,6 +12,7 @@ is: last_attempt: Þú getur reynt einu sinni í viðbót áður en aðgangnum þínum verður læst. locked: Notandaaðgangurinn þinn er læstur. not_found_in_database: Ógilt %{authentication_keys} eða lykilorð. + omniauth_user_creation_failure: Villa við að útbúa aðgang fyrir þetta auðkenni. pending: Notandaaðgangurinn þinn er enn til yfirferðar. timeout: Setan þín er útrunnin. Skráðu þig aftur inn til að halda áfram. unauthenticated: Þú þarft að skrá þig inn eða nýskrá þig áður en lengra er haldið. diff --git a/config/locales/devise.it.yml b/config/locales/devise.it.yml index 19bd999aad..8aaea3c15b 100644 --- a/config/locales/devise.it.yml +++ b/config/locales/devise.it.yml @@ -12,6 +12,7 @@ it: last_attempt: Hai un altro tentativo, prima che il tuo profilo venga bloccato. locked: Il tuo profilo è bloccato. not_found_in_database: "%{authentication_keys} o password non valida." + omniauth_user_creation_failure: Errore nella creazione di un account per questa identità. pending: Il tuo profilo è ancora in revisione. timeout: La tua sessione è scaduta. Sei pregato di accedere nuovamente per continuare. unauthenticated: Devi accedere o registrarti, per continuare. diff --git a/config/locales/devise.kab.yml b/config/locales/devise.kab.yml index 2f60629fd7..f878a5b503 100644 --- a/config/locales/devise.kab.yml +++ b/config/locales/devise.kab.yml @@ -13,13 +13,13 @@ kab: locked: Amiḍan-ik yettwargel. not_found_in_database: Tella tuccḍa deg %{authentication_keys} neγ deg wawal uffir. pending: Amiḍan-inek mazal-it deg ɛiwed n tmuγli. - timeout: Tiγimit n tuqqna tezri. Ma ulac aγilif ɛiwed tuqqna akken ad tkemmleḍ. - unauthenticated: Ilaq ad teqqneḍ neγ ad tjerrḍeḍ akken ad tkemmelḍ. + timeout: Tiɣimit n tuqqna tezri. Ma ulac aɣilif ɛiwed tuqqna akken ad tkemmleḍ. + unauthenticated: Ilaq ad teqqneḍ neɣ ad tjerrḍeḍ akken ad tkemmelḍ. unconfirmed: Ilaq ad wekdeḍ tansa-inek imayl akken ad tkemmelḍ. mailer: confirmation_instructions: action: Senqed tansa-inek imayl - action_with_app: Wekked sakkin uγal γer %{app} + action_with_app: Sentem sakkin uɣal ɣer %{app} explanation: Aqla-k terniḍ amiḍan deg %{host} s tansa imayl-agi. Mazal-ak yiwen utekki akken ad t-tremdeḍ. Ma mačči d kečč i yessutren ay-agi, ttxil-k ssinef izen-a. explanation_when_pending: Tsutreḍ-d ajerred deg %{host} s tansa-agi imayl. Ad nγeṛ asuter-ik ticki tsentmeḍ tansa-ik imayl. Send asentem, ur tezmireḍ ara ad teqqneḍ γer umiḍan-ik. Ma yella nugi asuter-ik, isefka-ik ad ttwakksen seg uqeddac, ihi ulac tigawt-nniḍen ara k-d-yettuqeblen. Ma mačči d kečč i yellan deffir n usuter-agi, ttxil-k ssinef izen-agi. extra_html: Ttxil-k ẓer daγen ilugan n uqeddac akked twetlin n useqdec-nneγ. @@ -87,7 +87,7 @@ kab: unlocks: send_instructions: Deg kra n tesdatin, ad teṭṭfeḍ imayl deg-s iwellihen i yilaqen i userreḥ n umiḍan-ik·im. Ma yella ur tufiḍ ara izen-agi, ttxil-k·m ẓer deg ukaram spam. send_paranoid_instructions: Ma yella umiḍan-ik·im yella, ad teṭṭfeḍ imayl deg tesdatin i d-iteddun, deg-s iwellihen i yilaqen i userreḥ n umiḍan-ik·im. Ma yella ur tufiḍ ara izen-agi, ttxil-k·m ẓer deg ukaram spam. - unlocked: Iserreḥ umiḍan-ik·im akken iwata. ttxil qqen akken ad tkemleḍ. + unlocked: Iserreḥ umiḍan-ik·im akken iwata. Ttxil qqen akken ad tkemleḍ. errors: messages: already_confirmed: ittwasentem yakan, ttxil εreḍ ad teqneḍ diff --git a/config/locales/devise.ko.yml b/config/locales/devise.ko.yml index 0c848e4bac..198d44a4f7 100644 --- a/config/locales/devise.ko.yml +++ b/config/locales/devise.ko.yml @@ -12,6 +12,7 @@ ko: last_attempt: 계정이 잠기기까지 한 번의 시도가 남았습니다. locked: 계정이 잠겼습니다. not_found_in_database: 올바르지 않은 %{authentication_keys} 혹은 암호입니다. + omniauth_user_creation_failure: 이 신원으로 계정을 만드는데 실패했습니다. pending: 이 계정은 아직 검토 중입니다. timeout: 세션이 만료되었습니다. 다시 로그인 하세요. unauthenticated: 계속 하려면 로그인을 해야 합니다. diff --git a/config/locales/devise.lad.yml b/config/locales/devise.lad.yml index d2ce53760c..7d447140f4 100644 --- a/config/locales/devise.lad.yml +++ b/config/locales/devise.lad.yml @@ -12,6 +12,7 @@ lad: last_attempt: Aprova una vez mas antes de ke tu kuento sea blokado. locked: Tu kuento esta blokado. not_found_in_database: Inkorekto %{authentication_keys} o kod. + omniauth_user_creation_failure: Ay un error en kriyar un kuento para esta identita. pending: Tu kuento ainda esta basho revizyon. timeout: Tu sesyon tiene kadukado. Por favor konektate kon tu kuento de muevo para kontinuar. unauthenticated: Kale konektarte kon tu kuento o enregistrarte antes de kontinuar. diff --git a/config/locales/devise.nl.yml b/config/locales/devise.nl.yml index 0aaf376f7f..ab6ae84db4 100644 --- a/config/locales/devise.nl.yml +++ b/config/locales/devise.nl.yml @@ -12,6 +12,7 @@ nl: last_attempt: Je hebt nog één poging over voordat jouw account wordt opgeschort. locked: Jouw account is opgeschort. not_found_in_database: "%{authentication_keys} of wachtwoord ongeldig." + omniauth_user_creation_failure: Fout bij het aanmaken van een account voor deze identiteit. pending: Jouw account moet nog steeds worden beoordeeld. timeout: Jouw sessie is verlopen, log opnieuw in. unauthenticated: Je dient in te loggen of te registreren. diff --git a/config/locales/devise.pl.yml b/config/locales/devise.pl.yml index a6d48f11ef..f34fd04633 100644 --- a/config/locales/devise.pl.yml +++ b/config/locales/devise.pl.yml @@ -12,6 +12,7 @@ pl: last_attempt: Masz jeszcze jedną próbę; Twoje konto zostanie zablokowane jeśli się nie powiedzie. locked: Twoje konto zostało zablokowane. not_found_in_database: Nieprawidłowy %{authentication_keys} lub hasło. + omniauth_user_creation_failure: Błąd przy tworzeniu konta dla tej tożsamości. pending: Twoje konto oczekuje na przegląd. timeout: Twoja sesja wygasła. Zaloguj się ponownie, aby kontynuować.. unauthenticated: Zapisz się lub zaloguj, aby kontynuować. diff --git a/config/locales/devise.pt-PT.yml b/config/locales/devise.pt-PT.yml index c169ddeb97..c66181fc5b 100644 --- a/config/locales/devise.pt-PT.yml +++ b/config/locales/devise.pt-PT.yml @@ -12,6 +12,7 @@ pt-PT: last_attempt: Tem só mais uma tentativa antes da sua conta ser bloqueada. locked: A tua conta está bloqueada. not_found_in_database: "%{authentication_keys} ou palavra-passe inválida." + omniauth_user_creation_failure: Erro ao criar uma conta para esta identidade. pending: A sua conta está ainda a aguardar revisão. timeout: A tua sessão expirou. Por favor, entra de novo para continuares. unauthenticated: Precisas de entrar na tua conta ou de te registares antes de continuar. diff --git a/config/locales/devise.sk.yml b/config/locales/devise.sk.yml index 3eb4b5304c..bc01b73ccf 100644 --- a/config/locales/devise.sk.yml +++ b/config/locales/devise.sk.yml @@ -12,6 +12,7 @@ sk: last_attempt: Máš posledný pokus pred zamknutím tvojho účtu. locked: Tvoj účet je zamknutý. not_found_in_database: Nesprávny %{authentication_keys}, alebo heslo. + omniauth_user_creation_failure: Chyba pri vytváraní účtu pre túto identitu. pending: Tvoj účet je stále prehodnocovaný. timeout: Tvoja aktívna sezóna vypršala. Pre pokračovanie sa prosím prihlás znovu. unauthenticated: K pokračovaniu sa musíš zaregistrovať alebo prihlásiť. diff --git a/config/locales/devise.sl.yml b/config/locales/devise.sl.yml index 2d567e63f4..0eb9b6330a 100644 --- a/config/locales/devise.sl.yml +++ b/config/locales/devise.sl.yml @@ -12,6 +12,7 @@ sl: last_attempt: Pred zaklepom računa imate še en poskus. locked: Vaš račun je zaklenjen. not_found_in_database: Neveljavno %{authentication_keys} ali geslo. + omniauth_user_creation_failure: Napaka pri ustvarjanju računa za to identiteto. pending: Vaš račun je še vedno pod drobnogledom. timeout: Vaša seja je potekla. Če želite nadaljevati, se znova prijavite. unauthenticated: Pred nadaljevanjem se morate prijaviti ali vpisati. diff --git a/config/locales/devise.sq.yml b/config/locales/devise.sq.yml index 32136a0baa..76dd493245 100644 --- a/config/locales/devise.sq.yml +++ b/config/locales/devise.sq.yml @@ -12,6 +12,7 @@ sq: last_attempt: Mund të provoni edhe një herë, përpara se llogaria juaj të kyçet. locked: Llogaria juaj është e kyçur. not_found_in_database: "%{authentication_keys} ose fjalëkalim i pavlefshëm." + omniauth_user_creation_failure: Gabim në krijim llogarie për këtë identitet. pending: Llogaria juaj është ende nën shqyrtim. timeout: Sesioni juaj ka skaduar. Ju lutemi, që të vazhdohet, ribëni hyrjen. unauthenticated: Përpara se të vazhdohet më tej, lypset të bëni hyrjen ose të regjistroheni. diff --git a/config/locales/devise.sr-Latn.yml b/config/locales/devise.sr-Latn.yml index c48ed87dca..3947b2d84f 100644 --- a/config/locales/devise.sr-Latn.yml +++ b/config/locales/devise.sr-Latn.yml @@ -12,6 +12,7 @@ sr-Latn: last_attempt: Imate još jedan pokušaj pre nego što Vaš nalog bude zaključan. locked: Vaš nalog je zaključan. not_found_in_database: Neispravna %{authentication_keys} ili lozinka. + omniauth_user_creation_failure: Greška pri kreiranju naloga za ovaj identitet. pending: Vaš račun je još uvek u pregledu. timeout: Vreme trajanja Vaše sesije je isteklo. Za nastavak prijavite se ponovo. unauthenticated: Za nastavak se morate prijaviti ili registrovati. diff --git a/config/locales/devise.sr.yml b/config/locales/devise.sr.yml index 3e49cf97ee..a4c08dfaf0 100644 --- a/config/locales/devise.sr.yml +++ b/config/locales/devise.sr.yml @@ -12,6 +12,7 @@ sr: last_attempt: Имате још један покушај пре него што Ваш налог буде закључан. locked: Ваш налог је закључан. not_found_in_database: Неисправна %{authentication_keys} или лозинка. + omniauth_user_creation_failure: Грешка при креирању налога за овај идентитет. pending: Ваш налог се још увек прегледа. timeout: Ваша сесија је истекла. Пријавите се поново да бисте наставили. unauthenticated: Морате да се пријавите или региструјете пре него што наставите. diff --git a/config/locales/devise.tr.yml b/config/locales/devise.tr.yml index 66ca9b2816..e709d3fff1 100644 --- a/config/locales/devise.tr.yml +++ b/config/locales/devise.tr.yml @@ -12,6 +12,7 @@ tr: last_attempt: Hesabınız kilitlenmeden önce bir kez daha denemeniz gerekir. locked: Hesabınız kilitlendi. not_found_in_database: Geçersiz %{authentication_keys} ya da parola. + omniauth_user_creation_failure: Bu kimlik için hesap oluşturmada hata. pending: Hesabınız hala inceleniyor. timeout: Oturum süreniz sona erdi. Lütfen devam etmek için tekrar giriş yapınız. unauthenticated: Devam etmeden önce oturum açmanız veya kayıt olmanız gerek. diff --git a/config/locales/devise.uk.yml b/config/locales/devise.uk.yml index 3b3883fa9c..65e89a274f 100644 --- a/config/locales/devise.uk.yml +++ b/config/locales/devise.uk.yml @@ -12,6 +12,7 @@ uk: last_attempt: У вас залишилась ще одна спроба, після якої ваш обліковий запис буде заблоковано. locked: Ваш обліковий запис заблоковано. not_found_in_database: Неправильний %{authentication_keys} або пароль. + omniauth_user_creation_failure: Помилка створення облікового запису для цієї особи. pending: Ваш обліковий запис ще перебуває на розгляді. timeout: Час сеансу минув. Будь ласка, увійдіть знову, щоб продовжити. unauthenticated: Щоб продовжити, увійдіть або зареєструйтеся. diff --git a/config/locales/devise.zh-CN.yml b/config/locales/devise.zh-CN.yml index 9b4b3ae203..3eb722b961 100644 --- a/config/locales/devise.zh-CN.yml +++ b/config/locales/devise.zh-CN.yml @@ -12,6 +12,7 @@ zh-CN: last_attempt: 你只有最后一次尝试机会,若未通过,帐号将被锁定。 locked: 你的账户已被锁定。 not_found_in_database: "%{authentication_keys}或密码错误。" + omniauth_user_creation_failure: 为此身份创建账户时出错。 pending: 你的账号仍在审核中。 timeout: 你的会话已过期。请重新登录再继续操作。 unauthenticated: 继续操作前请注册或者登录。 diff --git a/config/locales/devise.zh-HK.yml b/config/locales/devise.zh-HK.yml index 7f728bf0ad..a2620a8e4a 100644 --- a/config/locales/devise.zh-HK.yml +++ b/config/locales/devise.zh-HK.yml @@ -12,6 +12,7 @@ zh-HK: last_attempt: 若你再一次嘗試失敗,我們將鎖定你的帳號,以策安全。 locked: 你的帳號已被鎖定。 not_found_in_database: 不正確的%{authentication_keys}或密碼。 + omniauth_user_creation_failure: 為此身份建立帳號時出錯。 pending: 你的帳號仍在審核中 timeout: 你的登入階段已經過期,請重新登入以繼續使用。 unauthenticated: 你必須先登入或登記,以繼續使用。 diff --git a/config/locales/devise.zh-TW.yml b/config/locales/devise.zh-TW.yml index 06438971a7..7ead831e4f 100644 --- a/config/locales/devise.zh-TW.yml +++ b/config/locales/devise.zh-TW.yml @@ -12,6 +12,7 @@ zh-TW: last_attempt: 帳號鎖定前,您還有最後一次嘗試機會。 locked: 已鎖定您的帳號。 not_found_in_database: 無效的 %{authentication_keys} 或密碼。 + omniauth_user_creation_failure: 以此身分新增帳號時發生錯誤。 pending: 您的帳號仍在審核中。 timeout: 登入階段逾時。請重新登入以繼續。 unauthenticated: 您必須先登入或註冊才能繼續使用。 diff --git a/config/locales/doorkeeper.kab.yml b/config/locales/doorkeeper.kab.yml index fe1a8d9c50..d7f8904a35 100644 --- a/config/locales/doorkeeper.kab.yml +++ b/config/locales/doorkeeper.kab.yml @@ -36,7 +36,7 @@ kab: application: Asnas callback_url: URL n tririt n wawal delete: Kkes - empty: Ulac γur-ek·em isnasen. + empty: Ulac ɣur-k·m isnasen. name: Isem new: Asnas amaynut show: Ẓer @@ -57,7 +57,7 @@ kab: new: title: Tlaq tsiregt show: - title: Nγel tangalt n wurag sakkin senteḍ-itt deg usnas. + title: Nɣel tangalt n wurag sakkin senteḍ-itt deg usnas. authorized_applications: buttons: revoke: Ḥwi @@ -113,13 +113,13 @@ kab: read:notifications: ẓer tilγa-ik read:reports: ẓer ineqqisen-ik·im read:search: anadi deg umkan-ik·im - read:statuses: ẓer meṛṛa tisuffaγ + read:statuses: ẓer meṛṛa tisuffaɣ write: beddel meṛṛa isefka n umiḍan-ik write:accounts: ẓreg amaγnu-ik write:blocks: seḥbes imiḍanen d tγula - write:bookmarks: ad yernu tisuffγin γer ticraḍ + write:bookmarks: ad yernu tisuffaɣ ɣer ticraḍ write:filters: rnu-d imsizedgen write:follows: ḍfeṛ imdanen write:lists: ad yesnulfu tibdarin - write:media: ad yessali ifayluyen n teγwalt + write:media: ad yessali ifuyla n umidya write:notifications: sfeḍ tilɣa-k·m diff --git a/config/locales/ie.yml b/config/locales/ie.yml index a8287da533..7ab7f953be 100644 --- a/config/locales/ie.yml +++ b/config/locales/ie.yml @@ -1793,6 +1793,12 @@ ie: extra: It es ja pret a descargar! subject: Tui archive es pret por descargar title: Descargar archive + failed_2fa: + details: 'Vi li detallies del prova de intrar:' + explanation: Alqui provat accesser tui conto ma usat un ínvalid duesim factor de autentication. + further_actions_html: Si it ne esset tu, noi recomanda que tu strax %{action} nam li conto posse esser compromisset. + subject: Falliment de autentication de duesim factor + title: Fallit autentication de duesim factor suspicious_sign_in: change_password: changear tui passa-parol details: 'Vi li detallies del apertion de session:' diff --git a/config/locales/kab.yml b/config/locales/kab.yml index 66aeafde60..bf574fc016 100644 --- a/config/locales/kab.yml +++ b/config/locales/kab.yml @@ -5,7 +5,7 @@ kab: contact_missing: Ur yettusbadu ara contact_unavailable: Wlac hosted_on: Maṣṭudun yersen deg %{domain} - title: Γef + title: Ɣef accounts: follow: Ḍfeṛ followers: @@ -15,9 +15,9 @@ kab: last_active: armud aneggaru nothing_here: Ulac kra da! posts: - one: Tajewwiqt - other: Tijewwiqin - posts_tab_heading: Tijewwiqin + one: Tasuffeɣt + other: Tisuffaɣ + posts_tab_heading: Tisuffaɣ admin: account_actions: action: Eg tigawt @@ -47,7 +47,7 @@ kab: disable_two_factor_authentication: Gdel 2FA disabled: Yensa display_name: Isem ara d-yettwaskanen - domain: Taγult + domain: Taɣult edit: Ẓreg email: Imayl email_status: Addad n imayl @@ -111,7 +111,7 @@ kab: targeted_reports: Yettwazen uneqqis sɣur wiyaḍ silence: Sgugem silenced: Yettwasgugem - statuses: Tisuffɣin + statuses: Tisuffaɣ subscribe: Jerred suspended: Yeḥbes title: Imiḍanen @@ -203,22 +203,22 @@ kab: announcements: destroyed_msg: Tamselɣut tettwakkes akken iwata! edit: - title: Ẓreg ulγu - empty: Ulac kra n ulγuyen. + title: Ẓreg ulɣu + empty: Ulac kra n yilɣa yettwafen. live: Srid new: - create: Rnu-d ulγu - title: Ulγu amaynut + create: Snlufu-d ulɣu + title: Ulɣu amaynut publish: Sufeɣ published_msg: Tamselɣut tettwasufeɣ-d akken iwata! scheduled_for: Yettusɣiwsen i %{time} scheduled_msg: Tamselɣut tettusɣiwes i usufeɣ! - title: Ulγuyen + title: Ilɣa custom_emojis: assign_category: Efk taggayt - by_domain: Taγult + by_domain: Taɣult copied_msg: Takna tadigant n imuji yettwarna-d mebla ugur - copy: Nγel + copy: Nɣel create_new_category: Rnu-d taggayt tamaynut created_msg: Imuji yettwarna-d mebla ugur! delete: Kkes @@ -229,7 +229,7 @@ kab: enable: Rmed enabled: Yermed enabled_msg: Imuji yermed mebla ugur - list: Umuγ + list: Tabdart new: title: Timerna n imuji udmawan amaynut overwrite: Semselsi @@ -256,7 +256,7 @@ kab: add_new: Rni iḥder amaynut n taɣult confirm_suspension: cancel: Sefsex - domain: Taγult + domain: Taɣult export: Sifeḍ import: Kter new: @@ -274,9 +274,9 @@ kab: email_domain_blocks: add_new: Rnu amaynut delete: Kkes - domain: Taγult + domain: Taɣult new: - create: Rnu taγult + create: Rnu taɣult title: Timerna n taɣult tamaynut n imayl ɣer tebdart taberkant title: Tabdart taberkant n imayl follow_recommendations: @@ -286,8 +286,8 @@ kab: instances: back_to_all: Akk back_to_limited: Ɣur-s talast - back_to_warning: Γur-wat - by_domain: Taγult + back_to_warning: Ɣur-wat + by_domain: Taɣult content_policies: policy: Tasertit delivery: @@ -306,7 +306,7 @@ kab: private_comment: Awennit uslig public_comment: Awennit azayez title: Tamatut - total_blocked_by_us: Ttwasḥebsen sγur-neγ + total_blocked_by_us: Ttwasḥebsen sɣur-neɣ total_followed_by_them: Ṭtafaṛen-t total_followed_by_us: Neṭṭafaṛ-it total_reported: Ineqqisen fell-asen @@ -354,12 +354,15 @@ kab: other: "%{count} n timawin" action_taken_by: Tigawt yettwaṭṭfen sɣur are_you_sure: Tetḥaq-eḍ? + cancel: Sefsex category: Taggayt comment: none: Ula yiwen confirm: Sentem + delete_and_resolve: Kkes tisuffaɣ mark_as_resolved: Creḍ-it yefra mark_as_unresolved: Creḍ-it ur yefra ara + no_one_assigned: Ula yiwen notes: create: Rnu tazmilt create_and_resolve: Fru s tamawt @@ -390,16 +393,16 @@ kab: title: Ilugan n uqeddac settings: about: - title: Γef + title: Ɣef appearance: title: Udem discovery: - profile_directory: Akaram n imaγnuten + profile_directory: Akaram n imaɣnuten trends: Ayen mucaɛen domain_blocks: all: I medden akk - disabled: Γef ula yiwen - users: Γef yimseqdacen idiganen i yeqqnen + disabled: Ɣef ula yiwen + users: Ɣef yimseqdacen idiganen i yeqqnen registrations: title: Ajerred registrations_mode: @@ -408,19 +411,26 @@ kab: open: Zemren akk ad jerden site_uploads: delete: Kkes afaylu yulin + software_updates: + documentation_link: Issin ugar statuses: application: Asnas - back_to_account: Tuγalin γer usebter n umiḍan + back_to_account: Tuɣalin ɣer usebter n umiḍan deleted: Yettwakkes favourites: Imenyafen language: Tutlayt media: - title: Taγwalt - title: Tisuffiγin n umiḍan - with_media: S taγwalt + title: Amidya + title: Tisuffaɣ n umiḍan + trending: Ayen mucaɛen + visibility: Abani + with_media: S umidya title: Tadbelt trends: allow: Sireg + statuses: + title: Tisuffaɣ mucaɛen + trending: Ayen mucaɛen warning_presets: add_new: Rnu amaynut delete: Kkes @@ -431,7 +441,11 @@ kab: new_report: body: "%{reporter} yettwazen ɣef %{target}" subject: Aneqqis amaynut i %{instance} (#%{id}) + new_trends: + new_trending_statuses: + title: Tisuffaɣ mucaɛen appearance: + advanced_web_interface: Agrudem n web leqqayen discovery: Asnirem localization: guide_link: https://crowdin.com/project/mastodon @@ -448,6 +462,8 @@ kab: your_token: Ajiṭun-ik·im n unekcum auth: apply_for_account: Suter amiḍan + confirmations: + welcome_title: Ansuf yessek·em, %{name}! delete_account: Kkes amiḍan description: prefix_invited_by_user: "@%{name} inced-ik·ikem ad ternuḍ ɣer uqeddac-a n Mastodon!" @@ -455,9 +471,11 @@ kab: forgot_password: Tettud awal-ik uffir? log_in_with: Qqen s login: Qqen - logout: Ffeγ - migrate_account: Gujj γer umiḍan nniḍen - or_log_in_with: Neγ eqqen s + logout: Ffeɣ + migrate_account: Gujj ɣer umiḍan nniḍen + or_log_in_with: Neɣ eqqen s + progress: + confirm: Sentem imayl providers: cas: CAS saml: SAML @@ -466,8 +484,11 @@ kab: reset_password: Wennez awal uffir rules: back: Tuɣalin - security: Taγellist + security: Taɣellist set_new_password: Egr-d awal uffir amaynut + sign_in: + preamble_html: Kcem ar %{domain} s inekcam-inek n tuqqna. Ma yella yezga-d umiḍan-ik deg uqeddac-nniḍen, ur tezmireḍ ara ad tkecmeḍ sya. + title: Akeččum ɣer %{domain} status: account_status: Addad n umiḍan use_security_key: Seqdec tasarut n teɣlist @@ -498,16 +519,21 @@ kab: warning: username_available: Isem-ik·im n useqdac ad yuɣal yella i tikkelt-nniḍen username_unavailable: Isem-ik·im n useqdac ad yeqqim ulac-it + disputes: + strikes: + status: 'Tasuffeɣt #%{id}' + title_actions: + none: Ɣur-wat errors: '500': - title: Asebter-ayi d arameγtu + title: Asebter-ayi d arameɣtu existing_username_validator: not_found_multiple: ur yezmir ara ad yaf %{usernames} exports: archive_takeout: date: Azemz download: Sider-d aḥraz-ik·im - size: Teγzi + size: Teɣzi bookmarks: Ticraḍ csv: CSV lists: Tibdarin @@ -516,8 +542,8 @@ kab: add_new: Rnu amaynut filters: contexts: - account: Imuγna - notifications: Tilγa + account: Imuɣna + notifications: Ilɣa thread: Idiwenniyen edit: title: Ẓreg amzizdig @@ -534,8 +560,10 @@ kab: remove: Kkes seg umsizdeg generic: all: Akk + cancel: Sefsex changes_saved_msg: Ttwaskelsen ibelliden-ik·im akken ilaq! - copy: Nγel + confirm: Sentem + copy: Nɣel delete: Kkes order_by: Sizwer s save_changes: Sekles ibeddilen @@ -575,7 +603,7 @@ kab: sign_in_token: tangalt n tɣellist n tansa imayl webauthn: tisura n tɣellist migrations: - acct: Ibeddel γer + acct: Ibeddel ɣer incoming_migrations: Tusiḍ-d seg umiḍan nniḍen proceed_with_move: Awid imeḍfaṛen-ik moderation: @@ -597,7 +625,7 @@ kab: reblog: subject: "%{name} yesselha addad-ik·im" notifications: - other_settings: Iγewwaṛen nniḍen n tilγa + other_settings: Iɣewwaṛen nniḍen n yilɣa number: human: decimal_units: @@ -611,11 +639,13 @@ kab: setup: Sbadu pagination: newer: Amaynut - next: Γer zdat + next: Ɣer zdat older: Aqbuṛ prev: Win iɛeddan preferences: other: Wiyaḍ + privacy: + privacy: Tabaḍnit privacy_policy: title: Tasertit tabaḍnit relationships: @@ -634,6 +664,7 @@ kab: browser: Iminig browsers: alipay: Alipay + blackberry: BlackBerry chrome: Chrome edge: Microsoft Edge electron: Electron @@ -648,37 +679,41 @@ kab: qq: Iminig QQ safari: Safari weibo: Weibo - current_session: Tiγimit tamirant + current_session: Tiɣimit tamirant + date: Azemz description: "%{browser} s %{platform}" ip: IP platforms: adobe_air: Adobe Air android: Android + blackberry: BlackBerry + chrome_os: ChromeOS firefox_os: Firefox OS ios: iOS + kai_os: KaiOS linux: Linux mac: macOS windows: Windows windows_mobile: Windows Mobile - windows_phone: Tiliγri Windows Phone + windows_phone: Tiliɣri Windows Phone revoke: Ḥwi title: Tiɣimiyin settings: account: Amiḍan - account_settings: Iγewwaṛen n umiḍan + account_settings: Iɣewwaṛen n umiḍan appearance: Udem authorized_apps: Isnasen yettussirgen - back: Uγal γer Maṣṭudun + back: Uɣal ɣer Maṣṭudun delete: Tukksa n umiḍan development: Taneflit - edit_profile: Ẓreg amaγnu + edit_profile: Ẓreg amaɣnu export: Taktert n yisefka import: Kter import_and_export: Taktert d usifeḍ migrate: Tunigin n umiḍan - notifications: Tilγa + notifications: Ilɣa preferences: Imenyafen - profile: Ameγnu + profile: Ameɣnu relationships: Imeḍfaṛen akked wid i teṭṭafaṛeḍ statuses_cleanup: Tukksa tawurmant n tsuffaɣ two_factor_authentication: Asesteb s snat n tarrayin @@ -745,22 +780,25 @@ kab: otp: Asnas n usesteb webauthn: Tisura n teɣlist user_mailer: + appeal_approved: + action: Iɣewwaṛen n umiḍan warning: categories: spam: Aspam title: disable: Amiḍan i igersen - none: Γur-wat + none: Ɣur-wat silence: Amiḍan yesɛa talast suspend: Amiḍan yettwaḥbas welcome: final_action: Bdu asuffeɣ full_handle: Tansa umiḍan-ik takemmalit - subject: Ansuf γer Maṣṭudun + subject: Ansuf ɣer Maṣṭudun title: Ansuf yessek·em, %{name}! users: signed_in_as: 'Teqqneḍ amzun d:' verification: + here_is_how: Ha-t-a amek verification: Asenqed webauthn_credentials: add: Rnu tasarut n teɣlist tamaynut diff --git a/config/locales/simple_form.kab.yml b/config/locales/simple_form.kab.yml index 1e1c52da24..546336660c 100644 --- a/config/locales/simple_form.kab.yml +++ b/config/locales/simple_form.kab.yml @@ -12,7 +12,7 @@ kab: defaults: autofollow: Imdanen ara ijerrden s usnebgi-inek, ad k-ḍefṛen s wudem awurman email: Ad n-teṭṭfeḍ imayl i usentem - irreversible: Tijewwaqin i tessazedgeḍ ad ttwakksent i lebda, ula ma tekkseḍ imsizdeg-nni ar zdat + irreversible: Tisuffaɣ i tessazedgeḍ ad ttwakksent i lebda, ula ma tekkseḍ imsizdeg-nni ar zdat locale: Tutlayt n ugrudem, imaylen d tilγa password: Seqdec ma drus 8 n yisekkilen setting_display_media_default: Ffer teywalt yettwacreḍ d tanafrit @@ -69,12 +69,12 @@ kab: setting_display_media_show_all: Ssken kullec setting_hide_network: Ffer azetta-k·m setting_theme: Asental n wesmel - setting_use_pending_items: Askar aleγwayan + setting_use_pending_items: Askar aleɣwayan sign_in_token_attempt: Tangalt n tɣellist title: Azwel type: Anaw n uktar username: Isem n useqdac - username_or_email: Isem n useqdac neγ imal + username_or_email: Isem n useqdac neɣ imal whole_word: Awal akk featured_tag: name: Ahacṭag @@ -84,7 +84,7 @@ kab: invite: comment: Awennit invite_request: - text: Acimi tebγiḍ ad ternuḍ iman-ik? + text: Acimi tebɣiḍ ad ternuḍ iman-ik? ip_block: comment: Awennit ip: IP diff --git a/config/locales/sq.yml b/config/locales/sq.yml index 3dd4731209..460fd82dc0 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -188,7 +188,7 @@ sq: create_user_role: Krijoni Rol demote_user: Zhgradoje Përdoruesin destroy_announcement: Fshije Lajmërimin - destroy_canonical_email_block: Fshi Bllokim El-esh + destroy_canonical_email_block: Fshi Bllokim Email-esh destroy_custom_emoji: Fshi Emotikon Vetjak destroy_domain_allow: Fshi Lejim Përkatësie destroy_domain_block: Fshi Bllokim Përkatësie @@ -283,7 +283,7 @@ sq: unsuspend_account_html: "%{name} hoqi pezullimin për llogarinë e %{target}" update_announcement_html: "%{name} përditësoi lajmërimin %{target}" update_custom_emoji_html: "%{name} përditësoi emoxhin %{target}" - update_domain_block_html: "%{name} përditësoi bllokimin e përkatësish për %{target}" + update_domain_block_html: "%{name} përditësoi bllokim përkatësish për %{target}" update_ip_block_html: "%{name} ndryshoi rregull për IP-në %{target}" update_status_html: "%{name} përditësoi gjendjen me %{target}" update_user_role_html: "%{name} ndryshoi rolin për %{target}" diff --git a/config/locales/th.yml b/config/locales/th.yml index 74fc1b26b7..b76f6992ad 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -452,7 +452,7 @@ th: title: นำเข้าการปิดกั้นโดเมน no_file: ไม่ได้เลือกไฟล์ follow_recommendations: - description_html: "คำแนะนำการติดตามช่วยให้ผู้ใช้ใหม่ค้นหาเนื้อหาที่น่าสนใจได้อย่างรวดเร็ว เมื่อผู้ใช้ไม่ได้โต้ตอบกับผู้อื่นมากพอที่จะสร้างคำแนะนำการติดตามส่วนบุคคล จะแนะนำบัญชีเหล่านี้แทน จะคำนวณคำแนะนำใหม่เป็นประจำทุกวันจากบัญชีต่าง ๆ ที่มีการมีส่วนร่วมล่าสุดสูงสุดและจำนวนผู้ติดตามในเซิร์ฟเวอร์สูงสุดสำหรับภาษาที่กำหนด" + description_html: "คำแนะนำการติดตามช่วยให้ผู้ใช้ใหม่ค้นหาเนื้อหาที่น่าสนใจได้อย่างรวดเร็ว เมื่อผู้ใช้ไม่ได้โต้ตอบกับผู้อื่นมากพอที่จะสร้างคำแนะนำการติดตามเฉพาะบุคคล จะแนะนำบัญชีเหล่านี้แทน จะคำนวณคำแนะนำใหม่เป็นประจำทุกวันจากบัญชีต่าง ๆ ที่มีการมีส่วนร่วมล่าสุดสูงสุดและจำนวนผู้ติดตามในเซิร์ฟเวอร์สูงสุดสำหรับภาษาที่กำหนด" language: สำหรับภาษา status: สถานะ suppress: ระงับคำแนะนำการติดตาม From 4b7f04e3eab274e574289a554f004c4a58e7ef9b Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 02:52:29 -0500 Subject: [PATCH 44/63] Reduce `RSpec/MultipleExpectations` in post_status_service spec (#29225) --- spec/services/post_status_service_spec.rb | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index d10a82607e..acbebc5056 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -32,27 +32,27 @@ RSpec.describe PostStatusService, type: :service do let!(:future) { Time.now.utc + 2.hours } let!(:previous_status) { Fabricate(:status, account: account) } - it 'schedules a status' do - status = subject.call(account, text: 'Hi future!', scheduled_at: future) - expect(status).to be_a ScheduledStatus - expect(status.scheduled_at).to eq future - expect(status.params['text']).to eq 'Hi future!' - end - - it 'does not immediately create a status' do + it 'schedules a status for future creation and does not create one immediately' do media = Fabricate(:media_attachment, account: account) status = subject.call(account, text: 'Hi future!', media_ids: [media.id], scheduled_at: future) - expect(status).to be_a ScheduledStatus - expect(status.scheduled_at).to eq future - expect(status.params['text']).to eq 'Hi future!' - expect(status.params['media_ids']).to eq [media.id] + expect(status) + .to be_a(ScheduledStatus) + .and have_attributes( + scheduled_at: eq(future), + params: include( + 'text' => eq('Hi future!'), + 'media_ids' => contain_exactly(media.id) + ) + ) expect(media.reload.status).to be_nil expect(Status.where(text: 'Hi future!')).to_not exist end - it 'does not change statuses count' do - expect { subject.call(account, text: 'Hi future!', scheduled_at: future, thread: previous_status) }.to_not(change { [account.statuses_count, previous_status.replies_count] }) + it 'does not change statuses_count of account or replies_count of thread previous status' do + expect { subject.call(account, text: 'Hi future!', scheduled_at: future, thread: previous_status) } + .to not_change { account.statuses_count } + .and(not_change { previous_status.replies_count }) end end From a9f9b0097bc18b87c7fe6636a74ea135bab61dc0 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 02:52:57 -0500 Subject: [PATCH 45/63] Reduce `RSpec/MultipleExpectations` in captcha feature spec (#29226) --- spec/features/captcha_spec.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/spec/features/captcha_spec.rb b/spec/features/captcha_spec.rb index 15c37eb463..06c823adf2 100644 --- a/spec/features/captcha_spec.rb +++ b/spec/features/captcha_spec.rb @@ -19,12 +19,10 @@ describe 'email confirmation flow when captcha is enabled' do # It presents the user with a captcha form expect(page).to have_title(I18n.t('auth.captcha_confirmation.title')) - # It does not confirm the user just yet - expect(user.reload.confirmed?).to be false - # It redirects to app and confirms user - click_on I18n.t('challenge.confirm') - expect(user.reload.confirmed?).to be true + expect { click_on I18n.t('challenge.confirm') } + .to change { user.reload.confirmed? }.from(false).to(true) + expect(page).to have_current_path(/\A#{client_app.confirmation_redirect_uri}/, url: true) # Browsers will generally reload the original page upon redirection @@ -32,8 +30,9 @@ describe 'email confirmation flow when captcha is enabled' do visit "/auth/confirmation?confirmation_token=#{user.confirmation_token}&redirect_to_app=true" # It presents a page with a link to the app callback - expect(page).to have_content(I18n.t('auth.confirmations.registration_complete', domain: 'cb6e6126.ngrok.io')) - expect(page).to have_link(I18n.t('auth.confirmations.clicking_this_link'), href: client_app.confirmation_redirect_uri) + expect(page) + .to have_content(I18n.t('auth.confirmations.registration_complete', domain: 'cb6e6126.ngrok.io')) + .and have_link(I18n.t('auth.confirmations.clicking_this_link'), href: client_app.confirmation_redirect_uri) end end From a8ee6fdd62a85cc8ad20007783000682110a8f0d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 09:12:10 +0100 Subject: [PATCH 46/63] Update dependency pg to v1.5.5 (#29230) 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 00ca4663a8..0b53df82e0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -505,7 +505,7 @@ GEM parslet (2.0.0) pastel (0.8.0) tty-color (~> 0.5) - pg (1.5.4) + pg (1.5.5) pghero (3.4.1) activerecord (>= 6) posix-spawn (0.3.15) From 9fee5e852669e26f970e278021302e1a203fc022 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 16 Feb 2024 11:56:12 +0100 Subject: [PATCH 47/63] Merge pull request from GHSA-jhrq-qvrm-qr36 * Fix insufficient Content-Type checking of fetched ActivityStreams objects * Allow JSON-LD documents with multiple profiles --- app/helpers/jsonld_helper.rb | 14 +++++++++++++- app/services/fetch_resource_service.rb | 2 +- spec/helpers/json_ld_helper_spec.rb | 14 +++++++------- spec/lib/activitypub/activity/announce_spec.rb | 4 ++-- .../fetch_featured_collection_service_spec.rb | 18 +++++++++--------- ...ch_featured_tags_collection_service_spec.rb | 8 ++++---- .../fetch_remote_account_service_spec.rb | 10 +++++----- .../fetch_remote_actor_service_spec.rb | 10 +++++----- .../fetch_remote_key_service_spec.rb | 8 ++++---- .../activitypub/fetch_replies_service_spec.rb | 6 +++--- .../synchronize_followers_service_spec.rb | 6 +++--- .../activitypub/fetch_replies_worker_spec.rb | 2 +- 12 files changed, 57 insertions(+), 45 deletions(-) diff --git a/app/helpers/jsonld_helper.rb b/app/helpers/jsonld_helper.rb index cc05b7a403..b0f2077db0 100644 --- a/app/helpers/jsonld_helper.rb +++ b/app/helpers/jsonld_helper.rb @@ -174,7 +174,19 @@ module JsonLdHelper build_request(uri, on_behalf_of, options: request_options).perform do |response| raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) || !raise_on_temporary_error - body_to_json(response.body_with_limit) if response.code == 200 + body_to_json(response.body_with_limit) if response.code == 200 && valid_activitypub_content_type?(response) + end + end + + def valid_activitypub_content_type?(response) + return true if response.mime_type == 'application/activity+json' + + # When the mime type is `application/ld+json`, we need to check the profile, + # but `http.rb` does not parse it for us. + return false unless response.mime_type == 'application/ld+json' + + response.headers[HTTP::Headers::CONTENT_TYPE]&.split(';')&.map(&:strip)&.any? do |str| + str.start_with?('profile="') && str[9...-1].split.include?('https://www.w3.org/ns/activitystreams') end end diff --git a/app/services/fetch_resource_service.rb b/app/services/fetch_resource_service.rb index 71c6cca790..84c36f6a10 100644 --- a/app/services/fetch_resource_service.rb +++ b/app/services/fetch_resource_service.rb @@ -44,7 +44,7 @@ class FetchResourceService < BaseService @response_code = response.code return nil if response.code != 200 - if ['application/activity+json', 'application/ld+json'].include?(response.mime_type) + if valid_activitypub_content_type?(response) body = response.body_with_limit json = body_to_json(body) diff --git a/spec/helpers/json_ld_helper_spec.rb b/spec/helpers/json_ld_helper_spec.rb index 99857278a1..4855085027 100644 --- a/spec/helpers/json_ld_helper_spec.rb +++ b/spec/helpers/json_ld_helper_spec.rb @@ -56,15 +56,15 @@ describe JsonLdHelper do describe '#fetch_resource' do context 'when the second argument is false' do it 'returns resource even if the retrieved ID and the given URI does not match' do - stub_request(:get, 'https://bob.test/').to_return body: '{"id": "https://alice.test/"}' - stub_request(:get, 'https://alice.test/').to_return body: '{"id": "https://alice.test/"}' + stub_request(:get, 'https://bob.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' }) + stub_request(:get, 'https://alice.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' }) expect(fetch_resource('https://bob.test/', false)).to eq({ 'id' => 'https://alice.test/' }) end it 'returns nil if the object identified by the given URI and the object identified by the retrieved ID does not match' do - stub_request(:get, 'https://mallory.test/').to_return body: '{"id": "https://marvin.test/"}' - stub_request(:get, 'https://marvin.test/').to_return body: '{"id": "https://alice.test/"}' + stub_request(:get, 'https://mallory.test/').to_return(body: '{"id": "https://marvin.test/"}', headers: { 'Content-Type': 'application/activity+json' }) + stub_request(:get, 'https://marvin.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' }) expect(fetch_resource('https://mallory.test/', false)).to be_nil end @@ -72,7 +72,7 @@ describe JsonLdHelper do context 'when the second argument is true' do it 'returns nil if the retrieved ID and the given URI does not match' do - stub_request(:get, 'https://mallory.test/').to_return body: '{"id": "https://alice.test/"}' + stub_request(:get, 'https://mallory.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' }) expect(fetch_resource('https://mallory.test/', true)).to be_nil end end @@ -80,12 +80,12 @@ describe JsonLdHelper do describe '#fetch_resource_without_id_validation' do it 'returns nil if the status code is not 200' do - stub_request(:get, 'https://host.test/').to_return status: 400, body: '{}' + stub_request(:get, 'https://host.test/').to_return(status: 400, body: '{}', headers: { 'Content-Type': 'application/activity+json' }) expect(fetch_resource_without_id_validation('https://host.test/')).to be_nil end it 'returns hash' do - stub_request(:get, 'https://host.test/').to_return status: 200, body: '{}' + stub_request(:get, 'https://host.test/').to_return(status: 200, body: '{}', headers: { 'Content-Type': 'application/activity+json' }) expect(fetch_resource_without_id_validation('https://host.test/')).to eq({}) end end diff --git a/spec/lib/activitypub/activity/announce_spec.rb b/spec/lib/activitypub/activity/announce_spec.rb index 8ad892975d..b556bfd6c2 100644 --- a/spec/lib/activitypub/activity/announce_spec.rb +++ b/spec/lib/activitypub/activity/announce_spec.rb @@ -35,7 +35,7 @@ RSpec.describe ActivityPub::Activity::Announce do context 'when sender is followed by a local account' do before do Fabricate(:account).follow!(sender) - stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json)) + stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json), headers: { 'Content-Type': 'application/activity+json' }) subject.perform end @@ -120,7 +120,7 @@ RSpec.describe ActivityPub::Activity::Announce do let(:object_json) { 'https://example.com/actor/hello-world' } before do - stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json)) + stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json), headers: { 'Content-Type': 'application/activity+json' }) end context 'when the relay is enabled' do diff --git a/spec/services/activitypub/fetch_featured_collection_service_spec.rb b/spec/services/activitypub/fetch_featured_collection_service_spec.rb index b9e95b825f..dab204406b 100644 --- a/spec/services/activitypub/fetch_featured_collection_service_spec.rb +++ b/spec/services/activitypub/fetch_featured_collection_service_spec.rb @@ -72,11 +72,11 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do shared_examples 'sets pinned posts' do before do - stub_request(:get, 'https://example.com/account/pinned/known').to_return(status: 200, body: Oj.dump(status_json_pinned_known)) - stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined)) + stub_request(:get, 'https://example.com/account/pinned/known').to_return(status: 200, body: Oj.dump(status_json_pinned_known), headers: { 'Content-Type': 'application/activity+json' }) + stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/account/pinned/unknown-unreachable').to_return(status: 404) - stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable)) - stub_request(:get, 'https://example.com/account/collections/featured').to_return(status: 200, body: Oj.dump(featured_with_null)) + stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' }) + stub_request(:get, 'https://example.com/account/collections/featured').to_return(status: 200, body: Oj.dump(featured_with_null), headers: { 'Content-Type': 'application/activity+json' }) subject.call(actor, note: true, hashtag: false) end @@ -94,7 +94,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do describe '#call' do context 'when the endpoint is a Collection' do before do - stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it_behaves_like 'sets pinned posts' @@ -111,7 +111,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do end before do - stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it_behaves_like 'sets pinned posts' @@ -120,7 +120,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do let(:items) { 'https://example.com/account/pinned/unknown-reachable' } before do - stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable)) + stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' }) subject.call(actor, note: true, hashtag: false) end @@ -147,7 +147,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do end before do - stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it_behaves_like 'sets pinned posts' @@ -156,7 +156,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do let(:items) { 'https://example.com/account/pinned/unknown-reachable' } before do - stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable)) + stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' }) subject.call(actor, note: true, hashtag: false) end diff --git a/spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb b/spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb index 071e4d92d5..638278a10e 100644 --- a/spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb +++ b/spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb @@ -38,7 +38,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d describe '#call' do context 'when the endpoint is a Collection' do before do - stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it_behaves_like 'sets featured tags' @@ -46,7 +46,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d context 'when the account already has featured tags' do before do - stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) actor.featured_tags.create!(name: 'FoO') actor.featured_tags.create!(name: 'baz') @@ -67,7 +67,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d end before do - stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it_behaves_like 'sets featured tags' @@ -88,7 +88,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d end before do - stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it_behaves_like 'sets featured tags' diff --git a/spec/services/activitypub/fetch_remote_account_service_spec.rb b/spec/services/activitypub/fetch_remote_account_service_spec.rb index e7f6bb8dd8..799a70d091 100644 --- a/spec/services/activitypub/fetch_remote_account_service_spec.rb +++ b/spec/services/activitypub/fetch_remote_account_service_spec.rb @@ -38,7 +38,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do before do actor[:inbox] = nil - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end @@ -54,7 +54,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end @@ -75,7 +75,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end @@ -98,7 +98,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/bob' }] } } before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end @@ -114,7 +114,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/bob' }] } } before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end diff --git a/spec/services/activitypub/fetch_remote_actor_service_spec.rb b/spec/services/activitypub/fetch_remote_actor_service_spec.rb index e622c7d4c3..4ce42ea560 100644 --- a/spec/services/activitypub/fetch_remote_actor_service_spec.rb +++ b/spec/services/activitypub/fetch_remote_actor_service_spec.rb @@ -38,7 +38,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do before do actor[:inbox] = nil - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end @@ -54,7 +54,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end @@ -75,7 +75,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end @@ -98,7 +98,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/bob' }] } } before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end @@ -114,7 +114,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/bob' }] } } before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end diff --git a/spec/services/activitypub/fetch_remote_key_service_spec.rb b/spec/services/activitypub/fetch_remote_key_service_spec.rb index 0b14da4f44..478778cc9f 100644 --- a/spec/services/activitypub/fetch_remote_key_service_spec.rb +++ b/spec/services/activitypub/fetch_remote_key_service_spec.rb @@ -50,7 +50,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do end before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) + stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) end @@ -59,7 +59,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do context 'when the key is a sub-object from the actor' do before do - stub_request(:get, public_key_id).to_return(body: Oj.dump(actor)) + stub_request(:get, public_key_id).to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' }) end it 'returns the expected account' do @@ -71,7 +71,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do let(:public_key_id) { 'https://example.com/alice-public-key.json' } before do - stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] }))) + stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })), headers: { 'Content-Type': 'application/activity+json' }) end it 'returns the expected account' do @@ -84,7 +84,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do let(:actor_public_key) { 'https://example.com/alice-public-key.json' } before do - stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] }))) + stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })), headers: { 'Content-Type': 'application/activity+json' }) end it 'returns the nil' do diff --git a/spec/services/activitypub/fetch_replies_service_spec.rb b/spec/services/activitypub/fetch_replies_service_spec.rb index a76b996c20..8e1f606e26 100644 --- a/spec/services/activitypub/fetch_replies_service_spec.rb +++ b/spec/services/activitypub/fetch_replies_service_spec.rb @@ -58,7 +58,7 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do context 'when passing the URL to the collection' do before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it 'spawns workers for up to 5 replies on the same server' do @@ -93,7 +93,7 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do context 'when passing the URL to the collection' do before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it 'spawns workers for up to 5 replies on the same server' do @@ -132,7 +132,7 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do context 'when passing the URL to the collection' do before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it 'spawns workers for up to 5 replies on the same server' do diff --git a/spec/services/activitypub/synchronize_followers_service_spec.rb b/spec/services/activitypub/synchronize_followers_service_spec.rb index c9a513e24b..f62376ab95 100644 --- a/spec/services/activitypub/synchronize_followers_service_spec.rb +++ b/spec/services/activitypub/synchronize_followers_service_spec.rb @@ -60,7 +60,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do describe '#call' do context 'when the endpoint is a Collection of actor URIs' do before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it_behaves_like 'synchronizes followers' @@ -77,7 +77,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do end before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it_behaves_like 'synchronizes followers' @@ -98,7 +98,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do end before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) + stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' }) end it_behaves_like 'synchronizes followers' diff --git a/spec/workers/activitypub/fetch_replies_worker_spec.rb b/spec/workers/activitypub/fetch_replies_worker_spec.rb index ff4d049a26..2d080e286e 100644 --- a/spec/workers/activitypub/fetch_replies_worker_spec.rb +++ b/spec/workers/activitypub/fetch_replies_worker_spec.rb @@ -21,7 +21,7 @@ describe ActivityPub::FetchRepliesWorker do describe 'perform' do it 'performs a request if the collection URI is from the same host' do - stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 200, body: json) + stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 200, body: json, headers: { 'Content-Type': 'application/activity+json' }) subject.perform(status.id, 'https://example.com/statuses_replies/1') expect(a_request(:get, 'https://example.com/statuses_replies/1')).to have_been_made.once end From 5f21a1f5a3492a212a25235086e620799d47f1c9 Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 16 Feb 2024 12:06:47 +0100 Subject: [PATCH 48/63] Bump version to v4.3.0-alpha.3 (#29241) --- CHANGELOG.md | 95 +++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 6 +-- lib/mastodon/version.rb | 2 +- 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f775fcfa8..a53790afaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,101 @@ All notable changes to this project will be documented in this file. +## [4.2.7] - 2024-02-16 + +### Fixed + +- Fix OmniAuth tests and edge cases in error handling ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29201), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/29207)) +- Fix new installs by upgrading to the latest release of the `nsa` gem, instead of a no longer existing commit ([mjankowski](https://github.com/mastodon/mastodon/pull/29065)) + +### Security + +- Fix insufficient checking of remote posts ([GHSA-jhrq-qvrm-qr36](https://github.com/mastodon/mastodon/security/advisories/GHSA-jhrq-qvrm-qr36)) + +## [4.2.6] - 2024-02-14 + +### Security + +- Update the `sidekiq-unique-jobs` dependency (see [GHSA-cmh9-rx85-xj38](https://github.com/mhenrixon/sidekiq-unique-jobs/security/advisories/GHSA-cmh9-rx85-xj38)) + In addition, we have disabled the web interface for `sidekiq-unique-jobs` out of caution. + If you need it, you can re-enable it by setting `ENABLE_SIDEKIQ_UNIQUE_JOBS_UI=true`. + If you only need to clear all locks, you can now use `bundle exec rake sidekiq_unique_jobs:delete_all_locks`. +- Update the `nokogiri` dependency (see [GHSA-xc9x-jj77-9p9j](https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-xc9x-jj77-9p9j)) +- Disable administrative Doorkeeper routes ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/29187)) +- Fix ongoing streaming sessions not being invalidated when applications get deleted in some cases ([GHSA-7w3c-p9j8-mq3x](https://github.com/mastodon/mastodon/security/advisories/GHSA-7w3c-p9j8-mq3x)) + In some rare cases, the streaming server was not notified of access tokens revocation on application deletion. +- Change external authentication behavior to never reattach a new identity to an existing user by default ([GHSA-vm39-j3vx-pch3](https://github.com/mastodon/mastodon/security/advisories/GHSA-vm39-j3vx-pch3)) + Up until now, Mastodon has allowed new identities from external authentication providers to attach to an existing local user based on their verified e-mail address. + This allowed upgrading users from a database-stored password to an external authentication provider, or move from one authentication provider to another. + However, this behavior may be unexpected, and means that when multiple authentication providers are configured, the overall security would be that of the least secure authentication provider. + For these reasons, this behavior is now locked under the `ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH` environment variable. + In addition, regardless of this environment variable, Mastodon will refuse to attach two identities from the same authentication provider to the same account. + +## [4.2.5] - 2024-02-01 + +### Security + +- Fix insufficient origin validation (CVE-2024-23832, [GHSA-3fjr-858r-92rw](https://github.com/mastodon/mastodon/security/advisories/GHSA-3fjr-858r-92rw)) + +## [4.2.4] - 2024-01-24 + +### Fixed + +- Fix error when processing remote files with unusually long names ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28823)) +- Fix processing of compacted single-item JSON-LD collections ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28816)) +- Retry 401 errors on replies fetching ([ShadowJonathan](https://github.com/mastodon/mastodon/pull/28788)) +- Fix `RecordNotUnique` errors in LinkCrawlWorker ([tribela](https://github.com/mastodon/mastodon/pull/28748)) +- Fix Mastodon not correctly processing HTTP Signatures with query strings ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28443), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/28476)) +- Fix potential redirection loop of streaming endpoint ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28665)) +- Fix streaming API redirection ignoring the port of `streaming_api_base_url` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28558)) +- Fix error when processing link preview with an array as `inLanguage` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28252)) +- Fix unsupported time zone or locale preventing sign-up ([Gargron](https://github.com/mastodon/mastodon/pull/28035)) +- Fix "Hide these posts from home" list setting not refreshing when switching lists ([brianholley](https://github.com/mastodon/mastodon/pull/27763)) +- Fix missing background behind dismissable banner in web UI ([Gargron](https://github.com/mastodon/mastodon/pull/27479)) +- Fix line wrapping of language selection button with long locale codes ([gunchleoc](https://github.com/mastodon/mastodon/pull/27100), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27127)) +- Fix `Undo Announce` activity not being sent to non-follower authors ([MitarashiDango](https://github.com/mastodon/mastodon/pull/18482)) +- Fix N+1s because of association preloaders not actually getting called ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28339)) +- Fix empty column explainer getting cropped under certain conditions ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28337)) +- Fix `LinkCrawlWorker` error when encountering empty OEmbed response ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28268)) +- Fix call to inefficient `delete_matched` cache method in domain blocks ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28367)) + +### Security + +- Add rate-limit of TOTP authentication attempts at controller level ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28801)) + +## [4.2.3] - 2023-12-05 + +### Fixed + +- Fix dependency on `json-canonicalization` version that has been made unavailable since last release + +## [4.2.2] - 2023-12-04 + +### Changed + +- Change dismissed banners to be stored server-side ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27055)) +- Change GIF max matrix size error to explicitly mention GIF files ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27927)) +- Change `Follow` activities delivery to bypass availability check ([ShadowJonathan](https://github.com/mastodon/mastodon/pull/27586)) +- Change single-column navigation notice to be displayed outside of the logo container ([renchap](https://github.com/mastodon/mastodon/pull/27462), [renchap](https://github.com/mastodon/mastodon/pull/27476)) +- Change Content-Security-Policy to be tighter on media paths ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/26889)) +- Change post language code to include country code when relevant ([gunchleoc](https://github.com/mastodon/mastodon/pull/27099), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27207)) + +### Fixed + +- Fix upper border radius of onboarding columns ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27890)) +- Fix incoming status creation date not being restricted to standard ISO8601 ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27655), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/28081)) +- Fix some posts from threads received out-of-order sometimes not being inserted into timelines ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27653)) +- Fix posts from force-sensitized accounts being able to trend ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27620)) +- Fix error when trying to delete already-deleted file with OpenStack Swift ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27569)) +- Fix batch attachment deletion when using OpenStack Swift ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27554)) +- Fix processing LDSigned activities from actors with unknown public keys ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27474)) +- Fix error and incorrect URLs in `/api/v1/accounts/:id/featured_tags` for remote accounts ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27459)) +- Fix report processing notice not mentioning the report number when performing a custom action ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27442)) +- Fix handling of `inLanguage` attribute in preview card processing ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27423)) +- Fix own posts being removed from home timeline when unfollowing a used hashtag ([kmycode](https://github.com/mastodon/mastodon/pull/27391)) +- Fix some link anchors being recognized as hashtags ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27271), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/27584)) +- Fix format-dependent redirects being cached regardless of requested format ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27634)) + ## [4.2.1] - 2023-10-10 ### Added diff --git a/docker-compose.yml b/docker-compose.yml index 93451d9611..154754d45f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -56,7 +56,7 @@ services: web: build: . - image: ghcr.io/mastodon/mastodon:v4.2.0 + image: ghcr.io/mastodon/mastodon:v4.2.7 restart: always env_file: .env.production command: bundle exec puma -C config/puma.rb @@ -77,7 +77,7 @@ services: streaming: build: . - image: ghcr.io/mastodon/mastodon:v4.2.0 + image: ghcr.io/mastodon/mastodon:v4.2.7 restart: always env_file: .env.production command: node ./streaming @@ -95,7 +95,7 @@ services: sidekiq: build: . - image: ghcr.io/mastodon/mastodon:v4.2.0 + image: ghcr.io/mastodon/mastodon:v4.2.7 restart: always env_file: .env.production command: bundle exec sidekiq diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index c2f26aee63..1135ba0a17 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -17,7 +17,7 @@ module Mastodon end def default_prerelease - 'alpha.2' + 'alpha.3' end def prerelease From e140d05a6a6d679153fe02ac38588aaa4656e464 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 13:59:51 +0100 Subject: [PATCH 49/63] Update dependency doorkeeper to v5.6.9 (#29196) 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 0b53df82e0..79d3b1e637 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -219,7 +219,7 @@ GEM docile (1.4.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - doorkeeper (5.6.8) + doorkeeper (5.6.9) railties (>= 5) dotenv (2.8.1) dotenv-rails (2.8.1) @@ -811,7 +811,7 @@ GEM xorcist (1.1.3) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.12) + zeitwerk (2.6.13) PLATFORMS ruby From bba488c189084d8499173c3e65dcce8e40a5606a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:00:09 -0500 Subject: [PATCH 50/63] Reduce `RSpec/MultipleExpectations` in media_attachment spec (#29228) --- spec/models/media_attachment_spec.rb | 49 ++++++++++++++-------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/spec/models/media_attachment_spec.rb b/spec/models/media_attachment_spec.rb index 89916f9f50..1b9a13c38c 100644 --- a/spec/models/media_attachment_spec.rb +++ b/spec/models/media_attachment_spec.rb @@ -91,20 +91,15 @@ RSpec.describe MediaAttachment, :paperclip_processing do end it 'saves media attachment with correct file metadata' do - expect(media.persisted?).to be true - expect(media.file).to_not be_nil - - # completes processing - expect(media.processing_complete?).to be true - - # sets type - expect(media.type).to eq 'image' - - # sets content type - expect(media.file_content_type).to eq content_type - - # sets file extension - expect(media.file_file_name).to end_with extension + expect(media) + .to be_persisted + .and be_processing_complete + .and have_attributes( + file: be_present, + type: eq('image'), + file_content_type: eq(content_type), + file_file_name: end_with(extension) + ) # Rack::Mime (used by PublicFileServerMiddleware) recognizes file extension expect(Rack::Mime.mime_type(extension, nil)).to eq content_type @@ -112,17 +107,23 @@ RSpec.describe MediaAttachment, :paperclip_processing do it 'saves media attachment with correct size metadata' do # strips original file name - expect(media.file_file_name).to_not start_with '600x400' + expect(media.file_file_name) + .to_not start_with '600x400' - # sets meta for original - expect(media.file.meta['original']['width']).to eq 600 - expect(media.file.meta['original']['height']).to eq 400 - expect(media.file.meta['original']['aspect']).to eq 1.5 - - # sets meta for thumbnail - expect(media.file.meta['small']['width']).to eq 588 - expect(media.file.meta['small']['height']).to eq 392 - expect(media.file.meta['small']['aspect']).to eq 1.5 + # sets meta for original and thumbnail + expect(media.file.meta.deep_symbolize_keys) + .to include( + original: include( + width: eq(600), + height: eq(400), + aspect: eq(1.5) + ), + small: include( + width: eq(588), + height: eq(392), + aspect: eq(1.5) + ) + ) end end From 1690fb39e6e4a26cc5f708626920d3491d7dd95b Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:00:11 -0500 Subject: [PATCH 51/63] Reduce `RSpec/MultipleExpectations` in instance_actors_controller spec (#29229) --- .../instance_actors_controller_spec.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/spec/controllers/instance_actors_controller_spec.rb b/spec/controllers/instance_actors_controller_spec.rb index 36b9049fbc..be1eefa7b2 100644 --- a/spec/controllers/instance_actors_controller_spec.rb +++ b/spec/controllers/instance_actors_controller_spec.rb @@ -13,17 +13,19 @@ RSpec.describe InstanceActorsController do end it 'returns http success with correct media type, headers, and session values' do - expect(response).to have_http_status(200) + expect(response) + .to have_http_status(200) + .and have_attributes( + media_type: eq('application/activity+json'), + cookies: be_empty + ) - expect(response.media_type).to eq 'application/activity+json' - - expect(response.cookies).to be_empty - expect(response.headers['Set-Cookies']).to be_nil + expect(response.headers) + .to include('Cache-Control' => include('public')) + .and not_include('Set-Cookies') expect(session).to be_empty - expect(response.headers['Cache-Control']).to include 'public' - expect(body_as_json) .to include(:id, :type, :preferredUsername, :inbox, :publicKey, :inbox, :outbox, :url) end From 117b507df59b2f302c278797a0ea312aee68d570 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:01:04 -0500 Subject: [PATCH 52/63] Extract `subject` from `User#mark_email_as_confirmed!` spec (#29231) --- spec/models/user_spec.rb | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 845335e873..1baa3ccbf9 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -451,35 +451,32 @@ RSpec.describe User do end describe '#mark_email_as_confirmed!' do - subject(:user) { Fabricate(:user, confirmed_at: confirmed_at) } + subject { user.mark_email_as_confirmed! } - before do - ActionMailer::Base.deliveries.clear - user.mark_email_as_confirmed! - end + let!(:user) { Fabricate(:user, confirmed_at: confirmed_at) } + + before { ActionMailer::Base.deliveries.clear } after { ActionMailer::Base.deliveries.clear } context 'when user is new' do let(:confirmed_at) { nil } - it 'confirms user' do - expect(user.confirmed_at).to be_present - end + it 'confirms user and delivers welcome email', :sidekiq_inline do + subject - it 'delivers mails', :sidekiq_inline do - expect(ActionMailer::Base.deliveries.count).to eq 2 + expect(user.confirmed_at).to be_present + expect(ActionMailer::Base.deliveries.count).to eq 1 end end context 'when user is not new' do let(:confirmed_at) { Time.zone.now } - it 'confirms user' do - expect(user.confirmed_at).to be_present - end + it 'confirms user but does not deliver welcome email' do + subject - it 'does not deliver mail' do + expect(user.confirmed_at).to be_present expect(ActionMailer::Base.deliveries.count).to eq 0 end end From a316c0e38de9e0dd5853c1c7a1f8d8b7188fb253 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:01:15 -0500 Subject: [PATCH 53/63] Reduce round trips in disputes/appeals spec (#29232) --- .../disputes/appeals_controller_spec.rb | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/spec/controllers/disputes/appeals_controller_spec.rb b/spec/controllers/disputes/appeals_controller_spec.rb index da2f86ade5..d763068ebe 100644 --- a/spec/controllers/disputes/appeals_controller_spec.rb +++ b/spec/controllers/disputes/appeals_controller_spec.rb @@ -10,19 +10,17 @@ RSpec.describe Disputes::AppealsController do let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } describe '#create' do + subject { post :create, params: params } + context 'with valid params' do let(:current_user) { Fabricate(:user) } let(:strike) { Fabricate(:account_warning, target_account: current_user.account) } + let(:params) { { strike_id: strike.id, appeal: { text: 'Foo' } } } - before do - post :create, params: { strike_id: strike.id, appeal: { text: 'Foo' } } - end + it 'notifies staff about new appeal and redirects back to strike page', :sidekiq_inline do + subject - it 'notifies staff about new appeal', :sidekiq_inline do expect(ActionMailer::Base.deliveries.first.to).to eq([admin.email]) - end - - it 'redirects back to the strike page' do expect(response).to redirect_to(disputes_strike_path(strike.id)) end end @@ -30,16 +28,12 @@ RSpec.describe Disputes::AppealsController do context 'with invalid params' do let(:current_user) { Fabricate(:user) } let(:strike) { Fabricate(:account_warning, target_account: current_user.account) } + let(:params) { { strike_id: strike.id, appeal: { text: '' } } } - before do - post :create, params: { strike_id: strike.id, appeal: { text: '' } } - end + it 'does not send email and renders strike show page', :sidekiq_inline do + subject - it 'does not send email', :sidekiq_inline do expect(ActionMailer::Base.deliveries.size).to eq(0) - end - - it 'renders the strike show page' do expect(response).to render_template('disputes/strikes/show') end end From 3454fcbd719f3f28b1466fd65c42c14d394212c0 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:38:49 -0500 Subject: [PATCH 54/63] Reduce round trips in auth/sessions spec (#29233) --- .../auth/sessions_controller_spec.rb | 80 ++++++------------- 1 file changed, 25 insertions(+), 55 deletions(-) diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb index b663f55afa..dcbaf1fcbb 100644 --- a/spec/controllers/auth/sessions_controller_spec.rb +++ b/spec/controllers/auth/sessions_controller_spec.rb @@ -57,11 +57,9 @@ RSpec.describe Auth::SessionsController do post :create, params: { user: { email: 'pam_user1', password: '123456' } } end - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to be_instance_of(User) end end @@ -71,11 +69,9 @@ RSpec.describe Auth::SessionsController do post :create, params: { user: { email: 'pam_user1', password: 'WRONGPW' } } end - it 'shows a login error' do + it 'shows a login error and does not log the user in' do expect(flash[:alert]).to match I18n.t('devise.failure.invalid', authentication_keys: I18n.t('activerecord.attributes.user.email')) - end - it "doesn't log the user in" do expect(controller.current_user).to be_nil end end @@ -92,11 +88,9 @@ RSpec.describe Auth::SessionsController do post :create, params: { user: { email: user.email, password: '123456' } } end - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user end end @@ -110,16 +104,16 @@ RSpec.describe Auth::SessionsController do post :create, params: { user: { email: user.email, password: user.password } } end - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user end end context 'when using a valid password on a previously-used account with a new IP address' do + subject { post :create, params: { user: { email: user.email, password: user.password } } } + let(:previous_ip) { '1.2.3.4' } let(:current_ip) { '4.3.2.1' } @@ -127,18 +121,17 @@ RSpec.describe Auth::SessionsController do Fabricate(:login_activity, user: user, ip: previous_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 - it 'redirects to home' do - expect(response).to redirect_to(root_path) - end + it 'logs the user in and sends suspicious email and redirects home', :sidekiq_inline do + subject - it 'logs the user in' do - expect(controller.current_user).to eq user - end + expect(response) + .to redirect_to(root_path) + + expect(controller.current_user) + .to eq user - it 'sends a suspicious sign-in mail', :sidekiq_inline do expect(UserMailer.deliveries.size).to eq(1) expect(UserMailer.deliveries.first.to.first).to eq(user.email) expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.suspicious_sign_in.subject')) @@ -150,11 +143,9 @@ RSpec.describe Auth::SessionsController do post :create, params: { user: { email: user.email.upcase, password: user.password } } end - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user end end @@ -164,11 +155,9 @@ RSpec.describe Auth::SessionsController do post :create, params: { user: { email: user.email, password: 'wrongpw' } } end - it 'shows a login error' do + it 'shows a login error and does not log the user in' do expect(flash[:alert]).to match I18n.t('devise.failure.invalid', authentication_keys: I18n.t('activerecord.attributes.user.email')) - end - it "doesn't log the user in" do expect(controller.current_user).to be_nil end end @@ -270,7 +259,7 @@ RSpec.describe Auth::SessionsController do travel_to '2023-12-20T10:00:00Z' end - it 'does not log the user in' do + it 'does not log the user in, sets a flash message, and sends a suspicious sign in email', :sidekiq_inline do Auth::SessionsController::MAX_2FA_ATTEMPTS_PER_HOUR.times do post :create, params: { user: { otp_attempt: '1234' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } expect(controller.current_user).to be_nil @@ -278,17 +267,10 @@ RSpec.describe Auth::SessionsController do post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } - expect(controller.current_user).to be_nil - expect(flash[:alert]).to match I18n.t('users.rate_limited') - end - - it 'sends a suspicious sign-in mail', :sidekiq_inline do - Auth::SessionsController::MAX_2FA_ATTEMPTS_PER_HOUR.times do - post :create, params: { user: { otp_attempt: '1234' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } - expect(controller.current_user).to be_nil - end - - post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } + expect(controller.current_user) + .to be_nil + expect(flash[:alert]) + .to match I18n.t('users.rate_limited') expect(UserMailer.deliveries.size).to eq(1) expect(UserMailer.deliveries.first.to.first).to eq(user.email) @@ -301,11 +283,9 @@ RSpec.describe Auth::SessionsController do 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 - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user end end @@ -318,11 +298,9 @@ RSpec.describe Auth::SessionsController do 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 - it 'shows a login error' do + it 'shows a login error and does not log the user in' do expect(flash[:alert]).to match I18n.t('users.invalid_otp_token') - end - it "doesn't log the user in" do expect(controller.current_user).to be_nil end end @@ -332,11 +310,9 @@ RSpec.describe Auth::SessionsController do post :create, params: { user: { otp_attempt: recovery_codes.first } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } end - it 'redirects to home' do + it 'redirects to home and logs the user in' do expect(response).to redirect_to(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user end end @@ -346,11 +322,9 @@ RSpec.describe Auth::SessionsController do post :create, params: { user: { otp_attempt: 'wrongotp' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } end - it 'shows a login error' do + it 'shows a login error and does not log the user in' do expect(flash[:alert]).to match I18n.t('users.invalid_otp_token') - end - it "doesn't log the user in" do expect(controller.current_user).to be_nil end end @@ -417,15 +391,11 @@ RSpec.describe Auth::SessionsController do post :create, params: { user: { credential: fake_credential } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } end - it 'instructs the browser to redirect to home' do + it 'instructs the browser to redirect to home, logs the user in, and updates the sign count' do expect(body_as_json[:redirect_path]).to eq(root_path) - end - it 'logs the user in' do expect(controller.current_user).to eq user - end - it 'updates the sign count' do expect(webauthn_credential.reload.sign_count).to eq(sign_count) end end From 1946e171e6d150cecedf3949c3c4630d5bce1066 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 08:46:28 -0500 Subject: [PATCH 55/63] Reduce round trips in admin/disputes/appeals spec (#29234) --- .../admin/disputes/appeals_controller_spec.rb | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/spec/controllers/admin/disputes/appeals_controller_spec.rb b/spec/controllers/admin/disputes/appeals_controller_spec.rb index f830c3b95c..d365233167 100644 --- a/spec/controllers/admin/disputes/appeals_controller_spec.rb +++ b/spec/controllers/admin/disputes/appeals_controller_spec.rb @@ -30,21 +30,19 @@ RSpec.describe Admin::Disputes::AppealsController do end describe 'POST #approve' do + subject { post :approve, params: { id: appeal.id } } + let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - before do - post :approve, params: { id: appeal.id } - end + it 'redirects back to the strike page and notifies target account about approved appeal', :sidekiq_inline do + subject - it 'unsuspends a suspended account' do - expect(target_account.reload.suspended?).to be false - end + expect(response) + .to redirect_to(disputes_strike_path(appeal.strike)) - it 'redirects back to the strike page' do - expect(response).to redirect_to(disputes_strike_path(appeal.strike)) - end + expect(target_account.reload) + .to_not be_suspended - it 'notifies target account about approved appeal', :sidekiq_inline do expect(UserMailer.deliveries.size).to eq(1) expect(UserMailer.deliveries.first.to.first).to eq(target_account.user.email) expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.appeal_approved.subject', date: I18n.l(appeal.created_at))) @@ -52,17 +50,16 @@ RSpec.describe Admin::Disputes::AppealsController do end describe 'POST #reject' do + subject { post :reject, params: { id: appeal.id } } + let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - before do - post :reject, params: { id: appeal.id } - end + it 'redirects back to the strike page and notifies target account about rejected appeal', :sidekiq_inline do + subject - it 'redirects back to the strike page' do - expect(response).to redirect_to(disputes_strike_path(appeal.strike)) - end + expect(response) + .to redirect_to(disputes_strike_path(appeal.strike)) - it 'notifies target account about rejected appeal', :sidekiq_inline do expect(UserMailer.deliveries.size).to eq(1) expect(UserMailer.deliveries.first.to.first).to eq(target_account.user.email) expect(UserMailer.deliveries.first.subject).to eq(I18n.t('user_mailer.appeal_rejected.subject', date: I18n.l(appeal.created_at))) From 1d9d14b8de67daab169d10293e1f09901734c445 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 16 Feb 2024 09:29:24 -0500 Subject: [PATCH 56/63] Use `abort` instead of `warn(); exit` in boot.rb env check (#29209) --- .rubocop.yml | 6 ------ config/boot.rb | 11 +++++++++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index a8310489ea..dce33eab30 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -96,12 +96,6 @@ Rails/FilePath: Rails/HttpStatus: EnforcedStyle: numeric -# Reason: Allowed in boot ENV checker -# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsexit -Rails/Exit: - Exclude: - - 'config/boot.rb' - # Reason: Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions # https://docs.rubocop.org/rubocop-rails/cops_rails.html#railslexicallyscopedactionfilter Rails/LexicallyScopedActionFilter: diff --git a/config/boot.rb b/config/boot.rb index 717de85f20..70ffe22c04 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,8 +1,15 @@ # frozen_string_literal: true unless ENV.key?('RAILS_ENV') - warn 'ERROR: Missing RAILS_ENV environment variable, please set it to "production", "development", or "test".' - exit 1 + abort <<~ERROR + The RAILS_ENV environment variable is not set. + + Please set it correctly depending on context: + + - Use "production" for a live deployment of the application + - Use "development" for local feature work + - Use "test" when running the automated spec suite + ERROR end ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) From cfadb8707737ff679b1b08fa9dcab627a632f6ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Fourn=C3=A8s?= Date: Fri, 16 Feb 2024 15:54:23 +0100 Subject: [PATCH 57/63] Update enum syntax to use the new Rails 7.0 style (#29217) --- app/models/account.rb | 4 ++-- app/models/account_warning.rb | 4 ++-- app/models/bulk_import.rb | 4 ++-- app/models/custom_filter.rb | 2 +- app/models/domain_block.rb | 2 +- app/models/import.rb | 2 +- app/models/ip_block.rb | 2 +- app/models/list.rb | 2 +- app/models/login_activity.rb | 2 +- app/models/media_attachment.rb | 4 ++-- app/models/preview_card.rb | 4 ++-- app/models/relay.rb | 2 +- app/models/report.rb | 2 +- app/models/software_update.rb | 2 +- app/models/status.rb | 2 +- 15 files changed, 20 insertions(+), 20 deletions(-) diff --git a/app/models/account.rb b/app/models/account.rb index 05e1f943ca..442d4a431d 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -85,8 +85,8 @@ class Account < ApplicationRecord include DomainNormalizable include Paginable - enum protocol: { ostatus: 0, activitypub: 1 } - enum suspension_origin: { local: 0, remote: 1 }, _prefix: true + enum :protocol, { ostatus: 0, activitypub: 1 } + enum :suspension_origin, { local: 0, remote: 1 }, prefix: true validates :username, presence: true validates_with UniqueUsernameValidator, if: -> { will_save_change_to_username? } diff --git a/app/models/account_warning.rb b/app/models/account_warning.rb index 9286577f51..a54387a562 100644 --- a/app/models/account_warning.rb +++ b/app/models/account_warning.rb @@ -17,7 +17,7 @@ # class AccountWarning < ApplicationRecord - enum action: { + enum :action, { none: 0, disable: 1_000, mark_statuses_as_sensitive: 1_250, @@ -25,7 +25,7 @@ class AccountWarning < ApplicationRecord sensitive: 2_000, silence: 3_000, suspend: 4_000, - }, _suffix: :action + }, suffix: :action normalizes :text, with: ->(text) { text.to_s }, apply_to_nil: true diff --git a/app/models/bulk_import.rb b/app/models/bulk_import.rb index 406fb2aba2..4cd228705a 100644 --- a/app/models/bulk_import.rb +++ b/app/models/bulk_import.rb @@ -24,7 +24,7 @@ class BulkImport < ApplicationRecord belongs_to :account has_many :rows, class_name: 'BulkImportRow', inverse_of: :bulk_import, dependent: :delete_all - enum type: { + enum :type, { following: 0, blocking: 1, muting: 2, @@ -33,7 +33,7 @@ class BulkImport < ApplicationRecord lists: 5, } - enum state: { + enum :state, { unconfirmed: 0, scheduled: 1, in_progress: 2, diff --git a/app/models/custom_filter.rb b/app/models/custom_filter.rb index c8120c2395..5e2d152e34 100644 --- a/app/models/custom_filter.rb +++ b/app/models/custom_filter.rb @@ -31,7 +31,7 @@ class CustomFilter < ApplicationRecord include Expireable include Redisable - enum action: { warn: 0, hide: 1 }, _suffix: :action + enum :action, { warn: 0, hide: 1 }, suffix: :action belongs_to :account has_many :keywords, class_name: 'CustomFilterKeyword', inverse_of: :custom_filter, dependent: :destroy diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb index a05db099a8..e310918e9b 100644 --- a/app/models/domain_block.rb +++ b/app/models/domain_block.rb @@ -21,7 +21,7 @@ class DomainBlock < ApplicationRecord include DomainNormalizable include DomainMaterializable - enum severity: { silence: 0, suspend: 1, noop: 2 } + enum :severity, { silence: 0, suspend: 1, noop: 2 } validates :domain, presence: true, uniqueness: true, domain: true diff --git a/app/models/import.rb b/app/models/import.rb index 7cd6cccf7c..4bdb392014 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -28,7 +28,7 @@ class Import < ApplicationRecord belongs_to :account - enum type: { following: 0, blocking: 1, muting: 2, domain_blocking: 3, bookmarks: 4 } + enum :type, { following: 0, blocking: 1, muting: 2, domain_blocking: 3, bookmarks: 4 } validates :type, presence: true diff --git a/app/models/ip_block.rb b/app/models/ip_block.rb index 99783050b8..9def5b0cde 100644 --- a/app/models/ip_block.rb +++ b/app/models/ip_block.rb @@ -19,7 +19,7 @@ class IpBlock < ApplicationRecord include Expireable include Paginable - enum severity: { + enum :severity, { sign_up_requires_approval: 5000, sign_up_block: 5500, no_access: 9999, diff --git a/app/models/list.rb b/app/models/list.rb index fcef49e6e9..b45bd057bc 100644 --- a/app/models/list.rb +++ b/app/models/list.rb @@ -18,7 +18,7 @@ class List < ApplicationRecord PER_ACCOUNT_LIMIT = 50 - enum replies_policy: { list: 0, followed: 1, none: 2 }, _prefix: :show + enum :replies_policy, { list: 0, followed: 1, none: 2 }, prefix: :show belongs_to :account, optional: true diff --git a/app/models/login_activity.rb b/app/models/login_activity.rb index 2b7b37f8e4..654dd623ad 100644 --- a/app/models/login_activity.rb +++ b/app/models/login_activity.rb @@ -16,7 +16,7 @@ # class LoginActivity < ApplicationRecord - enum authentication_method: { password: 'password', otp: 'otp', webauthn: 'webauthn', sign_in_token: 'sign_in_token', omniauth: 'omniauth' } + enum :authentication_method, { password: 'password', otp: 'otp', webauthn: 'webauthn', sign_in_token: 'sign_in_token', omniauth: 'omniauth' } belongs_to :user diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 7ff6a15f5d..f53da04a97 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -34,8 +34,8 @@ class MediaAttachment < ApplicationRecord include Attachmentable - enum type: { image: 0, gifv: 1, video: 2, unknown: 3, audio: 4 } - enum processing: { queued: 0, in_progress: 1, complete: 2, failed: 3 }, _prefix: true + enum :type, { image: 0, gifv: 1, video: 2, unknown: 3, audio: 4 } + enum :processing, { queued: 0, in_progress: 1, complete: 2, failed: 3 }, prefix: true MAX_DESCRIPTION_LENGTH = 1_500 diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb index 8375927430..9fe02bd168 100644 --- a/app/models/preview_card.rb +++ b/app/models/preview_card.rb @@ -47,8 +47,8 @@ class PreviewCard < ApplicationRecord self.inheritance_column = false - enum type: { link: 0, photo: 1, video: 2, rich: 3 } - enum link_type: { unknown: 0, article: 1 } + enum :type, { link: 0, photo: 1, video: 2, rich: 3 } + enum :link_type, { unknown: 0, article: 1 } has_many :preview_cards_statuses, dependent: :delete_all, inverse_of: :preview_card has_many :statuses, through: :preview_cards_statuses diff --git a/app/models/relay.rb b/app/models/relay.rb index 8d697b891f..f652b4864b 100644 --- a/app/models/relay.rb +++ b/app/models/relay.rb @@ -15,7 +15,7 @@ class Relay < ApplicationRecord validates :inbox_url, presence: true, uniqueness: true, url: true, if: :will_save_change_to_inbox_url? - enum state: { idle: 0, pending: 1, accepted: 2, rejected: 3 } + enum :state, { idle: 0, pending: 1, accepted: 2, rejected: 3 } scope :enabled, -> { accepted } diff --git a/app/models/report.rb b/app/models/report.rb index 1b132753b5..df7e3d2efc 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -55,7 +55,7 @@ class Report < ApplicationRecord # - app/javascript/mastodon/features/notifications/components/report.jsx # - app/javascript/mastodon/features/report/category.jsx # - app/javascript/mastodon/components/admin/ReportReasonSelector.jsx - enum category: { + enum :category, { other: 0, spam: 1_000, legal: 1_500, diff --git a/app/models/software_update.rb b/app/models/software_update.rb index cb3a6df2ae..51a73c2731 100644 --- a/app/models/software_update.rb +++ b/app/models/software_update.rb @@ -16,7 +16,7 @@ class SoftwareUpdate < ApplicationRecord self.inheritance_column = nil - enum type: { patch: 0, minor: 1, major: 2 }, _suffix: :type + enum :type, { patch: 0, minor: 1, major: 2 }, suffix: :type def gem_version Gem::Version.new(version) diff --git a/app/models/status.rb b/app/models/status.rb index e3d41cceda..0ec69c8dd1 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -50,7 +50,7 @@ class Status < ApplicationRecord update_index('statuses', :proper) update_index('public_statuses', :proper) - enum visibility: { public: 0, unlisted: 1, private: 2, direct: 3, limited: 4 }, _suffix: :visibility + enum :visibility, { public: 0, unlisted: 1, private: 2, direct: 3, limited: 4 }, suffix: :visibility belongs_to :application, class_name: 'Doorkeeper::Application', optional: true From 96ddf1d4820419a6b5367af022be5cf17526109e Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 16 Feb 2024 17:57:23 +0100 Subject: [PATCH 58/63] Fix flaky end-to-end OCR test (#29244) --- spec/system/ocr_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/system/ocr_spec.rb b/spec/system/ocr_spec.rb index 3ab815c047..254efa7137 100644 --- a/spec/system/ocr_spec.rb +++ b/spec/system/ocr_spec.rb @@ -28,6 +28,6 @@ describe 'OCR', :paperclip_processing, :sidekiq_inline do click_on('Detect text from picture') - expect(page).to have_css('#upload-modal__description', text: 'Hello Mastodon') + expect(page).to have_css('#upload-modal__description', text: /Hello Mastodon\s*/, wait: 10) end end From 245064bb98ab11face7a04303fd62724820d9610 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 19 Feb 2024 06:09:43 -0500 Subject: [PATCH 59/63] Move "everyone" role and "instance actor" account magic number IDs to constants (#29260) --- app/models/account.rb | 5 +++-- app/models/concerns/account/finder_concern.rb | 4 ++-- app/models/user_role.rb | 10 ++++++---- db/migrate/20190715164535_add_instance_actor.rb | 6 ++++-- .../20220704024901_migrate_settings_to_user_roles.rb | 6 ++++-- db/seeds/02_instance_actor.rb | 2 +- lib/tasks/tests.rake | 2 +- spec/models/account_spec.rb | 4 ++-- spec/models/user_role_spec.rb | 6 +++--- 9 files changed, 26 insertions(+), 19 deletions(-) diff --git a/app/models/account.rb b/app/models/account.rb index 442d4a431d..d627fd6b64 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -64,6 +64,7 @@ class Account < ApplicationRecord ) BACKGROUND_REFRESH_INTERVAL = 1.week.freeze + INSTANCE_ACTOR_ID = -99 USERNAME_RE = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i MENTION_RE = %r{(? { where.not(sensitized_at: nil) } scope :without_suspended, -> { where(suspended_at: nil) } scope :without_silenced, -> { where(silenced_at: nil) } - scope :without_instance_actor, -> { where.not(id: -99) } + scope :without_instance_actor, -> { where.not(id: INSTANCE_ACTOR_ID) } scope :recent, -> { reorder(id: :desc) } scope :bots, -> { where(actor_type: %w(Application Service)) } scope :groups, -> { where(actor_type: 'Group') } @@ -176,7 +177,7 @@ class Account < ApplicationRecord end def instance_actor? - id == -99 + id == INSTANCE_ACTOR_ID end alias bot bot? diff --git a/app/models/concerns/account/finder_concern.rb b/app/models/concerns/account/finder_concern.rb index 7faaddeb43..a7acff1cbb 100644 --- a/app/models/concerns/account/finder_concern.rb +++ b/app/models/concerns/account/finder_concern.rb @@ -13,11 +13,11 @@ module Account::FinderConcern end def representative - actor = Account.find(-99).tap(&:ensure_keys!) + actor = Account.find(Account::INSTANCE_ACTOR_ID).tap(&:ensure_keys!) actor.update!(username: 'mastodon.internal') if actor.username.include?(':') actor rescue ActiveRecord::RecordNotFound - Account.create!(id: -99, actor_type: 'Application', locked: true, username: 'mastodon.internal') + Account.create!(id: Account::INSTANCE_ACTOR_ID, actor_type: 'Application', locked: true, username: 'mastodon.internal') end def find_local(username) diff --git a/app/models/user_role.rb b/app/models/user_role.rb index 89354da542..ed64ca0538 100644 --- a/app/models/user_role.rb +++ b/app/models/user_role.rb @@ -38,6 +38,8 @@ class UserRole < ApplicationRecord delete_user_data: (1 << 19), }.freeze + EVERYONE_ROLE_ID = -99 + module Flags NONE = 0 ALL = FLAGS.values.reduce(&:|) @@ -94,7 +96,7 @@ class UserRole < ApplicationRecord before_validation :set_position - scope :assignable, -> { where.not(id: -99).order(position: :asc) } + scope :assignable, -> { where.not(id: EVERYONE_ROLE_ID).order(position: :asc) } has_many :users, inverse_of: :role, foreign_key: 'role_id', dependent: :nullify @@ -103,9 +105,9 @@ class UserRole < ApplicationRecord end def self.everyone - UserRole.find(-99) + UserRole.find(EVERYONE_ROLE_ID) rescue ActiveRecord::RecordNotFound - UserRole.create!(id: -99, permissions: Flags::DEFAULT) + UserRole.create!(id: EVERYONE_ROLE_ID, permissions: Flags::DEFAULT) end def self.that_can(*any_of_privileges) @@ -113,7 +115,7 @@ class UserRole < ApplicationRecord end def everyone? - id == -99 + id == EVERYONE_ROLE_ID end def nobody? diff --git a/db/migrate/20190715164535_add_instance_actor.rb b/db/migrate/20190715164535_add_instance_actor.rb index 3785dc2553..6871b37bdf 100644 --- a/db/migrate/20190715164535_add_instance_actor.rb +++ b/db/migrate/20190715164535_add_instance_actor.rb @@ -5,6 +5,8 @@ class AddInstanceActor < ActiveRecord::Migration[5.2] # Dummy class, to make migration possible across version changes validates :username, uniqueness: { scope: :domain, case_sensitive: false } + INSTANCE_ACTOR_ID = -99 + before_create :generate_keys def generate_keys @@ -15,10 +17,10 @@ class AddInstanceActor < ActiveRecord::Migration[5.2] end def up - Account.create!(id: -99, actor_type: 'Application', locked: true, username: Rails.configuration.x.local_domain) + Account.create!(id: Account::INSTANCE_ACTOR_ID, actor_type: 'Application', locked: true, username: Rails.configuration.x.local_domain) end def down - Account.find_by(id: -99, actor_type: 'Application').destroy! + Account.find_by(id: Account::INSTANCE_ACTOR_ID, actor_type: 'Application').destroy! end end diff --git a/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb b/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb index 00afee26d0..42dc37f08b 100644 --- a/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb +++ b/db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb @@ -3,7 +3,9 @@ class MigrateSettingsToUserRoles < ActiveRecord::Migration[6.1] disable_ddl_transaction! - class UserRole < ApplicationRecord; end + class UserRole < ApplicationRecord + EVERYONE_ROLE_ID = -99 + end def up process_role_everyone @@ -17,7 +19,7 @@ class MigrateSettingsToUserRoles < ActiveRecord::Migration[6.1] private def process_role_everyone - everyone_role = UserRole.find_by(id: -99) + everyone_role = UserRole.find_by(id: UserRole::EVERYONE_ROLE_ID) return unless everyone_role everyone_role.permissions &= ~::UserRole::FLAGS[:invite_users] unless min_invite_role == 'user' diff --git a/db/seeds/02_instance_actor.rb b/db/seeds/02_instance_actor.rb index 55e83e8a08..2b6befec0d 100644 --- a/db/seeds/02_instance_actor.rb +++ b/db/seeds/02_instance_actor.rb @@ -1,3 +1,3 @@ # frozen_string_literal: true -Account.create_with(actor_type: 'Application', locked: true, username: 'mastodon.internal').find_or_create_by(id: -99) +Account.create_with(actor_type: 'Application', locked: true, username: 'mastodon.internal').find_or_create_by(id: Account::INSTANCE_ACTOR_ID) diff --git a/lib/tasks/tests.rake b/lib/tasks/tests.rake index 885be79f41..935f6d24a3 100644 --- a/lib/tasks/tests.rake +++ b/lib/tasks/tests.rake @@ -50,7 +50,7 @@ namespace :tests do exit(1) end - if Account.find(-99).private_key.blank? + if Account.find(Account::INSTANCE_ACTOR_ID).private_key.blank? puts 'Instance actor does not have a private key' exit(1) end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index b1dca52dc5..f6376eb36e 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -746,13 +746,13 @@ RSpec.describe Account do end it 'is valid if we are creating an instance actor account with a period' do - account = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com') + account = Fabricate.build(:account, id: described_class::INSTANCE_ACTOR_ID, actor_type: 'Application', locked: true, username: 'example.com') expect(account.valid?).to be true end it 'is valid if we are creating a possibly-conflicting instance actor account' do _account = Fabricate(:account, username: 'examplecom') - instance_account = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com') + instance_account = Fabricate.build(:account, id: described_class::INSTANCE_ACTOR_ID, actor_type: 'Application', locked: true, username: 'example.com') expect(instance_account.valid?).to be true end diff --git a/spec/models/user_role_spec.rb b/spec/models/user_role_spec.rb index d5234ebe8d..9dd04a8172 100644 --- a/spec/models/user_role_spec.rb +++ b/spec/models/user_role_spec.rb @@ -164,12 +164,12 @@ RSpec.describe UserRole do end describe '#everyone?' do - it 'returns true when id is -99' do - subject.id = -99 + it 'returns true when id matches the everyone id' do + subject.id = described_class::EVERYONE_ROLE_ID expect(subject.everyone?).to be true end - it 'returns false when id is not -99' do + it 'returns false when id does not match the everyone id' do subject.id = 123 expect(subject.everyone?).to be false end From 63f4ea055aceff47ae47eabe6da103af05ffafd5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 19 Feb 2024 12:09:58 +0100 Subject: [PATCH 60/63] Change follow suggestions design in web UI (#29272) --- .../components/inline_follow_suggestions.jsx | 25 ++++++++++++++++--- app/javascript/mastodon/locales/en.json | 7 +++++- .../styles/mastodon/components.scss | 9 +++++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx b/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx index f76526e045..c39b43bade 100644 --- a/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx +++ b/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx @@ -21,6 +21,7 @@ import { DisplayName } from 'mastodon/components/display_name'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from 'mastodon/components/icon_button'; import { VerifiedBadge } from 'mastodon/components/verified_badge'; +import { domain } from 'mastodon/initial_state'; const messages = defineMessages({ follow: { id: 'account.follow', defaultMessage: 'Follow' }, @@ -28,27 +29,43 @@ const messages = defineMessages({ previous: { id: 'lightbox.previous', defaultMessage: 'Previous' }, next: { id: 'lightbox.next', defaultMessage: 'Next' }, dismiss: { id: 'follow_suggestions.dismiss', defaultMessage: "Don't show again" }, + friendsOfFriendsHint: { id: 'follow_suggestions.hints.friends_of_friends', defaultMessage: 'This profile is popular among the people you follow.' }, + similarToRecentlyFollowedHint: { id: 'follow_suggestions.hints.similar_to_recently_followed', defaultMessage: 'This profile is similar to the profiles you have most recently followed.' }, + featuredHint: { id: 'follow_suggestions.hints.featured', defaultMessage: 'This profile has been hand-picked by the {domain} team.' }, + mostFollowedHint: { id: 'follow_suggestions.hints.most_followed', defaultMessage: 'This profile is one of the most followed on {domain}.'}, + mostInteractionsHint: { id: 'follow_suggestions.hints.most_interactions', defaultMessage: 'This profile has been recently getting a lot of attention on {domain}.' }, }); const Source = ({ id }) => { - let label; + const intl = useIntl(); + + let label, hint; switch (id) { case 'friends_of_friends': + hint = intl.formatMessage(messages.friendsOfFriendsHint); + label = ; + break; case 'similar_to_recently_followed': + hint = intl.formatMessage(messages.similarToRecentlyFollowedHint); label = ; break; case 'featured': - label = ; + hint = intl.formatMessage(messages.featuredHint, { domain }); + label = ; break; case 'most_followed': + hint = intl.formatMessage(messages.mostFollowedHint, { domain }); + label = ; + break; case 'most_interactions': + hint = intl.formatMessage(messages.mostInteractionsHint, { domain }); label = ; break; } return ( -
+
{label}
@@ -92,7 +109,7 @@ const Card = ({ id, sources }) => { {firstVerifiedField ? : }
-